Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add late prop resolution for Liberty configuration specified by Maven props #1706

Merged
merged 5 commits into from
Jul 12, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading