diff --git a/docs/common-server-parameters.md b/docs/common-server-parameters.md index e3de81402..454403c96 100644 --- a/docs/common-server-parameters.md +++ b/docs/common-server-parameters.md @@ -170,3 +170,9 @@ Example of Liberty configuration with parameters: ``` + +#### Late property replacement + +Maven does property replacement for `${...}` values in pom.xml before any plugin is run. Starting with the 3.8.3 release of the liberty-maven-plugin, an alternate syntax `@{...}` is supported which allows late replacement of properties when the plugin is executed. This enables properties that are modified by other plugins to be picked up correctly. + +The alternate syntax is supported for Liberty configuration specified by Maven properties, as well as the `jvmOptions` and `bootstrapProperties` parameters. diff --git a/liberty-maven-plugin/src/it/server-param-pom-override-it/pom.xml b/liberty-maven-plugin/src/it/server-param-pom-override-it/pom.xml index 833581ad9..949225f7c 100644 --- a/liberty-maven-plugin/src/it/server-param-pom-override-it/pom.xml +++ b/liberty-maven-plugin/src/it/server-param-pom-override-it/pom.xml @@ -13,8 +13,12 @@ war - + someBootstrapValue + -javaagent:/path/to/some/jar.jar + @{myArgLine} + @{undefined} -Xms512m + -Xmx1024m pom.xml /opt/ibm/java @@ -67,6 +71,10 @@ -Xmx768m + + @{myBootstrapArg} + @{undefinedValue} + test src/test/resources/server.xml src/main/liberty/config/bootstrap.properties diff --git a/liberty-maven-plugin/src/it/server-param-pom-override-it/src/test/java/net/wasdev/wlp/maven/test/app/PluginConfigXmlIT.java b/liberty-maven-plugin/src/it/server-param-pom-override-it/src/test/java/net/wasdev/wlp/maven/test/app/PluginConfigXmlIT.java index 2a3ef0dd2..172ce7a03 100644 --- a/liberty-maven-plugin/src/it/server-param-pom-override-it/src/test/java/net/wasdev/wlp/maven/test/app/PluginConfigXmlIT.java +++ b/liberty-maven-plugin/src/it/server-param-pom-override-it/src/test/java/net/wasdev/wlp/maven/test/app/PluginConfigXmlIT.java @@ -15,7 +15,7 @@ import org.w3c.dom.NodeList; import org.w3c.dom.Element; -import static junit.framework.Assert.*; +import static org.junit.Assert.*; public class PluginConfigXmlIT { @@ -96,8 +96,33 @@ public void testBootstrapPropertiesFileElements() throws Exception { nodes = (NodeList) xPath.compile(expression).evaluate(inputDoc, XPathConstants.NODESET); assertEquals("Number of bootstrapProperties element ==>", 1, nodes.getLength()); - assertEquals("verify target server bootstrap.properties", "# Generated by liberty-maven-plugin\nlocation=pom.xml\n", - FileUtils.fileRead(TARGET_BOOTSTRAP_PROPERTIES).replaceAll("\r","")); + String fileContents = FileUtils.fileRead(TARGET_BOOTSTRAP_PROPERTIES).replaceAll("\r",""); + + String[] fileContentsArray = fileContents.split("\\n"); + assertTrue("fileContents", fileContentsArray.length == 4); + + boolean someBootstrapVarFound = false; + boolean locationFound = false; + boolean someUndefinedBootstrapVarFound = false; + + for (int i=0; i < fileContentsArray.length; i++) { + String nextLine = fileContentsArray[i]; + if (i == 0) { + assertTrue("comment not found on first line", nextLine.equals("# Generated by liberty-maven-plugin")); + } else { + if (nextLine.equals("someBootstrapVar=someBootstrapValue")) { + someBootstrapVarFound = true; + } else if (nextLine.equals("location=pom.xml")) { + locationFound = true; + } else if (nextLine.equals("someUndefinedBootstrapVar=@{undefinedValue}")) { + someUndefinedBootstrapVarFound = true; + } + } + } + + assertTrue("someBootstrapVar=someBootstrapValue not found", someBootstrapVarFound); + assertTrue("location=pom.xml not found", locationFound); + assertTrue("someUndefinedBootstrapVar=@{undefinedValue} not found", someUndefinedBootstrapVarFound); } @Test @@ -126,8 +151,39 @@ public void testJvmOptionsFileElements() throws Exception { String fileContents = FileUtils.fileRead(TARGET_JVM_OPTIONS).replaceAll("\r",""); - // verify that -Xmx768m is last in the jvm.options file, and that -Xms512m and -Xmx1024m appear before it. - assertTrue("verify target server jvm.options", fileContents.equals( "# Generated by liberty-maven-plugin\n-Xms512m\n-Xmx1024m\n-Xmx768m\n") || fileContents.equals("# Generated by liberty-maven-plugin\n-Xmx1024m\n-Xms512m\n-Xmx768m\n")); + String[] fileContentsArray = fileContents.split("\\n"); + assertTrue("fileContents", fileContentsArray.length == 6); + + boolean myArgLineValueFound = false; + boolean myXms512mFound = false; + boolean myXmx1024mFound = false; + boolean myUndefinedVarFound = false; + + for (int i=0; i < fileContentsArray.length; i++) { + String nextLine = fileContentsArray[i]; + // verify that -Xmx768m is last in the jvm.options file, and that -Xms512m and -Xmx1024m appear before it. + if (i == 0) { + assertTrue("comment not found on first line", nextLine.equals("# Generated by liberty-maven-plugin")); + } else if (i == 5) { + assertTrue("-Xmx768m not found on last line", nextLine.equals("-Xmx768m")); + } else { + if (nextLine.equals("-Xms512m")) { + myXms512mFound = true; + } else if (nextLine.equals("-Xmx1024m")) { + myXmx1024mFound = true; + } else if (nextLine.equals("-javaagent:/path/to/some/jar.jar")) { + myArgLineValueFound = true; + } else if (nextLine.equals("@{undefined}")) { + myUndefinedVarFound = true; + } + } + } + + assertTrue("-Xms512m not found", myXms512mFound); + assertTrue("-Xmx1024m not found", myXmx1024mFound); + assertTrue("-javaagent:/path/to/some/jar.jar not found", myArgLineValueFound); + assertTrue("@{undefined} not found", myUndefinedVarFound); + } @Test diff --git a/liberty-maven-plugin/src/main/java/io/openliberty/tools/maven/server/PluginConfigSupport.java b/liberty-maven-plugin/src/main/java/io/openliberty/tools/maven/server/PluginConfigSupport.java index 1b16fe83a..becefe411 100644 --- a/liberty-maven-plugin/src/main/java/io/openliberty/tools/maven/server/PluginConfigSupport.java +++ b/liberty-maven-plugin/src/main/java/io/openliberty/tools/maven/server/PluginConfigSupport.java @@ -120,7 +120,10 @@ protected File exportParametersToXml() throws IOException, ParserConfigurationEx if (combinedBootstrapProperties != null) { configDocument.createElement("bootstrapProperties", combinedBootstrapProperties); } else if (bootstrapProperties != null) { - configDocument.createElement("bootstrapProperties", bootstrapProperties); + if (bootstrapPropertiesResolved == null) { + bootstrapPropertiesResolved = handleLatePropertyResolution(bootstrapProperties); + } + configDocument.createElement("bootstrapProperties", bootstrapPropertiesResolved); } else { configFile = findConfigFile("bootstrap.properties", bootstrapPropertiesFile); if (configFile != null) { @@ -131,7 +134,10 @@ protected File exportParametersToXml() throws IOException, ParserConfigurationEx if (combinedJvmOptions != null) { configDocument.createElement("jvmOptions", combinedJvmOptions); } else if (jvmOptions != null) { - configDocument.createElement("jvmOptions", jvmOptions); + if (jvmOptionsResolved == null) { + jvmOptionsResolved = handleLatePropertyResolution(jvmOptions); + } + configDocument.createElement("jvmOptions", jvmOptionsResolved); } else { configFile = findConfigFile("jvm.options", jvmOptionsFile); if (configFile != null) { diff --git a/liberty-maven-plugin/src/main/java/io/openliberty/tools/maven/server/StartDebugMojoSupport.java b/liberty-maven-plugin/src/main/java/io/openliberty/tools/maven/server/StartDebugMojoSupport.java index b297e0615..4199d251f 100644 --- a/liberty-maven-plugin/src/main/java/io/openliberty/tools/maven/server/StartDebugMojoSupport.java +++ b/liberty-maven-plugin/src/main/java/io/openliberty/tools/maven/server/StartDebugMojoSupport.java @@ -82,6 +82,8 @@ public abstract class StartDebugMojoSupport extends ServerFeatureSupport { protected static final String HEADER = "# Generated by liberty-maven-plugin"; private static final String LIBERTY_CONFIG_MAVEN_PROPS = "(^liberty\\.(env|jvm|bootstrap|var|defaultVar)\\.).+"; private static final Pattern pattern = Pattern.compile(LIBERTY_CONFIG_MAVEN_PROPS); + private static final String LATE_PROP_RESOLUTION_SYNTAX = "@\\{(.+?)\\}"; + private static final Pattern LATE_PROP_PATTERN = Pattern.compile(LATE_PROP_RESOLUTION_SYNTAX); private static boolean configFilesCopied = false; @@ -97,6 +99,10 @@ public abstract class StartDebugMojoSupport extends ServerFeatureSupport { protected Map combinedBootstrapProperties = null; protected List combinedJvmOptions = null; + // the following collections are copies of the originals with any @{xxx} references resolved in the values + protected Map bootstrapPropertiesResolved = null; // original collection is bootstrapProperties + protected List jvmOptionsResolved = null; // original collection is jvmOptions + @Component protected BuildPluginManager pluginManager; @@ -553,7 +559,8 @@ protected void copyConfigFiles() throws IOException, MojoExecutionException { if (jvmOptionsPath != null) { getLog().warn("The " + jvmOptionsPath + " file is overwritten by inlined configuration."); } - writeJvmOptions(optionsFile, jvmOptions, jvmMavenProps); + jvmOptionsResolved = handleLatePropertyResolution(jvmOptions); + writeJvmOptions(optionsFile, jvmOptionsResolved, jvmMavenProps); jvmOptionsPath = "inlined configuration"; } else if (jvmOptionsFile != null && jvmOptionsFile.exists()) { if (jvmOptionsPath != null) { @@ -580,7 +587,8 @@ protected void copyConfigFiles() throws IOException, MojoExecutionException { if (bootStrapPropertiesPath != null) { getLog().warn("The " + bootStrapPropertiesPath + " file is overwritten by inlined configuration."); } - writeBootstrapProperties(bootstrapFile, bootstrapProperties, bootstrapMavenProps); + bootstrapPropertiesResolved = handleLatePropertyResolution(bootstrapProperties); + writeBootstrapProperties(bootstrapFile, bootstrapPropertiesResolved, bootstrapMavenProps); bootStrapPropertiesPath = "inlined configuration"; } else if (bootstrapPropertiesFile != null && bootstrapPropertiesFile.exists()) { if (bootStrapPropertiesPath != null) { @@ -796,6 +804,9 @@ private void loadLibertyConfigFromProperties(Properties props) { if (propType != null) { String suffix = key.substring(propType.getPrefix().length()); String value = (String) entry.getValue(); + // Check the value for late property resolution with @{xxx} syntax. + value = resolveLatePropertyReferences(value); + getLog().debug("Processing Liberty configuration from property with key "+key+" and value "+value); switch (propType) { case ENV: envMavenProps.put(suffix, value); @@ -813,6 +824,51 @@ private void loadLibertyConfigFromProperties(Properties props) { } } + // Search the value parameter for any properties referenced with @{xxx} syntax and replace those with their property value if defined. + private String resolveLatePropertyReferences(String value) { + String returnValue = value; + + if (value != null) { + Matcher m = LATE_PROP_PATTERN.matcher(value); + while (m.find()) { + String varName = m.group(1); + if (project.getProperties().containsKey(varName)) { + String replacementValue = project.getProperties().getProperty(varName); + if (replacementValue != null) { + returnValue = returnValue.replace("@{"+varName+"}", replacementValue); + getLog().debug("Replaced Liberty configuration property value @{"+varName+"} with value "+replacementValue); + } + } + } + } + + return returnValue; + } + + protected Map handleLatePropertyResolution(Map properties) { + Map propertiesResolved = null; + if (properties != null) { + propertiesResolved = new HashMap (); + for (Map.Entry entry : properties.entrySet()) { + String value = resolveLatePropertyReferences(entry.getValue()); + propertiesResolved.put(entry.getKey(), value); + } + } + return propertiesResolved; + } + + protected List handleLatePropertyResolution(List properties) { + List propertiesResolved = null; + if (properties != null) { + propertiesResolved = new ArrayList (); + for (String nextOption : properties) { + String value = resolveLatePropertyReferences(nextOption); + propertiesResolved.add(value); + } + } + return propertiesResolved; + } + // The properties parameter comes from the configuration in pom.xml and takes precedence over // the mavenProperties parameter, which comes from generic maven configuration. // One of the passed in Maps must be not null and not empty