Skip to content

Commit

Permalink
Merge pull request #1706 from cherylking/latePropResolution
Browse files Browse the repository at this point in the history
Add late prop resolution for Liberty configuration specified by Maven props
  • Loading branch information
cherylking authored Jul 12, 2023
2 parents f7b7867 + 10ca3c9 commit f6dbbea
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 10 deletions.
6 changes: 6 additions & 0 deletions docs/common-server-parameters.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,3 +170,9 @@ Example of Liberty configuration with parameters:
</executions>
</plugin>
```

#### 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.
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,12 @@
<packaging>war</packaging>

<properties>
<!-- This maxHeap property should NOT override the one specified below in jvmOptions -->
<myBootstrapArg>someBootstrapValue</myBootstrapArg>
<myArgLine>-javaagent:/path/to/some/jar.jar</myArgLine>
<liberty.jvm.argLine>@{myArgLine}</liberty.jvm.argLine>
<liberty.jvm.undefined>@{undefined}</liberty.jvm.undefined>
<liberty.jvm.minHeap>-Xms512m</liberty.jvm.minHeap>
<!-- This maxHeap property should NOT override the one specified below in jvmOptions -->
<liberty.jvm.maxHeap>-Xmx1024m</liberty.jvm.maxHeap>
<liberty.bootstrap.location>pom.xml</liberty.bootstrap.location>
<liberty.env.JAVA_HOME>/opt/ibm/java</liberty.env.JAVA_HOME>
Expand Down Expand Up @@ -67,6 +71,10 @@
<jvmOptions>
<param>-Xmx768m</param>
</jvmOptions>
<bootstrapProperties>
<someBootstrapVar>@{myBootstrapArg}</someBootstrapVar>
<someUndefinedBootstrapVar>@{undefinedValue}</someUndefinedBootstrapVar>
</bootstrapProperties>
<serverName>test</serverName>
<serverXmlFile>src/test/resources/server.xml</serverXmlFile>
<bootstrapPropertiesFile>src/main/liberty/config/bootstrap.properties</bootstrapPropertiesFile>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -97,6 +99,10 @@ public abstract class StartDebugMojoSupport extends ServerFeatureSupport {
protected Map<String,String> combinedBootstrapProperties = null;
protected List<String> combinedJvmOptions = null;

// the following collections are copies of the originals with any @{xxx} references resolved in the values
protected Map<String,String> bootstrapPropertiesResolved = null; // original collection is bootstrapProperties
protected List<String> jvmOptionsResolved = null; // original collection is jvmOptions

@Component
protected BuildPluginManager pluginManager;

Expand Down Expand Up @@ -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) {
Expand All @@ -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) {
Expand Down Expand Up @@ -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);
Expand All @@ -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<String,String> handleLatePropertyResolution(Map<String,String> properties) {
Map<String,String> propertiesResolved = null;
if (properties != null) {
propertiesResolved = new HashMap<String,String> ();
for (Map.Entry<String, String> entry : properties.entrySet()) {
String value = resolveLatePropertyReferences(entry.getValue());
propertiesResolved.put(entry.getKey(), value);
}
}
return propertiesResolved;
}

protected List<String> handleLatePropertyResolution(List<String> properties) {
List<String> propertiesResolved = null;
if (properties != null) {
propertiesResolved = new ArrayList<String> ();
for (String nextOption : properties) {
String value = resolveLatePropertyReferences(nextOption);
propertiesResolved.add(value);
}
}
return propertiesResolved;
}

// The properties parameter comes from the <bootstrapProperties> configuration in pom.xml and takes precedence over
// the mavenProperties parameter, which comes from generic maven <properties> configuration.
// One of the passed in Maps must be not null and not empty
Expand Down

0 comments on commit f6dbbea

Please sign in to comment.