Support Apache Commons Daemon methods in XmlConfiguration (#5199)

* Support Apache Commons Daemon methods in XmlConfiguration so it can substitute for start.Main after a --dry-run

* + added --dry-run=parts to printout partial dry run
+ added --no-exec

Signed-off-by: Greg Wilkins <gregw@webtide.com>

* + updated for review feedback

Signed-off-by: Greg Wilkins <gregw@webtide.com>

* Feedback from review:

 + removed features other than --dry-run parts
 + added documentation
This commit is contained in:
Greg Wilkins 2020-09-02 23:40:05 +02:00 committed by GitHub
parent 5fef14019a
commit 820f2b9195
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 156 additions and 42 deletions

View File

@ -65,7 +65,7 @@ When executed `start.jar` performs the following actions:
3. Uses default behavior of `java.io.File` (Relative to `System.getProperty` ("user.dir") and then as absolute file system path).
* Loads any dependent modules (merges XXNK, library, and properties results with active command line).
* Builds out server classpath.
* Determines run mode:
* Determines run mode as one of:
** Shows informational command line options and exit.
** Executes Jetty normally, waits for Jetty to stop.
** Executes a forked JVM to run Jetty in, waits for forked JVM to exit.
@ -89,9 +89,36 @@ Lists the resolved configuration that will start Jetty.
* Server classpath
* Server XML configuration files
--dry-run::
Prints the resolved command line that `start.jar` should use to start a forked instance of Jetty.
Print the command line that the start.jar generates, then exit. This may be used to generate command lines when the start.ini includes -X or -D arguments:
....
$ java -jar start.jar --dry-run > jetty.sh
$ . jetty.sh
....
--dry-run=<parts>::
Print specific parts of the command line. The parts are a comma separated list of:
* "java" - the JVM to run
* "opts" - the JVM options (eg -D and -X flags)
* "path" - the JVM class path or JPMS modules options
* "main" - the main class to run
* "args" - the arguments passed to the main class
It is possible to decompose the start command:
....
$ OPTS=$(java -jar start.jar --dry-run=opts,path)
$ MAIN=$(java -jar start.jar --dry-run=main)
$ ARGS=$(java -jar start.jar --dry-run=args)
$ java $OPTS -Dextra=opt $MAIN $ARGS extra=arg
....
Alternatively to create an args file for java:
....
$ java -jar start.jar --dry-run=opts,path,main,args > /tmp/args
$ java @/tmp/args
....
--exec::
Starts a forked instance of Jetty.
Forces the start to use a forked instance of java to run Jetty.
Some modules include `--exec` in order to set java command line options.
Some start options, such as `--jpms` also imply `--exec`
--exec-properties=<filename>::
Assign a fixed name to the file used to transfer properties to the sub process.
This allows the generated properties file to be saved and reused.
@ -99,7 +126,7 @@ Without this option, a temporary file is used.
--commands=<filename>::
Instructs `start.jar` to use each line of the specified file as arguments on the command line.
===== Debugg and Start Logging
===== Debug and Start Logging
--debug::
Enables debugging output of the startup procedure.
@ -275,3 +302,25 @@ If you have a need for a shaded version of `start.jar` (such as for Gradle), you
<classifier>shaded</classifier>
</dependency>
....
==== Start.jar without exec or forking.
Some Jetty modules include the `--exec` option so that java command line options can be set.
Also some `start.jar` options (eg. `--jpms`) include an implicit `--exec`.
To start jetty without forking a new JVM instance from the start JVM, the `--dry-run` option can be used to generate a command line:
....
$ CMD=$(java -jar start.jar --dry-run)
$ $CMD
....
It is possible to decompose the start command so that it can be modified:
....
$ OPTS=$(java -jar start.jar --dry-run=opts,path)
$ MAIN=$(java -jar start.jar --dry-run=main)
$ ARGS=$(java -jar start.jar --dry-run=args)
$ java $OPTS -Dextra=opt $MAIN $ARGS extra=arg
....
Alternatively to create an args file for java:
....
$ java -jar start.jar --dry-run=opts,path,main,args > /tmp/args
$ java @/tmp/args
....

View File

@ -206,7 +206,7 @@ public class Main
StartLog.debug("%s - %s", invokedClass, invokedClass.getPackage().getImplementationVersion());
CommandLineBuilder cmd = args.getMainArgs(false);
CommandLineBuilder cmd = args.getMainArgs(StartArgs.ARG_PARTS);
String[] argArray = cmd.getArgs().toArray(new String[0]);
StartLog.debug("Command Line Args: %s", cmd.toString());
@ -415,7 +415,7 @@ public class Main
// Show Command Line to execute Jetty
if (args.isDryRun())
{
CommandLineBuilder cmd = args.getMainArgs(true);
CommandLineBuilder cmd = args.getMainArgs(args.getDryRunParts());
System.out.println(cmd.toString(StartLog.isDebugEnabled() ? " \\\n" : " "));
}
@ -454,7 +454,7 @@ public class Main
// execute Jetty in another JVM
if (args.isExec())
{
CommandLineBuilder cmd = args.getMainArgs(true);
CommandLineBuilder cmd = args.getMainArgs(StartArgs.ALL_PARTS);
cmd.debug();
ProcessBuilder pbuilder = new ProcessBuilder(cmd.getArgs());
StartLog.endStartLog();

View File

@ -57,6 +57,14 @@ import org.eclipse.jetty.util.ManifestUtils;
public class StartArgs
{
public static final String VERSION;
public static final Set<String> ALL_PARTS = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(
"java",
"opts",
"path",
"main",
"args")));
public static final Set<String> ARG_PARTS = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(
"args")));
static
{
@ -219,6 +227,7 @@ public class StartArgs
private boolean listConfig = false;
private boolean version = false;
private boolean dryRun = false;
private final Set<String> dryRunParts = new HashSet<>();
private boolean jpms = false;
private boolean createStartd = false;
private boolean updateIni = false;
@ -675,8 +684,11 @@ public class StartArgs
return jvmArgs;
}
public CommandLineBuilder getMainArgs(boolean addJavaInit) throws IOException
public CommandLineBuilder getMainArgs(Set<String> parts) throws IOException
{
if (parts.isEmpty())
parts = ALL_PARTS;
CommandLineBuilder cmd = new CommandLineBuilder();
// Special Stop/Shutdown properties
@ -684,10 +696,11 @@ public class StartArgs
ensureSystemPropertySet("STOP.KEY");
ensureSystemPropertySet("STOP.WAIT");
if (addJavaInit)
{
if (parts.contains("java"))
cmd.addRawArg(CommandLineBuilder.findJavaBin());
if (parts.contains("opts"))
{
cmd.addRawArg("-Djava.io.tmpdir=" + System.getProperty("java.io.tmpdir"));
cmd.addRawArg("-Djetty.home=" + baseHome.getHome());
cmd.addRawArg("-Djetty.base=" + baseHome.getBase());
@ -702,6 +715,7 @@ public class StartArgs
Prop p = processSystemProperty(key, value, null);
cmd.addRawArg("-D" + p.key + "=" + getProperties().expand(p.value));
}
else
{
@ -715,7 +729,10 @@ public class StartArgs
String value = System.getProperty(propKey);
cmd.addEqualsArg("-D" + propKey, value);
}
}
if (parts.contains("path"))
{
if (isJPMS())
{
Map<Boolean, List<File>> dirsAndFiles = StreamSupport.stream(classpath.spliterator(), false)
@ -764,52 +781,58 @@ public class StartArgs
cmd.addRawArg("--add-reads");
cmd.addRawArg(entry.getKey() + "=" + String.join(",", entry.getValue()));
}
cmd.addRawArg("--module");
cmd.addRawArg(getMainClassname());
}
else
{
cmd.addRawArg("-cp");
cmd.addRawArg(classpath.toString());
cmd.addRawArg(getMainClassname());
}
}
if (parts.contains("main"))
{
if (isJPMS())
cmd.addRawArg("--module");
cmd.addRawArg(getMainClassname());
}
// pass properties as args or as a file
if (dryRun && execProperties == null)
if (parts.contains("args"))
{
for (Prop p : properties)
if (dryRun && execProperties == null)
{
cmd.addRawArg(CommandLineBuilder.quote(p.key) + "=" + CommandLineBuilder.quote(p.value));
for (Prop p : properties)
{
cmd.addRawArg(CommandLineBuilder.quote(p.key) + "=" + CommandLineBuilder.quote(p.value));
}
}
}
else if (properties.size() > 0)
{
Path propPath;
if (execProperties == null)
else if (properties.size() > 0)
{
propPath = Files.createTempFile("start_", ".properties");
propPath.toFile().deleteOnExit();
}
else
propPath = new File(execProperties).toPath();
Path propPath;
if (execProperties == null)
{
propPath = Files.createTempFile("start_", ".properties");
propPath.toFile().deleteOnExit();
}
else
propPath = new File(execProperties).toPath();
try (OutputStream out = Files.newOutputStream(propPath))
try (OutputStream out = Files.newOutputStream(propPath))
{
properties.store(out, "start.jar properties");
}
cmd.addRawArg(propPath.toAbsolutePath().toString());
}
for (Path xml : xmls)
{
properties.store(out, "start.jar properties");
cmd.addRawArg(xml.toAbsolutePath().toString());
}
cmd.addRawArg(propPath.toAbsolutePath().toString());
}
for (Path xml : xmls)
{
cmd.addRawArg(xml.toAbsolutePath().toString());
}
for (Path propertyFile : propertyFiles)
{
cmd.addRawArg(propertyFile.toAbsolutePath().toString());
for (Path propertyFile : propertyFiles)
{
cmd.addRawArg(propertyFile.toAbsolutePath().toString());
}
}
return cmd;
@ -935,6 +958,11 @@ public class StartArgs
return dryRun;
}
public Set<String> getDryRunParts()
{
return dryRunParts;
}
public boolean isExec()
{
return exec;
@ -1152,6 +1180,21 @@ public class StartArgs
return;
}
if (arg.startsWith("--dry-run="))
{
int colon = arg.indexOf('=');
for (String part : arg.substring(colon + 1).split(","))
{
if (!ALL_PARTS.contains(part))
throw new UsageException(UsageException.ERR_BAD_ARG, "Unrecognized --dry-run=\"%s\" in %s", part, source);
dryRunParts.add(part);
}
dryRun = true;
run = false;
return;
}
// Enable forked execution of Jetty server
if ("--exec".equals(arg))
{

View File

@ -28,7 +28,30 @@ Command Line Options:
--dry-run Print the command line that the start.jar generates,
then exit. This may be used to generate command lines
when the start.ini includes -X or -D arguments.
when the start.ini includes -X or -D arguments:
java -jar start.jar --dry-run > jetty.sh
. jetty.sh
--dry-run=parts Print specific parts of the command line. The parts
are a comma separated list of
o "java" - the JVM to run
o "opts" - the JVM options (eg -D and -X flags)
o "path" - the JVM class path or JPMS modules options
o "main" - the main class to run
o "args" - the arguments passed to the main class
It is possible to decompose the start command:
OPTS=$(java -jar start.jar --dry-run=opts,path)
MAIN=$(java -jar start.jar --dry-run=main)
ARGS=$(java -jar start.jar --dry-run=args)
java $OPTS -Dextra=opt $MAIN $ARGS extra=arg
Alternatively to create an args file for java:
java -jar start.jar --dry-run=opts,path,main,args > /tmp/args
java @/tmp/args
--exec Run the generated command line (see --dry-run) in
a sub process. This can be used when start.ini
@ -59,7 +82,6 @@ Debug and Start Logging:
issues where the jetty specific logger has not yet kicked
in due to startup configuration errors.
Module Management:
------------------

View File

@ -193,7 +193,7 @@ public class MainTest
assertThat("jetty.home", baseHome.getHome(), is(homePath.toString()));
assertThat("jetty.base", baseHome.getBase(), is(homePath.toString()));
CommandLineBuilder commandLineBuilder = args.getMainArgs(true);
CommandLineBuilder commandLineBuilder = args.getMainArgs(StartArgs.ALL_PARTS);
String commandLine = commandLineBuilder.toString("\n");
String expectedExpansion = String.format("-Xloggc:%s/logs/gc-%s.log",
baseHome.getBase(), System.getProperty("java.version")