modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/util/JavaCommandLine.java | 200 ++++
modules/core/plugin-api/src/test/java/org/rhq/core/pluginapi/util/JavaCommandLineTest.java | 4
modules/plugins/jboss-as-7/pom.xml | 47 +
modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/AS7CommandLine.java | 52 -
modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/AS7CommandLineTest.java | 402 +++++++++-
5 files changed, 635 insertions(+), 70 deletions(-)
New commits:
commit 602c22d8493be65b05719888a1e57b1bb92372e1
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Mon Feb 4 18:53:21 2013 +0100
[BZ 907558] - JavaCommandLine and subclasses now parse the commandline lazily
to prevent calling overriden methods in super-class constructor.
A couple of other cosmetic improvements like static logger, etc.
(originally cherry-picked from master commit 2910d155e509b6ebccdc9483a70b2910bdf0133c) but had to remove jacoco.unit-test.args from the surefire argLine value as jacoco is not defined in 3.1.x code base.
diff --git a/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/util/JavaCommandLine.java b/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/util/JavaCommandLine.java
index 3319500..add1a3a 100644
--- a/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/util/JavaCommandLine.java
+++ b/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/util/JavaCommandLine.java
@@ -28,10 +28,13 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
+import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
+import java.util.regex.Pattern;
import com.sun.istack.Nullable;
@@ -49,11 +52,19 @@ import org.jetbrains.annotations.NotNull;
* or java [-options] -jar jarfile [args...]
* (to execute a jar file)
* </code></pre>
+ * <p>
+ * Note that this class offers the subclasses to ehance the parsing process by overriding the {@link #processClassArgument(String, String)}
+ * method. To be able to achieve that, the evaluation of the commandline arguments needs to happen lazily.
+ * See the {@link #parseCommandLine()} method for subclassing guidelines.
+ * <p>
+ * This class is <b>NOT</b> thread-safe.
*
* @author Ian Springer
+ * @author Lukas Krejci
*/
public class JavaCommandLine {
- /**
+
+ /**
* When parsing command line options, specifies the valid option value delimiter(s).
*
* @see JavaCommandLine#getClassOption(CommandLineOption)
@@ -74,9 +85,18 @@ public class JavaCommandLine {
private static final String SHORT_OPTION_PREFIX = "-";
private static final String LONG_OPTION_PREFIX = "--";
- private final Log log = LogFactory.getLog(JavaCommandLine.class);
+ private static final Pattern SYSTEM_PROPERTY_PATTERN = Pattern.compile("-D.+");
+
+ private static final Log log = LogFactory.getLog(JavaCommandLine.class);
+
+ //These properties are passed to the constructors
+ private final List<String> arguments;
+ private final boolean includeSystemPropertiesFromClassArguments;
+ private final Set<OptionValueDelimiter> shortClassOptionValueDelims;
+ private final Set<OptionValueDelimiter> longClassOptionValueDelims;
- private List<String> arguments;
+ //These are lazily evaluated in the getters
+ private boolean argumentsParsed;
private File javaExecutable;
private List<String> classPath;
private Map<String, String> systemProperties;
@@ -84,9 +104,6 @@ public class JavaCommandLine {
private String mainClassName;
private File executableJarFile;
private List<String> classArguments;
- private boolean includeSystemPropertiesFromClassArguments;
- private Set<OptionValueDelimiter> shortClassOptionValueDelims;
- private Set<OptionValueDelimiter> longClassOptionValueDelims;
private Map<String, String> shortClassOptionNameToOptionValueMap;
private Map<String, String> longClassOptionNameToOptionValueMap;
@@ -132,16 +149,49 @@ public class JavaCommandLine {
// Wrap as list and store as field for use by getArguments() and toString().
this.arguments = Arrays.asList(args);
-
- parseCommandLine(args);
}
- private void parseCommandLine(String[] args) {
+ /**
+ * This method can be called to process the command line from the arguments passed in the constructor.
+ * This is to support lazy evaluation of the parsed properties.
+ * <p>
+ * Any class overriding the {@link #processClassArgument(String, String)} method should make sure to call this method
+ * if it finds that the data extracted in that method is still uninitialized.
+ * <p>
+ * Typically, this will happen during a getter for such data:
+ * <pre>
+ * <code>
+ * public Data getDataExtractedFromCommandLine() {
+ * if (data == null) {
+ * parseCommandLine();
+ * }
+ *
+ * return data;
+ * }
+ * </code>
+ * </pre>
+ *
+ * The data variable would then be initialized as part of the {@link #processClassArgument(String, String)} method
+ * that gets called during the execution of this method.
+ * <p>
+ * Alternatively to the null check on the data, the subclass can use the {@link #isArgumentsParsed()} method that
+ * returns true only if this method successfully finished.
+ * <p>
+ * If you are overriding this method make sure to call <code>super.parseCommandLine()</code> before any of your other
+ * logic, otherwise you may end up with an <b>endless loop</b> (and eventually stack overflow) if you try to access
+ * any of the getters of the data extracted from the commandline (like {@link #getClassArguments()},
+ * {@link #getClassPath()}, etc).
+ */
+ protected void parseCommandLine() {
if (log.isDebugEnabled()) {
log.debug("Parsing " + this + "...");
}
- this.javaExecutable = new File(args[0]);
+ ListIterator<String> argIterator = arguments.listIterator();
+ ListIterator<String> classArgumentsIterator = arguments.listIterator();
+
+ this.javaExecutable = new File(argIterator.next());
+
this.classPath = new ArrayList<String>();
this.systemProperties = new LinkedHashMap<String, String>();
this.javaOptions = new ArrayList<String>();
@@ -149,26 +199,31 @@ public class JavaCommandLine {
boolean nextArgIsClassPath = false;
boolean nextArgIsJarFile = false;
- for (int i = 1; i < args.length; i++) {
- String arg = args[i];
+
+ while (argIterator.hasNext()) {
+ String arg = argIterator.next();
+
+ //skip along with the main iterator... once we break out of this loop, this iterator
+ //will point to the start of the class arguments.
+ classArgumentsIterator.next();
if (nextArgIsClassPath) {
this.classPath.addAll(Arrays.asList(arg.split(File.pathSeparator)));
nextArgIsClassPath = false;
} else if (nextArgIsJarFile) {
this.executableJarFile = new File(arg);
- parseClassArguments(args, i + 1);
+ parseClassArguments(argIterator, true);
break;
} else if (arg.charAt(0) != '-') {
this.mainClassName = arg;
- parseClassArguments(args, i + 1);
+ parseClassArguments(argIterator, true);
break;
} else if (arg.equals("-cp") || arg.equals("-classpath")) {
- if ((i + 1) == args.length) {
+ if (!argIterator.hasNext()) {
throw new IllegalArgumentException(arg + " option has no argument.");
}
nextArgIsClassPath = true;
} else if (arg.equals("-jar")) {
- if ((i + 1) == args.length) {
+ if (!argIterator.hasNext()) {
throw new IllegalArgumentException(arg + " option has no argument.");
}
nextArgIsJarFile = true;
@@ -180,26 +235,81 @@ public class JavaCommandLine {
}
}
+ parseClassOptions();
+
+ argumentsParsed = true;
+
+ if (classArgumentsIterator.hasNext()) {
+ parseClassArguments(classArgumentsIterator, false);
+ }
+
this.classPath = Collections.unmodifiableList(this.classPath);
this.javaOptions = Collections.unmodifiableList(this.javaOptions);
this.classArguments = Collections.unmodifiableList(this.classArguments);
this.systemProperties = Collections.unmodifiableMap(this.systemProperties);
+ }
- parseClassOptions();
+ /**
+ * @return true iff the {@link #parseCommandLine()} method was called and successfully finished.
+ */
+ protected boolean isArgumentsParsed() {
+ return argumentsParsed;
}
- private void parseClassArguments(String[] args, int beginIndex) {
- for (int i = beginIndex; i < args.length; i++) {
- String classArg = args[i];
- processClassArgument(classArg, ((i + 1) != args.length) ? args[i + 1] : null);
+ private void parseClassArguments(Iterator<String> arguments, boolean firstPass) {
+ if (!arguments.hasNext()) {
+ return;
+ }
+
+ //as strange as it seems, this adds each and every argument found in
+ //arguments as a class argument.
+ //Additionally, it will call processClassArgument() with every such class argument and the next argument in line.
+
+ String classArg = arguments.next();
+
+ while (arguments.hasNext()) {
+ String nextArg = arguments.next();
+
+ processClassArgument(classArg, nextArg, firstPass);
+
+ classArg = nextArg;
+ }
+
+ processClassArgument(classArg, null, firstPass);
+ }
+
+ private void processClassArgument(String classArg, String nextArg, boolean firstPass) {
+ if (firstPass) {
+ //in first pass, we do the processing required by this class
+ if (this.includeSystemPropertiesFromClassArguments && isSystemPropertyArgument(classArg)) {
+ parseSystemPropertyArgument(classArg);
+ }
+
this.classArguments.add(classArg);
+ } else {
+ //in the second pass, we let the subclasses process the class arguments
+ processClassArgument(classArg, nextArg);
}
}
+ /**
+ * Override this method to do additional processing of the class arguments.
+ * This method is called during the {@link #parseCommandLine()} call but after all other properties are processed.
+ * <p>
+ * It is therefore safe to call {@link #getClassArguments()}, {@link #getExecutableJarFile()} and all other getters
+ * defined by {@link JavaCommandLine}. At the time this method is called during {@link #parseCommandLine()}, the
+ * default implementation of {@link #isArgumentsParsed()} already returns true.
+ * <p>
+ * This method is called at a stage during the parsing of the commandline where all the properties are still writeable
+ * - you can modify the {@link #getSystemProperties() system properties} and other collections.
+ * <p>
+ * By default this method does nothing.
+ *
+ * @param classArg
+ * @param nextArg
+ */
protected void processClassArgument(String classArg, String nextArg) {
- if (this.includeSystemPropertiesFromClassArguments && isSystemPropertyArgument(classArg)) {
- parseSystemPropertyArgument(classArg);
- }
+ //do nothing by default.
}
private void parseClassOptions() {
@@ -285,7 +395,7 @@ public class JavaCommandLine {
}
private boolean isSystemPropertyArgument(String arg) {
- return arg.matches("-D.+");
+ return SYSTEM_PROPERTY_PATTERN.matcher(arg).matches();
}
private void parseSystemPropertyArgument(String arg) {
@@ -310,36 +420,64 @@ public class JavaCommandLine {
@NotNull
public File getJavaExecutable() {
+ if (!argumentsParsed) {
+ parseCommandLine();
+ }
+
return javaExecutable;
}
@NotNull
public List<String> getClassPath() {
+ if (!argumentsParsed) {
+ parseCommandLine();
+ }
+
return classPath;
}
@NotNull
public Map<String, String> getSystemProperties() {
+ if (!argumentsParsed) {
+ parseCommandLine();
+ }
+
return systemProperties;
}
@NotNull
public List<String> getJavaOptions() {
+ if (!argumentsParsed) {
+ parseCommandLine();
+ }
+
return javaOptions;
}
@Nullable
public String getMainClassName() {
+ if (!argumentsParsed) {
+ parseCommandLine();
+ }
+
return mainClassName;
}
@Nullable
public File getExecutableJarFile() {
+ if (!argumentsParsed) {
+ parseCommandLine();
+ }
+
return executableJarFile;
}
@NotNull
public List<String> getClassArguments() {
+ if (!argumentsParsed) {
+ parseCommandLine();
+ }
+
return classArguments;
}
@@ -351,6 +489,10 @@ public class JavaCommandLine {
*/
@Nullable
public String getClassOption(CommandLineOption option) {
+ if (!argumentsParsed) {
+ parseCommandLine();
+ }
+
return getClassOption(option, null);
}
@@ -363,6 +505,10 @@ public class JavaCommandLine {
*/
@Nullable
public String getClassOption(CommandLineOption option, String defaultValue) {
+ if (!argumentsParsed) {
+ parseCommandLine();
+ }
+
String optionValue = null;
// Note, we never store null values in either of the option value maps.
@@ -403,6 +549,10 @@ public class JavaCommandLine {
}
public boolean isClassOptionPresent(CommandLineOption option) {
+ if (!argumentsParsed) {
+ parseCommandLine();
+ }
+
String optionValue = getClassOption(option);
return (optionValue != null);
}
diff --git a/modules/core/plugin-api/src/test/java/org/rhq/core/pluginapi/util/JavaCommandLineTest.java b/modules/core/plugin-api/src/test/java/org/rhq/core/pluginapi/util/JavaCommandLineTest.java
index a8bab91..5f6a387 100644
--- a/modules/core/plugin-api/src/test/java/org/rhq/core/pluginapi/util/JavaCommandLineTest.java
+++ b/modules/core/plugin-api/src/test/java/org/rhq/core/pluginapi/util/JavaCommandLineTest.java
@@ -39,12 +39,12 @@ public class JavaCommandLineTest {
@Test(expectedExceptions = {IllegalArgumentException.class})
public void testNullArrayParam() throws Exception {
- JavaCommandLine javaCommandLine = new JavaCommandLine(null);
+ new JavaCommandLine((String[])null);
}
@Test(expectedExceptions = {IllegalArgumentException.class})
public void testEmptyArrayParam() throws Exception {
- JavaCommandLine javaCommandLine = new JavaCommandLine(new String[0]);
+ new JavaCommandLine(new String[0]);
}
public void testClass() throws Exception {
diff --git a/modules/plugins/jboss-as-7/pom.xml b/modules/plugins/jboss-as-7/pom.xml
index 9abba87..a84a7eb 100644
--- a/modules/plugins/jboss-as-7/pom.xml
+++ b/modules/plugins/jboss-as-7/pom.xml
@@ -88,7 +88,14 @@
<artifactId>postgresql</artifactId>
<scope>test</scope>
</dependency>
-
+
+ <!-- For native subsystem -->
+ <dependency>
+ <groupId>org.hyperic</groupId>
+ <artifactId>sigar-dist</artifactId>
+ <type>zip</type>
+ <scope>test</scope>
+ </dependency>
</dependencies>
@@ -137,9 +144,47 @@
-->
<exclude>org/rhq/modules/plugins/jbossas7/itest/**</exclude>
</excludes>
+ <!-- This is where the antrun below puts the sigar native libs -->
+ <argLine>-Djava.library.path=${project.build.directory}/test-libs</argLine>
</configuration>
</plugin>
+ <plugin>
+ <artifactId>maven-antrun-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>deploy-sigar-native-to-test-classpath</id>
+ <phase>generate-test-resources</phase>
+ <configuration>
+ <tasks>
+ <echo>Copying SIGAR native libs to test-libs</echo>
+ <unzip dest="${project.build.directory}/test-libs">
+ <fileset
+ dir="${settings.localRepository}/org/hyperic/sigar-dist/${sigar.version}"
+ includes="*.zip"/>
+ <patternset>
+ <include name="**/lib/sigar.jar"/>
+ <include name="**/lib/bcel*.jar"/>
+ <include name="**/lib/*.so"/>
+ <include name="**/lib/*.sl"/>
+ <include name="**/lib/*.dll"/>
+ <include name="**/lib/*.dylib"/>
+ </patternset>
+ </unzip>
+ <move todir="${project.build.directory}/test-libs" flatten="true">
+ <fileset dir="${project.build.directory}/test-libs">
+ <include name="**/lib/*"/>
+ </fileset>
+ </move>
+ <delete dir="${project.build.directory}/test-libs/hyperic-sigar-${sigar.version}"/>
+ </tasks>
+ </configuration>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
</plugins>
</build>
diff --git a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/AS7CommandLine.java b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/AS7CommandLine.java
index b44ceb3..cd654fa 100644
--- a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/AS7CommandLine.java
+++ b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/AS7CommandLine.java
@@ -58,7 +58,7 @@ public class AS7CommandLine extends JavaCommandLine {
"--" + PROPERTIES_OPTION.getLongName()
};
- private final Log log = LogFactory.getLog(AS7CommandLine.class);
+ private static final Log LOG = LogFactory.getLog(AS7CommandLine.class);
private String appServerModuleName;
private List<String> appServerArgs;
@@ -72,8 +72,30 @@ public class AS7CommandLine extends JavaCommandLine {
public AS7CommandLine(ProcessInfo process) {
this(process.getCommandLine());
-
this.process = process;
+ }
+
+ @NotNull
+ public String getAppServerModuleName() {
+ if (!isArgumentsParsed()) {
+ parseCommandLine();
+ }
+
+ return this.appServerModuleName;
+ }
+
+ @NotNull
+ public List<String> getAppServerArguments() {
+ if (!isArgumentsParsed()) {
+ parseCommandLine();
+ }
+
+ return this.appServerArgs;
+ }
+
+ @Override
+ protected void parseCommandLine() {
+ super.parseCommandLine();
// In the case of AS7, the class arguments are actually the arguments to the jboss-modules.jar main class. We
// want to split out the arguments to the app server module (i.e. "org.jboss.as.standalone" or
@@ -101,16 +123,6 @@ public class AS7CommandLine extends JavaCommandLine {
}
}
- @NotNull
- public String getAppServerModuleName() {
- return this.appServerModuleName;
- }
-
- @NotNull
- public List<String> getAppServerArguments() {
- return this.appServerArgs;
- }
-
@Override
protected void processClassArgument(String classArg, String nextArg) {
super.processClassArgument(classArg, nextArg);
@@ -133,8 +145,8 @@ public class AS7CommandLine extends JavaCommandLine {
if (propertiesURL != null) {
Properties props = loadProperties(propertiesURL);
if (props != null) {
- for (Map.Entry entry : props.entrySet()) {
- Map<String, String> sysProps = getSystemProperties();
+ Map<String, String> sysProps = getSystemProperties();
+ for (Map.Entry<?, ?> entry : props.entrySet()) {
sysProps.put((String) entry.getKey(), (String) entry.getValue());
}
}
@@ -163,7 +175,7 @@ public class AS7CommandLine extends JavaCommandLine {
propertiesURL = absoluteFile.toURI().toURL();
} catch (MalformedURLException murle2) {
propertiesURL = null;
- log.error("Value of class option " + PROPERTIES_OPTION + " (" + value + ") is not a valid URL.");
+ LOG.error("Value of class option " + PROPERTIES_OPTION + " (" + value + ") is not a valid URL.");
}
}
@@ -182,7 +194,7 @@ public class AS7CommandLine extends JavaCommandLine {
File binDir = new File(homeDir, "bin");
absoluteFile = new File(binDir, file.getPath());
} else {
- log.error("Failed to resolve relative properties file path [" + file + "].");
+ LOG.error("Failed to resolve relative properties file path [" + file + "].");
return null;
}
}
@@ -198,18 +210,18 @@ public class AS7CommandLine extends JavaCommandLine {
try {
urlConnection = propertiesURL.openConnection();
} catch (IOException e) {
- log.error("Failed to connect to URL [" + propertiesURL + "].", e);
+ LOG.error("Failed to connect to URL [" + propertiesURL + "].", e);
return null;
}
InputStream inputStream;
try {
inputStream = urlConnection.getInputStream();
if (inputStream == null) {
- log.error("Failed to read from URL [" + propertiesURL + "].");
+ LOG.error("Failed to read from URL [" + propertiesURL + "].");
return null;
}
} catch (IOException e) {
- log.error("Failed to read from URL [" + propertiesURL + "].", e);
+ LOG.error("Failed to read from URL [" + propertiesURL + "].", e);
return null;
}
@@ -217,7 +229,7 @@ public class AS7CommandLine extends JavaCommandLine {
try {
props.load(inputStream);
} catch (IOException e) {
- log.error("Failed to parse properties from URL [" + propertiesURL + "].", e);
+ LOG.error("Failed to parse properties from URL [" + propertiesURL + "].", e);
return null;
}
return props;
diff --git a/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/AS7CommandLineTest.java b/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/AS7CommandLineTest.java
index fc6c487..b21ef7a 100644
--- a/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/AS7CommandLineTest.java
+++ b/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/AS7CommandLineTest.java
@@ -1,48 +1,334 @@
package org.rhq.modules.plugins.jbossas7;
import java.io.File;
+import java.io.InputStreamReader;
+import java.util.Arrays;
+import java.util.List;
import java.util.Map;
import org.testng.Assert;
import org.testng.annotations.Test;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.asset.StringAsset;
+import org.jboss.shrinkwrap.api.exporter.ZipExporter;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+
+import org.rhq.core.system.ProcessInfo;
+import org.rhq.core.system.SystemInfo;
+import org.rhq.core.system.SystemInfoFactory;
import org.rhq.core.util.PropertiesFileUpdate;
+import org.rhq.core.util.stream.StreamUtil;
/**
* A unit test for {@link AS7CommandLine}.
*/
-@Test
public class AS7CommandLineTest {
+ private static final File FAKE_JBOSS_HOME = new File(".");
+
+ private interface CommandLineProducer {
+ AS7CommandLine get();
+ }
+
+ public static class FakeServerProcess {
+ ProcessInfo processInfo;
+ File fakeJBossModulesJar;
+
+ void cleanUp() throws Exception {
+ processInfo.kill("KILL");
+ fakeJBossModulesJar.delete();
+ }
+
+ //this used as a main class of the process that fakes a running AS7 server
+ //It just sits idle until killed (a featureful application server, indeed :) ).
+ public static synchronized void main(String[] args) throws Exception {
+ FakeServerProcess.class.wait();
+ }
+ }
+
+ @Test
+ public void testSysPropsWithAbsolutePathAndFileProtocolWithoutProcess() throws Exception {
+ File propsFile1 = File.createTempFile("jboss1-", ".properties");
+ File propsFile2 = File.createTempFile("jboss2-", ".properties");
+
+ String propsFile1Path = "file://" + propsFile1;
+ String propsFile2Path = "file://" + propsFile2;
+
+ try {
+ testSysProps(propsFile1, propsFile2, FAKE_JBOSS_HOME,
+ getAs7CommandLine(propsFile1Path, propsFile2Path, FAKE_JBOSS_HOME));
+ } finally {
+ propsFile1.delete();
+ propsFile2.delete();
+ }
+ }
+
+ @Test
+ public void testSysPropsWithRelativePathAndFileProtocolWithoutProcess() throws Exception {
+ File propsFile1 = File.createTempFile("jboss1-", ".properties", new File("."));
+ File propsFile2 = File.createTempFile("jboss2-", ".properties", new File("."));
+
+ //create the bin subdirectory so that the path deduced by AS7CommandLine can be traversed
+ new File("bin").mkdir();
+
+ //without the process, the AS7CommandLine tries to figure out the path as relative to $JBOSS_HOME/bin
+ //since we're assigning jboss home to "." and creating the file in ".", too, we need to prepend the
+ //path with a ".." to jump out of the assumed "bin".
+ String propsFile1Path = "file:../" + propsFile1.getName();
+ String propsFile2Path = "file:../" + propsFile2.getName();
+
+ try {
+ testSysProps(propsFile1, propsFile2, FAKE_JBOSS_HOME,
+ getAs7CommandLine(propsFile1Path, propsFile2Path, FAKE_JBOSS_HOME));
+ } finally {
+ propsFile1.delete();
+ propsFile2.delete();
+ new File("bin").delete();
+ }
+ }
+
+ @Test
+ public void testSysPropsWithAbsolutePathWithoutProcess() throws Exception {
+ File propsFile1 = File.createTempFile("jboss1-", ".properties");
+ File propsFile2 = File.createTempFile("jboss2-", ".properties");
+
+ String propsFile1Path = propsFile1.getAbsolutePath();
+ String propsFile2Path = propsFile2.getAbsolutePath();
+
+ try {
+ testSysProps(propsFile1, propsFile2, FAKE_JBOSS_HOME,
+ getAs7CommandLine(propsFile1Path, propsFile2Path, FAKE_JBOSS_HOME));
+ } finally {
+ propsFile1.delete();
+ propsFile2.delete();
+ }
+ }
+
+ @Test
+ public void testSysPropsWithRelativePathWithoutProcess() throws Exception {
+ File propsFile1 = File.createTempFile("jboss1-", ".properties", new File("."));
+ File propsFile2 = File.createTempFile("jboss2-", ".properties", new File("."));
+
+ //create the bin subdirectory so that the path deduced by AS7CommandLine can be traversed
+ new File("bin").mkdir();
+
+ //without the process, the AS7CommandLine tries to figure out the path as relative to $JBOSS_HOME/bin
+ //since we're assigning jboss home to "." and creating the file in ".", too, we need to prepend the
+ //path with a ".." to jump out of the assumed "bin".
+ String propsFile1Path = "../" + propsFile1.getName();
+ String propsFile2Path = "../" + propsFile2.getName();
+
+ try {
+ testSysProps(propsFile1, propsFile2, FAKE_JBOSS_HOME,
+ getAs7CommandLine(propsFile1Path, propsFile2Path, FAKE_JBOSS_HOME));
+ } finally {
+ propsFile1.delete();
+ propsFile2.delete();
+ new File("bin").delete();
+ }
+ }
+
+ @Test
+ public void testSysPropsWithAbsolutePathWithProcess() throws Exception {
+ File propsFile1 = File.createTempFile("jboss1-", ".properties");
+ File propsFile2 = File.createTempFile("jboss2-", ".properties");
+
+ String propsFile1Path = propsFile1.getAbsolutePath();
+ String propsFile2Path = propsFile2.getAbsolutePath();
+
+ FakeServerProcess fakeServer = startFakeServer(FAKE_JBOSS_HOME, FAKE_JBOSS_HOME, propsFile1Path, propsFile2Path);
+
+ Assert.assertNotNull(fakeServer, "Failed to start or find the fake server process.");
+
+ try {
+ testSysProps(propsFile1, propsFile2, FAKE_JBOSS_HOME, getAs7CommandLine(fakeServer));
+ } finally {
+ propsFile1.delete();
+ propsFile2.delete();
+ fakeServer.cleanUp();
+ }
+ }
+
+ @Test
+ public void testSysPropsWithAbsolutePathWithProcessFromDifferentDirectory() throws Exception {
+ File propsFile1 = File.createTempFile("jboss1-", ".properties");
+ File propsFile2 = File.createTempFile("jboss2-", ".properties");
+
+ String propsFile1Path = propsFile1.getAbsolutePath();
+ String propsFile2Path = propsFile2.getAbsolutePath();
+
+ FakeServerProcess fakeServer = startFakeServer(new File(".."), FAKE_JBOSS_HOME, propsFile1Path, propsFile2Path);
+
+ Assert.assertNotNull(fakeServer, "Failed to start or find the fake server process.");
+
+ try {
+ testSysProps(propsFile1, propsFile2, FAKE_JBOSS_HOME, getAs7CommandLine(fakeServer));
+ } finally {
+ propsFile1.delete();
+ propsFile2.delete();
+ fakeServer.cleanUp();
+ }
+ }
+
+ @Test
+ public void testSysPropsWithAbsolutePathAndFileProtocolWithProcess() throws Exception {
+ File propsFile1 = File.createTempFile("jboss1-", ".properties");
+ File propsFile2 = File.createTempFile("jboss2-", ".properties");
+
+ String propsFile1Path = "file://" + propsFile1;
+ String propsFile2Path = "file://" + propsFile2;
+
+ FakeServerProcess fakeServer = startFakeServer(FAKE_JBOSS_HOME, FAKE_JBOSS_HOME, propsFile1Path, propsFile2Path);
+
+ Assert.assertNotNull(fakeServer, "Failed to start or find the fake server process.");
+
+ try {
+ testSysProps(propsFile1, propsFile2, FAKE_JBOSS_HOME, getAs7CommandLine(fakeServer));
+ } finally {
+ propsFile1.delete();
+ propsFile2.delete();
+ fakeServer.cleanUp();
+ }
+ }
- public void testSysProps() throws Exception {
+ @Test
+ public void testSysPropsWithAbsolutePathAndFileProtocolWithProcessFromDifferentDirectory() throws Exception {
File propsFile1 = File.createTempFile("jboss1-", ".properties");
+ File propsFile2 = File.createTempFile("jboss2-", ".properties");
+
+ String propsFile1Path = "file://" + propsFile1;
+ String propsFile2Path = "file://" + propsFile2;
+
+ FakeServerProcess fakeServer = startFakeServer(new File(".."), FAKE_JBOSS_HOME, propsFile1Path, propsFile2Path);
+
+ Assert.assertNotNull(fakeServer, "Failed to start or find the fake server process.");
+
+ try {
+ testSysProps(propsFile1, propsFile2, FAKE_JBOSS_HOME, getAs7CommandLine(fakeServer));
+ } finally {
+ propsFile1.delete();
+ propsFile2.delete();
+ fakeServer.cleanUp();
+ }
+ }
+
+ @Test
+ public void testSysPropsWithRelativePathAndFileProtocolWithProcess() throws Exception {
+ File propsFile1 = File.createTempFile("jboss1-", ".properties", FAKE_JBOSS_HOME);
+ File propsFile2 = File.createTempFile("jboss2-", ".properties", FAKE_JBOSS_HOME);
+
+ String propsFile1Path = "file:./" + propsFile1.getName();
+ String propsFile2Path = "file:./" + propsFile2.getName();
+
+ FakeServerProcess fakeServer = startFakeServer(FAKE_JBOSS_HOME, FAKE_JBOSS_HOME, propsFile1Path, propsFile2Path);
+
+ Assert.assertNotNull(fakeServer, "Failed to start or find the fake server process.");
+
+ try {
+ testSysProps(propsFile1, propsFile2, FAKE_JBOSS_HOME, getAs7CommandLine(fakeServer));
+ } finally {
+ propsFile1.delete();
+ propsFile2.delete();
+ fakeServer.cleanUp();
+ }
+ }
+
+ @Test
+ public void testSysPropsWithRelativePathAndFileProtocolWithProcessFromDifferentDirectory() throws Exception {
+ File cwd = new File("..");
+ File propsFile1 = File.createTempFile("jboss1-", ".properties", cwd);
+ File propsFile2 = File.createTempFile("jboss2-", ".properties", cwd);
+
+ String propsFile1Path = "file:./" + propsFile1.getName();
+ String propsFile2Path = "file:./" + propsFile2.getName();
+
+ FakeServerProcess fakeServer = startFakeServer(cwd, FAKE_JBOSS_HOME, propsFile1Path, propsFile2Path);
+
+ Assert.assertNotNull(fakeServer, "Failed to start or find the fake server process.");
+
+ try {
+ testSysProps(propsFile1, propsFile2, FAKE_JBOSS_HOME, getAs7CommandLine(fakeServer));
+ } finally {
+ propsFile1.delete();
+ propsFile2.delete();
+ fakeServer.cleanUp();
+ }
+ }
+
+ @Test
+ public void testSysPropsWithRelativePathWithProcess() throws Exception {
+ File propsFile1 = File.createTempFile("jboss1-", ".properties", FAKE_JBOSS_HOME);
+ File propsFile2 = File.createTempFile("jboss2-", ".properties", FAKE_JBOSS_HOME);
+
+ String propsFile1Path = propsFile1.getName();
+ String propsFile2Path = propsFile2.getName();
+
+ FakeServerProcess fakeServer = startFakeServer(FAKE_JBOSS_HOME, FAKE_JBOSS_HOME, propsFile1Path, propsFile2Path);
+
+ Assert.assertNotNull(fakeServer, "Failed to start or find the fake server process.");
+
+ try {
+ testSysProps(propsFile1, propsFile2, FAKE_JBOSS_HOME, getAs7CommandLine(fakeServer));
+ } finally {
+ propsFile1.delete();
+ propsFile2.delete();
+ fakeServer.cleanUp();
+ }
+ }
+
+ @Test
+ public void testSysPropsWithRelativePathWithProcessFromDifferentDirectory() throws Exception {
+ File cwd = new File("..");
+ File propsFile1 = File.createTempFile("jboss1-", ".properties", cwd);
+ File propsFile2 = File.createTempFile("jboss2-", ".properties", cwd);
+ String propsFile1Path = propsFile1.getName();
+ String propsFile2Path = propsFile2.getName();
+
+ FakeServerProcess fakeServer = startFakeServer(cwd, FAKE_JBOSS_HOME, propsFile1Path, propsFile2Path);
+
+ Assert.assertNotNull(fakeServer, "Failed to start or find the fake server process.");
+
+ try {
+ testSysProps(propsFile1, propsFile2, FAKE_JBOSS_HOME, getAs7CommandLine(fakeServer));
+ } finally {
+ propsFile1.delete();
+ propsFile2.delete();
+ fakeServer.cleanUp();
+ }
+ }
+
+ private CommandLineProducer getAs7CommandLine(final String propsFile1Path, final String propsFile2Path,
+ final File jbossHome) {
+ return new CommandLineProducer() {
+ @Override
+ public AS7CommandLine get() {
+ return new AS7CommandLine(getCommandLine(jbossHome, propsFile1Path, propsFile2Path));
+ }
+ };
+ }
+
+ private CommandLineProducer getAs7CommandLine(final FakeServerProcess serverProcess) {
+ return new CommandLineProducer() {
+ @Override
+ public AS7CommandLine get() {
+ return new AS7CommandLine(serverProcess.processInfo);
+ }
+ };
+ }
+
+ private void testSysProps(File propsFile1, File propsFile2, File jbossHome, CommandLineProducer commandLine)
+ throws Exception {
PropertiesFileUpdate propsFile1Updater = new PropertiesFileUpdate(propsFile1.getPath());
propsFile1Updater.update("prop1", "delta");
propsFile1Updater.update("prop4", "epsilon");
- File propsFile2 = File.createTempFile("jboss2-", ".properties");
PropertiesFileUpdate propsFile2Updater = new PropertiesFileUpdate(propsFile1.getPath());
propsFile2Updater.update("prop2", "zeta");
propsFile2Updater.update("prop5", "eta");
- AS7CommandLine javaCommandLine = new AS7CommandLine(new String[] { //
- "/usr/java/default/bin/java", //
- "-D[Standalone]", //
- "-server", //
- "-Dprop1=alpha", //
- "-Dprop2=beta", //
- "-Dprop3=gamma", //
- "-jar", "/home/jboss/jboss-eap-6.0.0.ER6/jboss-modules.jar", //
- "-mp", "/home/jboss/jboss-eap-6.0.0.ER6/modules", //
- "-jaxpmodule", "javax.xml.jaxp-provider", //
- "org.jboss.as.standalone", //
- "-Djboss.home.dir=/home/jboss/jboss-eap-6.0.0.ER6", //
- "-Djboss.server.base.dir=/home/jboss/jboss-eap-6.0.0.ER6/standalone", //
- "-P", "file://" + propsFile1, //
- "--properties=file://" + propsFile2 //
- });
- Map<String,String> sysprops = javaCommandLine.getSystemProperties();
+ Map<String, String> sysprops = commandLine.get().getSystemProperties();
+
Assert.assertNotNull(sysprops);
Assert.assertEquals(sysprops.size(), 8);
Assert.assertEquals(sysprops.get("[Standalone]"), "");
@@ -51,8 +337,80 @@ public class AS7CommandLineTest {
Assert.assertEquals(sysprops.get("prop3"), "gamma");
Assert.assertEquals(sysprops.get("prop4"), "epsilon");
Assert.assertEquals(sysprops.get("prop5"), "eta");
- Assert.assertEquals(sysprops.get("jboss.home.dir"), "/home/jboss/jboss-eap-6.0.0.ER6");
- Assert.assertEquals(sysprops.get("jboss.server.base.dir"), "/home/jboss/jboss-eap-6.0.0.ER6/standalone");
+ Assert.assertEquals(sysprops.get("jboss.home.dir"), jbossHome.getAbsolutePath());
+ Assert.assertEquals(sysprops.get("jboss.server.base.dir"), new File(jbossHome, "standalone").getAbsolutePath());
+ }
+
+ private FakeServerProcess startFakeServer(File cwd, File jbossHome, String propsFile1Path, String propsFile2Path)
+ throws Exception {
+ //prepare the fake jboss-modules.jar
+ Class<?> mainClass = FakeServerProcess.class;
+ File jbossModulesJar = File.createTempFile("jboss-modules-fake", ".jar");
+
+ ShrinkWrap.create(JavaArchive.class).addClass(mainClass)
+ .setManifest(new StringAsset("Main-Class: " + mainClass.getName() + "\n")).as(ZipExporter.class)
+ .exportTo(jbossModulesJar, true);
+
+ String[] commandLine = getCommandLine(jbossModulesJar, jbossHome, propsFile1Path, propsFile2Path);
+
+ ProcessBuilder pb = new ProcessBuilder(commandLine);
+ Process process = pb.directory(cwd).start();
+
+ try {
+ int exitValue = process.exitValue();
+ String stdout = StreamUtil.slurp(new InputStreamReader(process.getInputStream()));
+ String stderr = StreamUtil.slurp(new InputStreamReader(process.getErrorStream()));
+
+ Assert
+ .fail("The fake jboss as server process has finished even though it should keep running. The exit value was "
+ + exitValue
+ + ". Stdout was:\n"
+ + stdout
+ + "\n\nStderr was:\n"
+ + stderr);
+ } catch (IllegalThreadStateException e) {
+ //expected
+ }
+
+ SystemInfo sysInfo = SystemInfoFactory.createSystemInfo();
+ List<ProcessInfo> processes = sysInfo.getAllProcesses();
+
+ for (ProcessInfo pi : processes) {
+ String[] cl = pi.getCommandLine();
+ if (Arrays.equals(cl, commandLine)) {
+ FakeServerProcess ret = new FakeServerProcess();
+ ret.fakeJBossModulesJar = jbossModulesJar;
+ ret.processInfo = pi;
+ return ret;
+ }
+ }
+
+ return null;
+ }
+
+ private String[] getCommandLine(File jbossHome, String propsFile1Path, String propsFile2Path) {
+ return getCommandLine(new File(jbossHome, "jboss-modules.jar"), jbossHome, propsFile1Path, propsFile2Path);
}
+ private String[] getCommandLine(File jbossModules, File jbossHome, String propsFile1Path, String propsFile2Path) {
+ return new String[] { //
+ "java", //
+ "-D[Standalone]", //
+ "-server", //
+ "-Dprop1=alpha", //
+ "-Dprop2=beta", //
+ "-Dprop3=gamma", //
+ "-jar", jbossModules.getAbsolutePath(), //
+ "-mp", new File(jbossHome, "modules").getAbsolutePath(), //
+ "-jaxpmodule", "javax.xml.jaxp-provider", //
+ "org.jboss.as.standalone", //
+ "-Djboss.home.dir=" + jbossHome.getAbsolutePath(), //
+ "-Djboss.server.base.dir=" + new File(jbossHome, "standalone").getAbsolutePath(), //
+ "-P", propsFile1Path, //
+ "--properties=" + propsFile2Path };
+ }
+
+ public static synchronized void main(String[] args) throws Exception {
+ AS7CommandLineTest.class.wait();
+ }
}