0

I've a Maven webapp project. It has a default directory structure as below -

 |-- pom.xml
 `-- src
     `-- main
         |-- java
         |   `-- com
         |       `-- example
         |           `-- projects
         |               `-- SampleAction.java
         |-- resources
         |   `-- images
         |       `-- sampleimage.jpg
         `-- webapp
             |-- WEB-INF
             |   `-- web.xml
             |-- index.jsp
             `-- jsp
                 `-- websource.jsp

The WAR file it generates has the structure as below which is again based on defaults -

  |-- META-INF
  |   |-- MANIFEST.MF
  |   `-- maven
  |       `-- com.example.projects
  |           `-- documentedproject
  |               |-- pom.properties
  |               `-- pom.xml
  |-- WEB-INF
  |   |-- classes
  |   |   |-- com
  |   |   |   `-- example
  |   |   |       `-- projects
  |   |   |           `-- SampleAction.class
  |   |   `-- images
  |   |       `-- sampleimage.jpg
  |   `-- web.xml
  |-- index.jsp
  `-- jsp
      `-- websource.jsp

I want to rename web-prod.xml to web.xml, which reside under webapp directory, before packaging into WAR. Now the catch is - contents of this directory are copied into target/<finalName> by the maven-war-plugin only during the packaging phase and immediately the WAR is generated.
Since webapp contents are copied by default by maven-war-plugin, other plugins like maven-compiler-plugin and maven-resources-plugin which come into picture early, don't have any role in modifying the said file.

pom.xml

