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 | 46 + 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(+), 69 deletions(-)
New commits: commit 2910d155e509b6ebccdc9483a70b2910bdf0133c Author: Lukas Krejci lkrejci@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.
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 bee2bbb..75d5b51 100644 --- a/modules/plugins/jboss-as-7/pom.xml +++ b/modules/plugins/jboss-as-7/pom.xml @@ -108,6 +108,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>
@@ -166,9 +174,47 @@ --> <exclude>org/rhq/modules/plugins/jbossas7/itest/**</exclude> </excludes> + <!-- This is where the antrun below puts the sigar native libs --> + <argLine>${jacoco.unit-test.args} -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 02084a9..bb8adcd 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 @@ -23,48 +23,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]"), ""); @@ -73,8 +359,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(); + } }
rhq-commits@lists.fedorahosted.org