Maven: Customize web.xml of web-app project
Asked Answered
W

7

58

I have a web application Maven project, and I want to customize the web.xml file depending on the Profile that is running. I am using the Maven-War-plugin, which allows me to define a "resources" directory, where the files may be filtered. However, filtering alone is not sufficient for me.

In more detail, I want to include (or exclude) the whole section on security, depending on the profile I an running. This is the part:

....
....

<security-constraint>

    <web-resource-collection>
        <web-resource-name>protected</web-resource-name>
        <url-pattern>/pages/*.xhtml</url-pattern>
        <url-pattern>/pages/*.jsp</url-pattern>
    </web-resource-collection>

    <auth-constraint>
        <role-name>*</role-name>
    </auth-constraint>

    </security-constraint>
        <login-config>
        <auth-method>${web.modules.auth.type}</auth-method>
        <realm-name>MyRealm</realm-name>
    </login-config>

<security-constraint>

....
....

If this is not done easily, is there a way to have two web.xml files and select the appropriate one depending on the profile?

Writein answered 21/7, 2010 at 11:36 Comment(0)
L
81

is there a way to have two web.xml files and select the appropriate one depending on the profile?

Yes, within each profile you can add a configuration of the maven-war-plugin and configure each to point at a different web.xml.

<profiles>
    <profile>
        <id>profile1</id>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-war-plugin</artifactId>
                    <configuration>
                        <webXml>/path/to/webXml1</webXml>
                    </configuration>
                </plugin>
                 ...

As an alternative to having to specify the maven-war-plugin configuration in each profile, you can supply a default configuration in the main section of the POM and then just override it for specific profiles.

Or to be even simpler, in the main <build><plugins> of your POM, use a property to refer to the webXml attribute and then just change it's value in different profiles

<properties>
    <webXmlPath>path/to/default/webXml</webXmlPath>
</properties>
<profiles>
    <profile>
        <id>profile1</id>
        <properties>
            <webXmlPath>path/to/custom/webXml</webXmlPath>
        </properties>
    </profile>
</profiles>
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-war-plugin</artifactId>
            <configuration>
                <webXml>${webXmlPath}</webXml>
            </configuration>
        </plugin>
        ...
Loud answered 21/7, 2010 at 11:52 Comment(0)
D
50

There's a third, compromise option which I implemented in my project. It keeps everything in one web.xml while still making both it and the pom.xml readable. In my case, I had a need to sometimes have security and sometimes have no security, depending on the environment.

So what I did was:

In the pom.xml, define two profiles (or however many you need). Within the profiles, include two properties. When you want security, you leave them empty, like this:

<enable.security.start></enable.security.start>
<enable.security.end></enable.security.end>

When you want to exclude all of the security, you define them as follows:

<enable.security.start>&lt;!--</enable.security.start>
<enable.security.end>--&gt;</enable.security.end>

Then, you have a single web.xml file with the following:

${enable.security.start}
<security-constraint>
  ...
  // all of the XML that you need, in a completely readable format
  ...
</login-config>  
${enable.security.end}

The pom.xml maven-war-plugin has to be configured to use filtering. Mine looks like this:

   <configuration>
      <webResources>
        <resource>
          <filtering>true</filtering>
          <directory>src/main/webapp</directory>
          <includes>
            <include>**/web.xml</include>
          </includes>
        </resource>
      </webResources>
      <warSourceDirectory>src/main/webapp</warSourceDirectory>
      <webXml>src/main/webapp/WEB-INF/web.xml</webXml>
      ...

So, basically, when you select the profile to include security, you get two extra CRLF's in your web.xml. When you select the profile to NOT include security, the XML is all still in the web.xml, but it's commented out so it gets ignored. I like this because you don't have to worry about keeping multiple files in sync, yet the XML is still readable (and it's in the web.xml file where people would naturally look for it).