<build>
    ...
    <plugins>
        ...
        <plugin>
            <artifactId>maven-antrun-plugin</artifactId>
            <executions>
                <execution>
                    <id>replace-descriptor</id>
                    <phase>compile</phase>
                    <goals>
                        <goal>run</goal>
                    </goals>
                    <configuration>
                        <target>
                            <delete file="${project.build.directory}/${project.finalName}/WEB-INF/web.xml" />
                            <move file="${project.build.directory}/${project.finalName}/WEB-INF/web-prod.xml" tofile="${project.build.directory}/${project.finalName}/WEB-INF/web.xml"/>
                        </target>
                    </configuration>
                </execution>
            </executions>
        </plugin>
        <plugin>
            <artifactId>maven-war-plugin</artifactId>
            <configuration>
                <archiveClasses>true</archiveClasses>
                <attachClasses>true</attachClasses>
                <warSourceIncludes>WEB-INF/**</warSourceIncludes>
                <packagingExcludes>WEB-INF/classes</packagingExcludes>
                <webResources>
                    <resource>
                        <directory>src/main/resources</directory>
                        <targetPath>WEB-INF/classes</targetPath>
                        <includes>
                            ...
                        </includes>
                    </resource>
                    <resource>
                        <directory>${project.build.directory}/classes</directory>
                        <includes>
                            ...
                        </includes>
                        <targetPath>WEB-INF/classes</targetPath>
                    </resource>
                </webResources>
            </configuration>
        </plugin>
    </plugins>
</build>

web.xml

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" metadata-complete="true" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
    <display-name>NSWeb</display-name>
    ...
    <filter>
        <filter-name>corsFilter</filter-name>
        <filter-class>com.example.core.security.filter.CORSFilter</filter-class>
    </filter>
    ...
</web-app>

web-prod.xml

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" metadata-complete="true" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
    <display-name>NSWeb</display-name>
    ...
    <filter>
        <filter-name>corsFilter</filter-name>
        <filter-class>com.example.core.security.filter.CORSFilter</filter-class>
        <init-param>
            <description>A comma separated list of allowed origins. Note: An '*' cannot be used for an allowed origin when using credentials.</description>
            <param-name>cors.enabled</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            ...
        </init-param>
        <init-param>
            ...
        </init-param>
        <init-param>
            ...
        </init-param>
        ...
    </filter>
    ...
</web-app>
Sid
  • 145
  • 1
  • 11
  • Why do you like to rename `web-prod.xml` to `web.xml` ? – khmarbaise Jul 14 '21 at 09:34
  • `web-prod.xml` is for production deployment. Hence, I want that to be available as actual `web.xml` before war packaging. – Sid Jul 14 '21 at 10:00
  • Where is exactly the difference between them? Apart from having environmental dependencies should be in your artifact (war file).. should be applied from outside....Tomcat? – khmarbaise Jul 14 '21 at 10:16
  • It has some CORS policy configurations which vary from env to env. Moreover, we're using `maven-cargo-plugin` along with `Cargo Daemon` which automatically downloads and starts the Tomcat server and also deploys the artifact into it. So we cannot manually configure Tomcat to have the `web.xml` externally. – Sid Jul 14 '21 at 10:42
  • I repeat my question: What is the difference between your prod and usual web.xml ...? What kind of information is difference? Using cargo plugin in production or in dev? – khmarbaise Jul 14 '21 at 11:09
  • As I mentioned - it has some CORS policy configuration. Using cargo plugin for UAT. Just ignore the terminology please. Just think that there are two different sets of configurations in both the web.xml files which are specific to two different environments and the right file should be packaged into war. – Sid Jul 14 '21 at 11:47
  • @Sid is there some reason you're not using maven-cargo-plugin war [web.xml merge feature](https://codehaus-cargo.github.io/cargo/Merging+WAR+files.html#MergingWARfiles-Mergingtheweb.xmlfile) for this? or maven-war-plugin [overlay feature](https://maven.apache.org/plugins/maven-war-plugin/overlays.html)? – eis Jul 15 '21 at 05:51
  • or maven-war-plugin [filtering feature](https://stackoverflow.com/questions/1782352/filtering-maven-files-into-web-inf) – eis Jul 15 '21 at 05:52
  • also, I don't see `web-prod.xml` in your example source code. It could help if you would provide values in the question to actually reproduce the issue (e.g. do you have both web.xml and web-prod.xml there or what) – eis Jul 15 '21 at 05:56
  • `maven-cargo-plugin` web.xml merge feature and `maven-war-plugin` overlay feature are something focused on merger of two WAR files. I don't think they fit into my case. I didn't go for filtering feature since there are 40 odd lines that I'll have to replace through a placeholder. I can anyway try it now. – Sid Jul 15 '21 at 10:24

1 Answers1

0

Thanks eis for pointing me to the filtering feature!
Earlier I maintained two different web.xml files and was trying to replace one with the other since there was a difference of around 40 lines of block between those two files. I could achieve the end result by modifying the same and NOT by replacing it with the other. Here's the solution explained stepwise:

  1. Have a single web.xml file with a placeholder to be replaced with the block.
  2. Enable resource filtering for maven-war-plugin and use the profiles.
  3. Have two different properties files to store the target specific values for the placeholder.

web.xml

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" metadata-complete="true" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
    <display-name>NSWeb</display-name>
    ...
    <filter>
        <filter-name>corsFilter</filter-name>
        <filter-class>com.example.core.security.filter.CORSFilter</filter-class>
        @web.xml.cors.config@
    </filter>
    ...
</web-app>

pom.xml

<build>
    ...
    <filters>
        <filter>src/main/resources/place-holders-${targetenv}.properties</filter>
    </filters>
    <plugins>
        
        <plugin>
            <artifactId>maven-war-plugin</artifactId>
            <configuration>
                ...
                <webResources>
                    ...
                    <resource>
                        <directory>${basedir}/src/main/webapp/WEB-INF</directory>
                        <filtering>true</filtering>
                        <targetPath>WEB-INF</targetPath>
                        <includes>
                            <include>**/web.xml</include>
                        </includes>
                    </resource>
                </webResources>
            </configuration>
        </plugin>
    </plugins>
</build>
<profiles>
    <profile>
        <id>dev</id>
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
        <properties>
            <targetenv>dev</targetenv>
        </properties>
    </profile>
    <profile>
        <id>prod</id>
        <properties>
            <targetenv>prod</targetenv>
        </properties>
    </profile>
</profiles>

place-holders-dev.properties [just a blank/empty space for dev]

web.xml.cors.config= 

place-holders-prod.properties

web.xml.cors.config=<init-param>\
\n\t\t\t<description>A comma separated list of allowed origins. Note An '*' cannot be used for an allowed origin when using credentials.</description>\
\n\t\t\t<param-name>cors.enabled</param-name>\
\n\t\t\t<param-value>true</param-value>\
\n\t\t</init-param>\
\n\t\t<init-param>\
        ...
\n\t\t</init-param>\
\n\t\t<init-param>\
        ...
\n\t\t</init-param>\
        ...
        ...
Sid
  • 145
  • 1
  • 11