Search code examples
websphere-libertyliberty-maven-plugin

Use maven filtering in server.xml without breaking mvn liberty:dev


I would like to use maven filtering, in my src/main/liberty/config/server.xml without breaking the use of liberty:dev from the maven-liberty-plugin. My biggest problem seems to be that the liberty-maven-plugin does not honor filtering.

For example, consider this webApplication element:

<webApplication id="${project.artifactId}" contextRoot="/"
    location="${server.config.dir}/apps/${project.artifactId}.war">
</webApplication>

Without any other guidance, this file is copied to target/liberty/wlp/usr/servers/defaultServer/server.xml without any filtering, so the runtime cannot find the WAR file.

Let's say I manually turn on the filtering using maven-resources-plugin:

<plugin>
  <artifactId>maven-resources-plugin</artifactId>
  <version>3.2.0</version>
  <executions>
    <execution>
      <id>01-liberty-config</id>
      <phase>package</phase>
      <goals>
        <goal>copy-resources</goal>
      </goals>
      <configuration>
        <outputDirectory>${project.build.directory}/liberty/wlp/usr/servers/defaultServer</outputDirectory>
        <resources>          
          <resource>
            <directory>src/main/liberty/config</directory>
            <filtering>true</filtering>
          </resource>
        </resources>              
      </configuration>            
    </execution>
  </executions>
</plugin>

Now the filtering works and the file is in the correct location. Unfortunately, I observe that when I run mvn liberty:dev, this gets overwritten by the unfiltered server.xml from src/main/liberty/config/server.xml.

Is it possible to use maven filtering in a server.xml?


Solution

  • BACKGROUND

    This is essentially not supported today. The liberty-maven-plugin doesn't let you do this, and the way in which the liberty-maven-plugin manages and controls the Liberty config also doesn't make it easy for you to use standard Maven plugins like 'dependency' or 'resources' plugin either.

    Since this issue was raised before I shared a sample approach which you might find useful, though it has the feel of a workaround.

    SOLUTION OVERVIEW

    Basically, although although we can't substitute into server.xml itself via filters we can substitute into a config snippet that gets included by server.xml, and copy this into place using the resources plugin, rather than liberty-maven-plugin.

    SOLUTION DETAIL

    Say I wanted to use a "filter"-style Maven variable substitution ${tidal.url} for a URL in Liberty server config.

    1. src/main/filtered-config/environment.xml

    First define a config snippet, which we are going to apply the filter to.

    <server description="environment">
        <!-- Expect to come from filter -->
        <variable name="tidal.url" value="${tidal.url}"/>
    </server>
    

    2. pom.xml

    Configure an execution of resources:copy-resources copying the "environment.xml" snippet above to the shared config dir location, target/liberty/wlp/usr/shared/config, with filtering enabled:

                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-resources-plugin</artifactId>
                    <version>3.2.0</version>
                    <executions>
                        <execution>
                            <id>default-cli</id>
                            <phase>none</phase>
                            <goals>
                                <goal>copy-resources</goal>
                            </goals>
                            <configuration>
                                <overwrite>true</overwrite>
                                <!-- This location can persist across a server recreate, where the refresh can annoyingly wipe out your earlier copy -->
                                <outputDirectory>target/liberty/wlp/usr/shared/config</outputDirectory>
                                <resources>
                                    <resource>
                                        <directory>src/main/filtered-config</directory>
                                        <filtering>true</filtering>
                                    </resource>
                                </resources>
                            </configuration>
                        </execution>
                    </executions>
                </plugin>
    

    3. server.xml

    In your main server.xml config file, add an <include> of the config snippet you copied into the shared config dir via "copy-resources".

    Also shown is how we finally use or "consume" the value applied via the filter, here in this <jndiEntry>, in this sample:

     <include location="${shared.config.dir}/environment.xml"/>
    
     <!-- This is how I'm ultimately going to "consume" the filtered value -->
     <jndiEntry jndiName="url/tidal-api" value="${tidal.url}" id="TidalJNDI" />
    

    4. Run dev mode, invoking the extra goal first, and activating your filter somehow

    E.g.:

    mvn resources:copy-resources liberty:dev
    

    As far as activating your filter, maybe you have a filter defined in your build (via build.filters.filter like in my sample repo) or maybe you're just using -Dtidal.url=<value>.

    FOLLOW-UP

    Besides being complicated a significant limitation of the above is that you only get a single chance to apply the filter. You cannot iterate through different values in a single dev mode "session".

    Feel free to give feedback on the issue: https://github.com/OpenLiberty/ci.maven/issues/587

    Also I will note we are considering enhancing filter support for general resources and web resources here.

    ONE MORE THOUGHT

    If all you need is a dynamic way to select, at build time, one set of Liberty config values vs. another you don't necessarily need to use filtering.

    You could instead use the support which maps Maven properties to Liberty config.

    E.g. for this example you could have one profile which defines

    <properties>
        <liberty.var.tidal.url>URL1</liberty.var.tidal.url>
    </properties>
    

    and another profile defining the same property with a different value.

    This would parameterize my sample:

    <jndiEntry jndiName="url/tidal-api" value="${tidal.url}" id="TidalJNDI" />
    

    just fine.

    The problem though is if you wanted to use the same sets of properties in other contexts with other plugins that did fully support filtering. Then, you want standard Maven filtering.