Directly answered 21/12, 2011 at 16:26 Comment(6)
I used a similar technique. Instead of using comment start and end nodes, I created a commented macro like <security-constraint><!--${dev.security.constraint}-->...</security-constraint>. Because it was commented out, it is still a valid XML document. In my dev profile I had <profile><id>dev</id><properties><dev.security.constraint>--&gt;[Content goes here]&lt;</dev.security.constraint><properties></profile>. This means that if I don't define dev.security.constraint, it is becomes a harmless comment, but when it is defined, it is the content sandwiched between two empty comments.Devorahdevore
I'd do more than +1 for this solution if I could. Very nice!Vermiculate
I like the idea of this, except for the invalid XML errors which are resolved by @ajozwik answer below. +1 for heading in the right direction though!Tepper
So hacky but i love itSalesmanship
I'm using this approach, but sometimes, not everytime, in the web.xml it remains the escaped string, ie --&gt;, instead of -->. Same if I use cdata. maven-war-plugin 3.2.0Proverb
@Proverb Use '<![CDATA[..]]> instead.Inmate
F
23

Comment to Chris Clark answer. You can reverse - so in development you do not want to have any constraints (security or jndi, other)

<!-- ${enable.security.end}
<security-constraint>
    ...
</security-constraint>


${enable.security.start} -->

So in development you have commented out section. But in production it will be translated to (with maven profile):

<!-- -->
<security-constraint>
    ...
</security-constraint>


<!-- -->

and commented section will be visible.

Ferrosilicon answered 21/2, 2013 at 15:36 Comment(0)
H
19

"matt b" has already posted the answer that is the most maven way of doing it. It is the way I'd recommend doing it 99% of the time.

However, occasionally, your configuration file might be quite complicated, and it doesn't make much sense to duplicate the whole file for each environment when only one XML stanza differs. In these cases, you can abuse property filtering to accomplish your goal.

Warning, a very duct-tape-y solution follows, and will not be for the faint of heart:

In your pom.xml:

Attention StackOverflow Editors!!!!

The html entity escaping is a part of the solution. The solution will NOT work if you replace it all with greater-than and less-than signs. Please leave the answer as is...

