diff --git a/README.md b/README.md
index 7d004fe..9b13cf3 100644
--- a/README.md
+++ b/README.md
@@ -1,14 +1,14 @@
Jetty Daemon Runner
===================
-Ever wanted a servlet engine in a single runnable JAR that could
-correctly daemonize and run WAR from a command line?
+Ever wanted a servlet engine in a single runnable JAR that could
+correctly daemonize and run WAR from a command line?
Jetty Daemon Runner improves over existing jetty-runner with JVM daemonization.
It's packaged as a single runnable jar you can use on Unix platforms
supported by Akuma/JNA.
-[Download latest release (0.5)](https://github.com/vnesek/jetty-daemon-runner/releases/tag/v0.5)
+[Download latest release (0.6)](https://github.com/vnesek/jetty-daemon-runner/releases/tag/v0.6)
Usage
-----
@@ -16,19 +16,19 @@ Usage
* Start Jetty at port 8080 serving WAR at / as a daemon in background
```sh
- java -jar jetty-daemon.jar --start --pid some.pid some.war
+ java -jar jetty-daemon.jar --start --pid some.pid some.war
```
* Stop Jetty using pid file
```sh
- java -jar jetty-daemon.jar --stop --pid some.pid
+ java -jar jetty-daemon.jar --stop --pid some.pid
```
Features
--------
* Supports Java 8 on Unix
-* Start/stop/restart service
+* Start/stop/restart service
* Detaching from terminal (no need for nohup, java service wrapper...)
* All dependencies packaged as a single runnable JAR
* BSD style license
@@ -44,7 +44,7 @@ Addition daemon server opts:
--pid file - PID file
--chdir dir - change running directory
-Usage: java [-Djetty.home=dir] -jar jetty-runner.jar [--help|--version] [ server opts] [[ context opts] context ...]
+Usage: java [-Djetty.home=dir] -jar jetty-runner.jar [--help|--version] [ server opts] [[ context opts] context ...]
Server opts:
--version - display version and exit
--log file - request log filename (with optional 'yyyy_mm_dd' wildcard
@@ -67,7 +67,7 @@ References
----------
* [Akuma](http://akuma.kohsuke.org/) for JVM daemonization
-* [JNA](https://github.com/java-native-access/jna) for native code access
+* [JNA](https://github.com/java-native-access/jna) for native code access
* [Jetty Runner](http://www.eclipse.org/jetty/documentation/current/runner.html) favorite servlet engine
Author Contact and Support
diff --git a/pom.xml b/pom.xml
index 3e55384..91d2c4f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
4.0.0
com.nmote.jetty
jetty-daemon-runner
- 0.5
+ 0.6
Jetty Daemon Runner
Jetty daemon runner for Unix
https://github.com/vnesek/jetty-daemon-runner
@@ -46,12 +46,12 @@
org.eclipse.jetty
jetty-runner
- 9.3.5.v20151012
+ 9.3.8.v20160314
net.java.dev.jna
jna
- 4.2.1
+ 4.2.2
diff --git a/src/main/java/com/nmote/jetty/daemon/JettyRunner.java b/src/main/java/com/nmote/jetty/daemon/JettyRunner.java
index f70afac..843cee0 100644
--- a/src/main/java/com/nmote/jetty/daemon/JettyRunner.java
+++ b/src/main/java/com/nmote/jetty/daemon/JettyRunner.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) Nmote Ltd. 2003-2014. All rights reserved.
+ * Copyright (c) Nmote Ltd. 2003-2014. All rights reserved.
* See LICENSE doc in a root of project folder for additional information.
*/
@@ -26,216 +26,216 @@
public class JettyRunner {
- private static class RunnerInternal extends Runner {
-
- @Override
- public void usage(String error) {
- System.err.println("Addition daemon server opts:");
- System.err.println(" --start - detach from a terminal and run in background");
- System.err.println(" --stop - stop running server by pid");
- System.err.println(" --restart - restarts server by pid");
- System.err.println(" --pid file - PID file");
- System.err.println(" --chdir dir - change running directory");
- System.err.println();
- super.usage(error);
- }
-
- @Override
- public void version() {
- System.err.println("com.nmote.jetty.daemon.JettyRunner: 0.5.0");
- super.version();
- }
-
- void serverJoin() throws InterruptedException {
- _server.join();
- }
-
- void serverStart() throws Exception {
- _server.start();
- }
- }
-
- public static void main(String[] javaArgs) throws Exception {
- // All command line arguments, including VM ones
- JavaVMArguments args = JavaVMArguments.current();
-
- // Check if args are correctly set
- getArg("--chdir", args);
-
- String pidFile = getArg("--pid", args);
- Path pidPath = pidFile != null ? Paths.get(pidFile) : null;
-
- // What should we do
- boolean doStop = hasArg("--stop", args);
- boolean doStart = hasArg("--start", args);
- if (hasArg("--restart", args)) {
- doStart = true;
- doStop = true;
- }
-
- // Read PID from file
- int pid = readPid(pidPath);
-
- // Stop running server
- if (doStop && pid != -1) {
- stopServer(pidPath, pid);
- if (!doStart) {
- System.exit(0);
- }
- pid = -1;
- }
-
- if (doStart && pid != -1) {
- System.exit(3);
- }
-
- // Daemonize
- Daemon d = new Daemon();
- if (!d.isDaemonized() && doStart) {
- d.daemonize(args);
- System.exit(0);
- }
-
- if (d.isDaemonized()) {
- // Customized Daemon::init procedure
- LIBC.setsid();
-
- // Save PID to file
- writePid(pidPath, LIBC.getpid());
-
- try {
- // Change running directory
- String chDir = getArg("--chdir", args);
- if (chDir != null) {
- LIBC.chdir(chDir);
- }
-
- // Save out,in,err. Jetty could redirect'em
- Closeable[] streams = { System.out, System.err, System.in };
-
- RunnerInternal runner = new RunnerInternal();
- runner.configure(jettyCleanedArgs(javaArgs));
- runner.serverStart();
-
- // Close out,in,err
- for (Closeable c : streams) {
- c.close();
- }
-
- // Wait for server to shutdown
- runner.serverJoin();
- } finally {
- // Delete PID file
- if (pidFile != null) {
- Files.delete(Paths.get(pidFile));
- }
- }
- } else {
- // Run in foreground
- RunnerInternal runner = new RunnerInternal();
- if (hasArg("--help", args)) {
- runner.usage(null);
- } else if (hasArg("--version", args)) {
- runner.version();
- } else {
- runner.configure(jettyCleanedArgs(javaArgs));
- runner.run();
- }
- }
- }
-
- protected static String getArg(String arg, Iterable args) {
- Iterator i = args.iterator();
- while (i.hasNext()) {
- String a = i.next();
- if (arg.equals(a)) {
- try {
- String value = i.next();
- if (value.startsWith("--")) {
- throw new NoSuchElementException();
- }
- return value;
- } catch (NoSuchElementException e) {
- System.err.println("ERROR: Missing argument for " + arg);
- System.exit(1);
- }
- }
- }
- return null;
- }
-
- protected static boolean hasArg(String arg, Collection args) {
- return args.contains(arg);
- }
-
- protected static String[] jettyCleanedArgs(String[] javaArgs) {
- ArrayList jettyArgs = new ArrayList(Arrays.asList(javaArgs));
- removeArg("--pid", jettyArgs, true);
- removeArg("--chdir", jettyArgs, true);
- removeArg("--start", jettyArgs, false);
- removeArg("--stop", jettyArgs, false);
- removeArg("--restart", jettyArgs, false);
- return jettyArgs.toArray(new String[jettyArgs.size()]);
- }
-
- protected static void removeArg(String arg, Iterable args, boolean hasValue) {
- Iterator i = args.iterator();
- while (i.hasNext()) {
- String a = i.next();
- if (arg.equals(a)) {
- i.remove();
- if (hasValue) {
- i.next();
- i.remove();
- }
- }
- }
- }
-
- private static int readPid(Path pidPath) throws IOException {
- if (pidPath != null) {
- if (Files.exists(pidPath)) {
- return Integer.parseInt(Files.readAllLines(pidPath).get(0));
- }
- }
- return -1;
- }
-
- private static void stopServer(Path pidPath, int pid) throws IOException, InterruptedException {
- // Wait up-to 10 seconds for exit (deletion of pid file)
- System.err.print("INFO: Stopping " + pid);
- if (LIBC.kill(pid, 1) == 0 && !waitTillDeleted(pidPath, 100)) {
- // Send SIGKILL
- System.err.println("\nERROR: Stop failed, sending SIGKILL " + pid);
- LIBC.kill(pid, 9);
- Files.delete(pidPath);
- }
-
- if (Files.exists(pidPath)) {
- System.err.println(String.format( //
- "\nERROR: Stop failed, check if process %d is running and delete %s", pid, pidPath));
- System.exit(2);
- }
-
- System.err.println("\nINFO: Stopped");
- }
-
- private static boolean waitTillDeleted(Path pidPath, int max) throws InterruptedException {
- for (int i = 0; i < max; ++i) {
- Thread.sleep(100);
- if (!Files.exists(pidPath)) {
- return true;
- }
- if ((i % 10) == 9) {
- System.err.print('.');
- }
- }
- return false;
- }
-
- private static void writePid(Path pidPath, int pid) throws IOException {
- if (pidPath != null) {
- Files.write(pidPath, Collections.singleton(Integer.toString(pid)));
- }
- }
+ private static class RunnerInternal extends Runner {
+
+ @Override
+ public void usage(String error) {
+ System.err.println("Addition daemon server opts:");
+ System.err.println(" --start - detach from a terminal and run in background");
+ System.err.println(" --stop - stop running server by pid");
+ System.err.println(" --restart - restarts server by pid");
+ System.err.println(" --pid file - PID file");
+ System.err.println(" --chdir dir - change running directory");
+ System.err.println();
+ super.usage(error);
+ }
+
+ @Override
+ public void version() {
+ System.err.println("com.nmote.jetty.daemon.JettyRunner: 0.5.0");
+ super.version();
+ }
+
+ void serverJoin() throws InterruptedException {
+ _server.join();
+ }
+
+ void serverStart() throws Exception {
+ _server.start();
+ }
+ }
+
+ public static void main(String[] javaArgs) throws Exception {
+ // All command line arguments, including VM ones
+ JavaVMArguments args = JavaVMArguments.current();
+
+ // Check if args are correctly set
+ getArg("--chdir", args);
+
+ String pidFile = getArg("--pid", args);
+ Path pidPath = pidFile != null ? Paths.get(pidFile) : null;
+
+ // What should we do
+ boolean doStop = hasArg("--stop", args);
+ boolean doStart = hasArg("--start", args);
+ if (hasArg("--restart", args)) {
+ doStart = true;
+ doStop = true;
+ }
+
+ // Read PID from file
+ int pid = readPid(pidPath);
+
+ // Change running directory
+ String chDir = getArg("--chdir", args);
+ if (chDir != null) {
+ LIBC.chdir(chDir);
+ }
+
+ Daemon d = new Daemon();
+ if (!d.isDaemonized()) {
+ // Stop running server
+ if (doStop && pid != -1) {
+ stopServer(pidPath, pid);
+ pid = -1;
+ }
+
+ if (doStart && pid != -1) {
+ System.err.println(String.format("ERROR: Can't start, process %d already running", pid));
+ System.exit(3);
+ }
+
+ // Daemonize me
+ if (doStart) {
+ d.daemonize(args);
+ System.exit(0);
+ }
+
+ if (!doStart && !doStop) {
+ // Run in foreground
+ RunnerInternal runner = new RunnerInternal();
+ if (hasArg("--help", args)) {
+ runner.usage(null);
+ } else if (hasArg("--version", args)) {
+ runner.version();
+ } else {
+ runner.configure(jettyCleanedArgs(javaArgs));
+ runner.run();
+ }
+ }
+ } else {
+ // Customized Daemon::init procedure
+ LIBC.setsid();
+
+ // Save PID to file
+ writePid(pidPath, LIBC.getpid());
+
+ try {
+ // Save out,in,err. Jetty could redirect'em
+ Closeable[] streams = { System.out, System.err, System.in };
+
+ RunnerInternal runner = new RunnerInternal();
+ runner.configure(jettyCleanedArgs(javaArgs));
+ runner.serverStart();
+
+ // Close out,in,err
+ for (Closeable c : streams) {
+ c.close();
+ }
+
+ // Wait for server to shutdown
+ runner.serverJoin();
+ } finally {
+ // Delete PID file
+ if (pidFile != null) {
+ Files.delete(Paths.get(pidFile));
+ }
+ }
+ }
+ }
+
+ protected static String getArg(String arg, Iterable args) {
+ Iterator i = args.iterator();
+ while (i.hasNext()) {
+ String a = i.next();
+ if (arg.equals(a)) {
+ try {
+ String value = i.next();
+ if (value.startsWith("--")) {
+ throw new NoSuchElementException();
+ }
+ return value;
+ } catch (NoSuchElementException e) {
+ System.err.println("ERROR: Missing argument for " + arg);
+ System.exit(1);
+ }
+ }
+ }
+ return null;
+ }
+
+ protected static boolean hasArg(String arg, Collection args) {
+ return args.contains(arg);
+ }
+
+ protected static String[] jettyCleanedArgs(String[] javaArgs) {
+ ArrayList jettyArgs = new ArrayList(Arrays.asList(javaArgs));
+ removeArg("--pid", jettyArgs, true);
+ removeArg("--chdir", jettyArgs, true);
+ removeArg("--start", jettyArgs, false);
+ removeArg("--stop", jettyArgs, false);
+ removeArg("--restart", jettyArgs, false);
+ return jettyArgs.toArray(new String[jettyArgs.size()]);
+ }
+
+ protected static void removeArg(String arg, Iterable args, boolean hasValue) {
+ Iterator i = args.iterator();
+ while (i.hasNext()) {
+ String a = i.next();
+ if (arg.equals(a)) {
+ i.remove();
+ if (hasValue) {
+ i.next();
+ i.remove();
+ }
+ }
+ }
+ }
+
+ private static int readPid(Path pidPath) throws IOException {
+ if (pidPath != null) {
+ if (Files.exists(pidPath)) {
+ return Integer.parseInt(Files.readAllLines(pidPath).get(0));
+ }
+ }
+ return -1;
+ }
+
+ private static void stopServer(Path pidPath, int pid) throws IOException, InterruptedException {
+ // Wait up-to 10 seconds for exit (deletion of pid file)
+ System.err.print("INFO: Stopping " + pid);
+ if (LIBC.kill(pid, 1) == 0 && !waitTillDeleted(pidPath, 100)) {
+ // Send SIGKILL
+ System.err.println("\nERROR: Stop failed, sending SIGKILL " + pid);
+ LIBC.kill(pid, 9);
+ Files.delete(pidPath);
+ }
+
+ if (Files.exists(pidPath)) {
+ System.err.println(String.format( //
+ "\nERROR: Stop failed, check if process %d is running and delete %s", pid, pidPath));
+ System.exit(2);
+ }
+
+ System.err.println("\nINFO: Stopped");
+ }
+
+ private static boolean waitTillDeleted(Path pidPath, int max) throws InterruptedException {
+ for (int i = 0; i < max; ++i) {
+ Thread.sleep(100);
+ if (!Files.exists(pidPath)) {
+ return true;
+ }
+ if ((i % 10) == 9) {
+ System.err.print('.');
+ }
+ }
+ return false;
+ }
+
+ private static void writePid(Path pidPath, int pid) throws IOException {
+ if (pidPath != null) {
+ Files.write(pidPath, Collections.singleton(Integer.toString(pid)));
+ }
+ }
}