diff --git a/nailgun-examples/src/main/java/com/facebook/nailgun/examples/DumpAll.java b/nailgun-examples/src/main/java/com/facebook/nailgun/examples/DumpAll.java index 24e1f5d7..5e696819 100644 --- a/nailgun-examples/src/main/java/com/facebook/nailgun/examples/DumpAll.java +++ b/nailgun-examples/src/main/java/com/facebook/nailgun/examples/DumpAll.java @@ -18,6 +18,8 @@ package com.facebook.nailgun.examples; import com.facebook.nailgun.NGContext; + +import java.io.PrintStream; import java.util.TreeSet; /** @@ -28,24 +30,26 @@ public class DumpAll { public static void nailMain(NGContext context) { - context.out.println(); - context.out.println(" context.getCommand(): " + context.getCommand()); - context.out.println(" context.getInetAddress(): " + context.getInetAddress()); - context.out.println(" context.getPort(): " + context.getPort()); - context.out.println("context.getWorkingDirectory(): " + context.getWorkingDirectory()); - context.out.println(" context.getFileSeparator(): " + context.getFileSeparator()); - context.out.println(" context.getPathSeparator(): " + context.getPathSeparator()); - - context.out.println("\ncontext.getArgs():"); + PrintStream out = context.getOut(); + out.println(); + out.println(" context.getCommand(): " + context.getCommand()); + out.println(" context.getInetAddress(): " + context.getInetAddress()); + out.println(" context.getPort(): " + context.getPort()); + out.println("context.getWorkingDirectory(): " + context.getWorkingDirectory()); + out.println(" context.getFileSeparator(): " + context.getFileSeparator()); + out.println(" context.getPathSeparator(): " + context.getPathSeparator()); + + out.println("\ncontext.getArgs():"); for (int i = 0; i < context.getArgs().length; ++i) { - context.out.println(" args[" + i + "]=" + context.getArgs()[i]); + out.println(" args[" + i + "]=" + context.getArgs()[i]); } - context.out.println("\ncontext.getEnv():"); + out.println("\ncontext.getEnv():"); TreeSet keys = new TreeSet(context.getEnv().keySet()); for (Object okey : keys) { String key = (String) okey; - context.out.println(" env[\"" + key + "\"]=" + context.getEnv().getProperty(key)); + out.println(" env[\"" + key + "\"]=" + context.getEnv().getProperty(key)); } + out.flush(); } } diff --git a/nailgun-examples/src/main/java/com/facebook/nailgun/examples/Hash.java b/nailgun-examples/src/main/java/com/facebook/nailgun/examples/Hash.java index 568e0440..be52e2f5 100644 --- a/nailgun-examples/src/main/java/com/facebook/nailgun/examples/Hash.java +++ b/nailgun-examples/src/main/java/com/facebook/nailgun/examples/Hash.java @@ -83,8 +83,9 @@ public static void nailMain(NGContext context) // display available algorithms Set algs = getCryptoImpls("MessageDigest"); for (Object alg : algs) { - context.out.println(alg); + context.getOut().println(alg); } + context.getOut().flush(); return; } @@ -92,7 +93,7 @@ public static void nailMain(NGContext context) MessageDigest md = MessageDigest.getInstance(args[0]); byte[] b = new byte[1024]; - int bytesRead = context.in.read(b); + int bytesRead = context.getIn().read(b); while (bytesRead != -1) { md.update(b, 0, bytesRead); bytesRead = System.in.read(b); @@ -105,6 +106,7 @@ public static void nailMain(NGContext context) buf.append(HEXCHARS[(result[i] >> 4) & 0x0f]); buf.append(HEXCHARS[result[i] & 0x0f]); } - context.out.println(buf); + context.getOut().println(buf); + context.getOut().flush(); } } diff --git a/nailgun-examples/src/main/java/com/facebook/nailgun/examples/Heartbeat.java b/nailgun-examples/src/main/java/com/facebook/nailgun/examples/Heartbeat.java index 92b4a5f9..545c78b9 100644 --- a/nailgun-examples/src/main/java/com/facebook/nailgun/examples/Heartbeat.java +++ b/nailgun-examples/src/main/java/com/facebook/nailgun/examples/Heartbeat.java @@ -47,7 +47,7 @@ public static void nailMain(final NGContext context) { } }); - context.addHeartbeatListener(() -> context.out.print("H")); + context.addHeartbeatListener(() -> context.getOut().print("H")); synchronized (lock) { if (!shutdown.get()) { diff --git a/nailgun-examples/src/main/java/com/facebook/nailgun/examples/Prompt.java b/nailgun-examples/src/main/java/com/facebook/nailgun/examples/Prompt.java index 2dc7b1af..101f220d 100644 --- a/nailgun-examples/src/main/java/com/facebook/nailgun/examples/Prompt.java +++ b/nailgun-examples/src/main/java/com/facebook/nailgun/examples/Prompt.java @@ -32,7 +32,8 @@ public static void nailMain(NGContext context) { if (result == null) { context.exit(1); } else { - context.out.println(result); + context.getOut().println(result); + context.getOut().flush(); } } } diff --git a/nailgun-examples/src/main/java/com/facebook/nailgun/examples/Stack.java b/nailgun-examples/src/main/java/com/facebook/nailgun/examples/Stack.java index 7d0946b8..9f3f2ab5 100644 --- a/nailgun-examples/src/main/java/com/facebook/nailgun/examples/Stack.java +++ b/nailgun-examples/src/main/java/com/facebook/nailgun/examples/Stack.java @@ -66,10 +66,11 @@ public static void nailMain(NGContext context) throws InterruptedException { sharedStack.wait(); } if (sharedStack.size() > 0) { - context.out.println(sharedStack.pop()); + context.getOut().println(sharedStack.pop()); exitCode = 0; } } + context.getOut().flush(); context.exit(exitCode); return; } diff --git a/nailgun-server/src/main/java/com/facebook/nailgun/NGClientListener.java b/nailgun-server/src/main/java/com/facebook/nailgun/NGClientListener.java index d0be5d4a..0baeb71c 100644 --- a/nailgun-server/src/main/java/com/facebook/nailgun/NGClientListener.java +++ b/nailgun-server/src/main/java/com/facebook/nailgun/NGClientListener.java @@ -16,6 +16,7 @@ package com.facebook.nailgun; +@FunctionalInterface public interface NGClientListener { /** diff --git a/nailgun-server/src/main/java/com/facebook/nailgun/NGCommunicator.java b/nailgun-server/src/main/java/com/facebook/nailgun/NGCommunicator.java index 8038a1c3..c0d061a9 100644 --- a/nailgun-server/src/main/java/com/facebook/nailgun/NGCommunicator.java +++ b/nailgun-server/src/main/java/com/facebook/nailgun/NGCommunicator.java @@ -17,7 +17,6 @@ package com.facebook.nailgun; import java.io.ByteArrayInputStream; -import java.io.Closeable; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.EOFException; @@ -48,7 +47,7 @@ * using underlying socket streams. Also handles client disconnect events based on client * heartbeats. */ -public class NGCommunicator implements Closeable { +public class NGCommunicator implements AutoCloseable { private static final Logger LOG = Logger.getLogger(NGCommunicator.class.getName()); private final ExecutorService orchestratorExecutor; diff --git a/nailgun-server/src/main/java/com/facebook/nailgun/NGConstants.java b/nailgun-server/src/main/java/com/facebook/nailgun/NGConstants.java index ececaffa..ef4a5558 100644 --- a/nailgun-server/src/main/java/com/facebook/nailgun/NGConstants.java +++ b/nailgun-server/src/main/java/com/facebook/nailgun/NGConstants.java @@ -17,8 +17,12 @@ package com.facebook.nailgun; +import java.io.File; import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; import java.util.Properties; +import java.util.logging.Logger; /** * Just a simple holder for various NailGun-related contants. @@ -27,6 +31,8 @@ */ public class NGConstants { + private static final Logger LOG = Logger.getLogger(NGConstants.class.getName()); + /** The default NailGun port (2113) */ public static final int DEFAULT_PORT = 2113; /** The exit code sent to clients if nail completed successfully */ @@ -63,9 +69,6 @@ public class NGConstants { /** Chunk type marker for heartbeats sent to let the server know the client is still alive. */ public static final byte CHUNKTYPE_HEARTBEAT = 'H'; - /** Server version number */ - public static final String VERSION = getVersion(); - /** Expected interval between heartbeats in milliseconds. */ public static final short HEARTBEAT_INTERVAL_MILLIS = 1000; @@ -78,17 +81,37 @@ public class NGConstants { /** Maximum chunk len sent from client. */ public static final short MAXIMUM_CHUNK_LENGTH = 2048; + private static String VERSION = null; + /** Loads the version number from a file generated by Maven. */ - private static String getVersion() { - Properties props = new Properties(); - try (InputStream is = - NGConstants.class.getResourceAsStream( - "/META-INF/maven/com.facebook/nailgun-server/pom.properties")) { - props.load(is); - } catch (Throwable e) { - // In static initialization context, outputting or logging an exception is dangerous - // It smells bad, but let's ignore it + public static String getVersion() throws MalformedURLException { + if (VERSION == null) { + Properties props = new Properties(); + URL url = + NGConstants.class.getResource( + "META-INF/maven/com.facebook/nailgun-server/pom.properties"); + if (url == null) { + File file = new File("target/maven-archiver/pom.properties"); + if (file.isFile()) { + url = file.toURI().toURL(); + } + } + if (url == null) { + File file = new File("nailgun-server/target/maven-archiver/pom.properties"); + if (file.isFile()) { + url = file.toURI().toURL(); + } + } + LOG.info("get version info from " + url); + try (InputStream is = url.openStream()) { + props.load(is); + } catch (Throwable e) { + // In static initialization context, outputting or logging an exception is dangerous + // It smells bad, but let's ignore it + } + VERSION = + props.getProperty("version", System.getProperty("nailgun.server.version", "[UNKNOWN]")); } - return props.getProperty("version", System.getProperty("nailgun.server.version", "[UNKNOWN]")); + return VERSION; } } diff --git a/nailgun-server/src/main/java/com/facebook/nailgun/NGContext.java b/nailgun-server/src/main/java/com/facebook/nailgun/NGContext.java index b723207b..aa058822 100644 --- a/nailgun-server/src/main/java/com/facebook/nailgun/NGContext.java +++ b/nailgun-server/src/main/java/com/facebook/nailgun/NGContext.java @@ -63,18 +63,22 @@ public class NGContext { private String workingDirectory = null; /** The client's stdin */ - public InputStream in = null; + private InputStream in = null; /** The client's stdout */ - public PrintStream out = null; + private PrintStream out = null; /** The client's stderr */ - public PrintStream err = null; + private PrintStream err = null; private NGCommunicator communicator = null; /** Creates a new, empty NGContext */ - public NGContext() {} + public NGContext(InputStream in, PrintStream out, PrintStream err) { + setIn(in); + setOut(out); + setErr(err); + } public void setCommunicator(NGCommunicator comm) { this.communicator = comm; @@ -123,7 +127,7 @@ public String getWorkingDirectory() { * @param in The {@link InputStream} to use as stdin for the current nail. This should be an * InputStream that ultimately reads from {@link NGInputStream}. */ - public void setIn(InputStream in) { + private void setIn(InputStream in) { this.in = in; if (!(System.in instanceof ThreadLocalInputStream)) { throw new IllegalStateException("System.in should be set by nailgun."); @@ -138,7 +142,7 @@ public void setIn(InputStream in) { * @param out The {@link PrintStream} to use as stdout for the current nail. This should be a * PrintStream that ultimately writes to {@link NGOutputStream}. */ - public void setOut(PrintStream out) { + private void setOut(PrintStream out) { this.out = out; if (!(System.out instanceof ThreadLocalPrintStream)) { throw new IllegalStateException("System.out should be set by nailgun."); @@ -153,7 +157,7 @@ public void setOut(PrintStream out) { * @param err The {@link PrintStream} to use as stderr for the current nail. This should be a * PrintStream that ultimately writes to {@link NGOutputStream}. */ - public void setErr(PrintStream err) { + private void setErr(PrintStream err) { this.err = err; if (!(System.err instanceof ThreadLocalPrintStream)) { throw new IllegalStateException("System.err should be set by nailgun."); @@ -162,6 +166,18 @@ public void setErr(PrintStream err) { tls.init(err); } + public InputStream getIn() { + return in; + } + + public PrintStream getOut() { + return out; + } + + public PrintStream getErr() { + return err; + } + void setEnv(Properties remoteEnvironment) { this.remoteEnvironment = remoteEnvironment; } diff --git a/nailgun-server/src/main/java/com/facebook/nailgun/NGHeartbeatListener.java b/nailgun-server/src/main/java/com/facebook/nailgun/NGHeartbeatListener.java index 512986cc..0acbe238 100644 --- a/nailgun-server/src/main/java/com/facebook/nailgun/NGHeartbeatListener.java +++ b/nailgun-server/src/main/java/com/facebook/nailgun/NGHeartbeatListener.java @@ -16,6 +16,7 @@ package com.facebook.nailgun; +@FunctionalInterface public interface NGHeartbeatListener { /** diff --git a/nailgun-server/src/main/java/com/facebook/nailgun/NGInputStream.java b/nailgun-server/src/main/java/com/facebook/nailgun/NGInputStream.java index c7ebb9fd..ca97c1aa 100644 --- a/nailgun-server/src/main/java/com/facebook/nailgun/NGInputStream.java +++ b/nailgun-server/src/main/java/com/facebook/nailgun/NGInputStream.java @@ -51,6 +51,7 @@ public boolean markSupported() { } /** @see java.io.InputStream#read() */ + @Override public int read() throws IOException { // have to synchronize all one byte reads to be able to reuse internal buffer and not // recreate new buffer on heap each time @@ -60,11 +61,13 @@ public int read() throws IOException { } /** @see java.io.InputStream#read(byte[]) */ + @Override public int read(byte[] b) throws IOException { return read(b, 0, b.length); } /** @see java.io.InputStream#read(byte[], int, int) */ + @Override public int read(byte[] b, int offset, int length) throws IOException { try { return communicator.receive(b, offset, length); diff --git a/nailgun-server/src/main/java/com/facebook/nailgun/NGServer.java b/nailgun-server/src/main/java/com/facebook/nailgun/NGServer.java index 0bacb67d..10b86334 100644 --- a/nailgun-server/src/main/java/com/facebook/nailgun/NGServer.java +++ b/nailgun-server/src/main/java/com/facebook/nailgun/NGServer.java @@ -372,7 +372,7 @@ public void run() { // test_ng.py on *nix relies on reading this line from stdout to start connecting to server. out.println( "NGServer " - + NGConstants.VERSION + + NGConstants.getVersion() + " started on " + listeningAddress.toString() + portDescription diff --git a/nailgun-server/src/main/java/com/facebook/nailgun/NGSession.java b/nailgun-server/src/main/java/com/facebook/nailgun/NGSession.java index 8ac4d3c6..107aaf3c 100644 --- a/nailgun-server/src/main/java/com/facebook/nailgun/NGSession.java +++ b/nailgun-server/src/main/java/com/facebook/nailgun/NGSession.java @@ -38,7 +38,7 @@ public class NGSession extends Thread { @FunctionalInterface - public interface CommnunicatorCreator { + public static interface CommnunicatorCreator { NGCommunicator get(Socket socket) throws IOException; } @@ -281,11 +281,8 @@ private void runImpl(NGCommunicator comm, Socket socket) { } else { try { mainMethod = cmdclass.getMethod("nailMain", nailMainSignature); - NGContext context = new NGContext(); + NGContext context = new NGContext(in, out, err); context.setArgs(cmdlineArgs); - context.in = in; - context.out = out; - context.err = err; context.setCommand(cmdContext.getCommand()); context.setNGServer(server); context.setCommunicator(comm); @@ -301,8 +298,11 @@ private void runImpl(NGCommunicator comm, Socket socket) { methodArgs[0] = cmdlineArgs; } catch (NoSuchMethodException ex) { // failed to find 'main' too, so give up and throw - throw new NGNailNotFoundException( - "Can't find nailMain or main functions in " + cmdclass.getName(), ex); + NGNailNotFoundException e = + new NGNailNotFoundException( + "Can't find nailMain or main functions in " + cmdclass.getName(), ex); + LOG.log(Level.SEVERE, e.toString(), e); + throw e; } } } diff --git a/nailgun-server/src/main/java/com/facebook/nailgun/NGWin32NamedPipeSocket.java b/nailgun-server/src/main/java/com/facebook/nailgun/NGWin32NamedPipeSocket.java index 8e88bfa4..36836a37 100644 --- a/nailgun-server/src/main/java/com/facebook/nailgun/NGWin32NamedPipeSocket.java +++ b/nailgun-server/src/main/java/com/facebook/nailgun/NGWin32NamedPipeSocket.java @@ -39,7 +39,8 @@ public class NGWin32NamedPipeSocket extends Socket { private final HANDLE readerWaitable; private final HANDLE writerWaitable; - interface CloseCallback { + @FunctionalInterface + static interface CloseCallback { void onNamedPipeSocketClose(HANDLE handle) throws IOException; } diff --git a/nailgun-server/src/main/java/com/facebook/nailgun/NonStaticNail.java b/nailgun-server/src/main/java/com/facebook/nailgun/NonStaticNail.java index 74bb3a2d..fe3b4818 100644 --- a/nailgun-server/src/main/java/com/facebook/nailgun/NonStaticNail.java +++ b/nailgun-server/src/main/java/com/facebook/nailgun/NonStaticNail.java @@ -23,7 +23,8 @@ * *
Implementations of this interface MUST provide a public, no-args constructor.
*/
+@FunctionalInterface
public interface NonStaticNail {
- public void nailMain(String[] args);
+ void nailMain(String[] args);
}
diff --git a/nailgun-server/src/main/java/com/facebook/nailgun/ThreadLocalPrintStream.java b/nailgun-server/src/main/java/com/facebook/nailgun/ThreadLocalPrintStream.java
index 13411c4c..78e45159 100644
--- a/nailgun-server/src/main/java/com/facebook/nailgun/ThreadLocalPrintStream.java
+++ b/nailgun-server/src/main/java/com/facebook/nailgun/ThreadLocalPrintStream.java
@@ -32,7 +32,7 @@
class ThreadLocalPrintStream extends PrintStream {
/** The PrintStreams for the various threads */
- private InheritableThreadLocal streams = null;
+ private InheritableThreadLocal