<properties>
    <test.security.config>
        &lt;security-constraint&gt;
            &lt;web-resource-collection&gt;
                &lt;web-resource-name&gt;protected&lt;/web-resource-name&gt;
                &lt;url-pattern&gt;/pages/*.xhtml&lt;/url-pattern&gt;
                &lt;url-pattern&gt;/pages/*.jsp&lt;/url-pattern&gt;
            &lt;/web-resource-collection&gt;

            &lt;auth-constraint&gt;
                &lt;role-name&gt;*&lt;/role-name&gt;
            &lt;/auth-constraint&gt;

            &lt;/security-constraint&gt;
                &lt;login-config&gt;
                &lt;auth-method&gt;${web.modules.auth.type}&lt;/auth-method&gt;
                &lt;realm-name&gt;MyRealm&lt;/realm-name&gt;
            &lt;/login-config&gt;

        &lt;security-constraint&gt;
    </test.security.config>
</properties>

in your web.xml

....
${test.security.config}
....

Because non-existent properties evaluate to an empty string, your configurations which do not have this property set (or the property is an empty xml tag) will evaluate to a blank line here.

It's ugly, and the xml is hard to modify in this form. However, if your web.xml is complex and you pose a greater risk of 4-5 copies of the web.xml getting out of sync, this may be an approach that will work for you.

Hotheaded answered 25/7, 2010 at 0:51 Comment(4)
I actually prefer this way. It's not ugly, and with different web.xml files, I could see a situation where someone made a change to the development web.xml, and it worked, then built with production's web.xml, deployed, and the site went down.Pileate
I had to wrap the property in <![CDATA[ ... ]]> in order for this to work.Pileate
since people keep helpfully editing the original (hint, the &gt; is a part of the solution!!!!), note that the above will not work out of the box. I've already fixed it, but people keep changing it back...Hotheaded
Is this solution possible when building an EAR? Say I have a maven project with two EAR sub projects, and each include the same WAR, but require different web.xml. web-fragment.xml doesn't work with EAR/lib packaging. See #48390670Surplus
E
12

A new configuration was added to maven-war-plugin in version 2.1-alpha-2. Its name is filteringDeploymentDescriptors and it does exacly what you want.

This works:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-war-plugin</artifactId>
    <version>2.4</version>
    <configuration>
        <filteringDeploymentDescriptors>true</filteringDeploymentDescriptors>
    </configuration>
</plugin>

And this also works:

<properties>
    <maven.war.filteringDeploymentDescriptors>true</maven.war.filteringDeploymentDescriptors>
</properties>

More information is available in the official documentation of filteringDeploymentDescriptors.

Ewell answered 9/10, 2014 at 14:38 Comment(0)
P
4

An improvement to https://mcmap.net/q/328870/-maven-customize-web-xml-of-web-app-project

Instead of specifying a custom property, use the default property maven.war.webxml in your different profiles.

<profiles>
    <profile>
        <id>profile1</id>
        <properties>
            <maven.war.webxml>path/to/custom/webXml</maven.war.webxml>
        </properties>
    </profile>
</profiles>

Further info can be found at the following link: https://maven.apache.org/plugins-archives/maven-war-plugin-2.4/war-mojo.html#webXml

Panier answered 24/11, 2014 at 13:30 Comment(1)
Is it maven.war.webxml or webXmlPath? Your start tag is different from the closing tag.Butts
C
0
is there a way to have two web.xml files and select the appropriate one depending on the profile?

Other than the approach suggested by matt b, it is useful to think it the other way around, mainly because in many cases you will have to bundle application server specific configurations that are not covered by the maven plugins (afaik). These may very well have differences between profiles.

Specifically, you can use a parent project that has all the common files between web projects of different profiles. Then child projects can have different web.xml files and the rest id done with profiles and the maven-war-plugin. For example, I have used this layout to achieve unattended builds (other than specifying a profile) for different target environments (development, uat etc.)

WebPc
├── common
│   ├── css
│   ├── images
│   ├── js
│   └── WEB-INF
│   └──├── wsdl
│── pom.xml
│
├── WebPc-DEV
│   ├── pom.xml
│   └── src
│       └── main
│           └── webapp
│               └── WEB-INF
│                   ├── geronimo-web.xml
│                   ├── ibm-web-bnd.xml
│                   ├── ibm-web-ext.xml
│                   └── web.xml
├── WebPc-UAT
│   ├── pom.xml
│   └── src
│       └── main
│           └── webapp
│               └── WEB-INF
│                   ├── geronimo-web.xml
│                   ├── ibm-web-bnd.xml
│                   ├── ibm-web-ext.xml
│                   └── web.xml

The pom of WebPc has the following pom

<groupId>my.grp</groupId>
<artifactId>WebPc</artifactId>
<packaging>pom</packaging>

<profiles>
    <profile>
        <id>DEV</id>
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
        <modules>
            <module>WebPc-DEV</module>
        </modules>
    </profile>
    <profile>
        <id>UAT</id>
        <modules>
            <module>WebPc-UAT</module>
        </modules>
    </profile>
</profiles>

<build>
    <pluginManagement>
        <plugins>

            <!-- copy common resources located on parent
                 project common folder for packaging -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.4</version>
                <configuration>
                    <resourceEncoding>${project.build.sourceEncoding}</resourceEncoding>
                    <webResources>
                        <resource>
                            <directory>../common</directory>
                            <excludes>
                                <exclude>WEB-INF/**</exclude>
                            </excludes>
                        </resource>
                        <resource>
                            <directory>../common/WEB-INF</directory>
                            <includes>
                                <include>wsdl/*.wsdl</include>
                                <include>wsdl/*.xsd</include>
                            </includes>
                            <targetPath>WEB-INF</targetPath>
                        </resource>
                    </webResources>
                </configuration>
            </plugin>

        </plugins>
    </pluginManagement>
</build>

And this is the pom for WebPc-DEV

<parent>
    <groupId>my.grp</groupId>
    <artifactId>WebPc</artifactId>
    <version>1.0.0-SNAPSHOT</version>
</parent>

<artifactId>WebPc-DEV</artifactId>
<packaging>war</packaging>
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-war-plugin</artifactId>
        </plugin>
    </plugins>
</build>
Creamery answered 25/9, 2013 at 14:31 Comment(1)
the downside of this solution is that if there's only one difference among the various web.xml files you have to be sure to coordinate any other changes across all of the web.xml files. This violates a central tenant of coding. If you only need to alter one or two parameters in the web.xml the more appropriate way is to use variablesStrang

© 2022 - 2024 — McMap. All rights reserved.