Commits

Meikel Brandmeyer committed 997483f

Move modified nailgun to vimclojure package

Comments (0)

Files changed (52)

 JAVA=${CLOJURE_JAVA:-java}
 OPTS=${CLOJURE_OPTS:-}
 
-exec ${JAVA} ${OPTS} com.martiansoftware.nailgun.NGServer 127.0.0.1 "$@"
+exec ${JAVA} ${OPTS} vimclojure.nailgun.NGServer 127.0.0.1 "$@"

bin/ng-server.bat

 IF EXIST .clojure FOR /F %%E IN (.clojure) DO SET CP=!CP!;%%~fE
 
 REM # Since we do not provide any security we at least bind only to the loopback.
-%CLOJURE_JAVA% %CLOJURE_OPTS% -cp "%CP%" com.martiansoftware.nailgun.NGServer 127.0.0.1 %1 %2 %3 %4 %5 %6 %7 %8 %9
+%CLOJURE_JAVA% %CLOJURE_OPTS% -cp "%CP%" vimclojure.nailgun.NGServer 127.0.0.1 %1 %2 %3 %4 %5 %6 %7 %8 %9
         sourceSets.main.classesDir.path,
         configurations.clojure
     ])
-    main = 'com.martiansoftware.nailgun.NGServer'
+    main = 'vimclojure.nailgun.NGServer'
     args = [ '127.0.0.1' ]
 }
 
 To use the interactive part you have to start the nailgun server via the jar
 file. Make sure, that clojure and clojure-contrib are in your classpath and
-start the com.martiansoftware.nailgun.NGServer class. Example invocation:
+start the vimclojure.nailgun.NGServer class. Example invocation:
 >
-        java -cp clojure.jar:clojure-contrib.jar:vimclojure.jar com.martiansoftware.nailgun.NGServer 127.0.0.1
+        java -cp clojure.jar:clojure-contrib.jar:vimclojure.jar vimclojure.nailgun.NGServer 127.0.0.1
 <
 This may look different depending on your system.
 

src/main/clojure/vimclojure/nails.clj

     java.io.PrintStream
     java.io.PrintWriter
     clojure.lang.LineNumberingPushbackReader
-    com.martiansoftware.nailgun.NGContext
-    com.martiansoftware.nailgun.NGServer
-    com.martiansoftware.nailgun.ThreadLocalInputStream
-    com.martiansoftware.nailgun.ThreadLocalPrintStream))
+    vimclojure.nailgun.NGContext
+    vimclojure.nailgun.NGServer
+    vimclojure.nailgun.ThreadLocalInputStream
+    vimclojure.nailgun.ThreadLocalPrintStream))
 
 (defn start-server-thread
   "Start a nailgun server in a dedicated daemon thread. host defaults

src/main/java/com/martiansoftware/nailgun/Alias.java

-/*   
-
-  Copyright 2004, Martian Software, Inc.
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-  http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-
-*/
-
-package com.martiansoftware.nailgun;
-
-/**
- * Provides a means to map memorable, short names to classes in order
- * to make the issuing of commands more convenient.  For example, an
- * Alias can map the "<code>mycommand</code>" command to the <code>com.yourdomain.yourpackage.YourClass</code>
- * class.  Obviously, it's a lot easier to type "<code>ng mycommand</code>" than the fully
- * qualified class name.
- * 
- * @author <a href="http://www.martiansoftware.com/contact.html">Marty Lamb</a>
- */
-public class Alias implements Comparable {
-
-	/**
-	 * The alias name
-	 */
-	private String name;
-	
-	/**
-	 * The alias description (may be used to provide help to users)
-	 */
-	private String description;
-	
-	/**
-	 * The class providing a <code>main()</code> or <code>nailMain()</code> method
-	 */
-	private Class clazz;
-	
-	/**
-	 * Creates a new Alias with the specified properties.
-	 * @param name the alias name (short command)
-	 * @param description a description of the command
-	 * @param clazz the class implementing the command
-	 */
-	public Alias(String name, String description, Class clazz) {
-		if (name == null) throw (new IllegalArgumentException("Alias must have a name."));
-		this.name = name.trim();
-		if (this.name.length() == 0) throw (new IllegalArgumentException("Alias must have a name."));
-		
-		if (clazz == null) throw (new IllegalArgumentException("Alias must have an associated class."));
-		this.description = description;
-		this.clazz = clazz;
-	}
-	
-	/**
-	 * Returns the <code>Class</code> object providing a static <code>main()</code> or <code>nailMain()</code> method
-	 * for this command.
-	 * @return the <code>Class</code> object providing a static <code>main()</code> or <code>nailMain()</code> method
-	 * for this command.
-	 */
-	public Class getAliasedClass() {
-		return(clazz);
-	}
-	
-	/**
-	 * Returns the name of the aliased command
-	 * @return the name of the aliased command
-	 */
-	public String getName() {
-		return (name);
-	}
-	
-	/**
-	 * Returns a description for the aliased command
-	 * @return a description for the aliased command
-	 */
-	public String getDescription() {
-		return (description);
-	}
-	
-	/**
-	 * @see Object#hashCode()
-	 */
-	public int hashCode() {
-		return (name.hashCode());
-	}
-	
-	/**
-	 * Checks whether two Aliases have the same name.  Does <b>not</b>
-	 * compare any other fields.
-	 * @param o the other Alias to check
-	 * @return true if the specified Alias has the same name as this Alias.
-	 */
-	public boolean equals(Object o) {
-		return (compareTo(o) == 0);
-	}
-	
-	/**
-	 * Compares Alias <b>names</b> - no other fields are compared.
-	 * @see Comparable#compareTo(Object)
-	 */
-	public int compareTo(Object o) {
-		return (name.compareTo(((Alias) o).getName()));
-	}
-}

src/main/java/com/martiansoftware/nailgun/AliasManager.java

-/*   
-
-  Copyright 2004, Martian Software, Inc.
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-  http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-
-*/
-
-package com.martiansoftware.nailgun;
-
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Properties;
-import java.util.Set;
-
-/**
- * An AliasManager is used to store and lookup command Aliases by name.
- * See <a href="Alias.html">Alias</a> for more details.
- * 
- * @author <a href="http://www.martiansoftware.com/contact.html">Marty Lamb</a>
- */
-public class AliasManager {
-	
-	/**
-	 * actual alias storage
-	 */
-	private Map aliases;
-	
-	/**
-	 * Creates a new AliasManager, populating it with
-	 * default Aliases.
-	 */
-	public AliasManager() {
-		aliases = new java.util.HashMap();
-		
-		try {
-			Properties props = new Properties();
-			props.load(getClass().getClassLoader().getResourceAsStream("com/martiansoftware/nailgun/builtins/builtins.properties"));
-			loadFromProperties(props);
-		} catch (java.io.IOException e) {
-			System.err.println("Unable to load builtins.properties: " + e.getMessage());
-		}
-	}
-	
-	/**
-	 * Loads Aliases from a java.util.Properties file located at the
-	 * specified URL.  The properties must be of the form:
-	 * <pre><code>[alias name]=[fully qualified classname]</code></pre>
-	 * each of which may have an optional
-	 * <pre><code>[alias name].desc=[alias description]</code></pre>
-	 * 
-	 * For example, to create an alias called "<code>myprog</code>" for
-	 * class <code>com.mydomain.myapp.MyProg</code>, the following properties
-	 * would be defined:
-	 * 
-	 * <pre><code>myprog=com.mydomain.myapp.MyProg
-	 *myprog.desc=Runs my program.
-	 * </code></pre>
-	 * @param properties the Properties to load.
-	 */
-	public void loadFromProperties(java.util.Properties properties) {
-		for (Iterator i = properties.keySet().iterator(); i.hasNext();) {
-			String key = (String) i.next();
-			if (!key.endsWith(".desc")) {
-				try {
-					Class clazz = Class.forName(properties.getProperty(key));
-					String desc = properties.getProperty(key + ".desc", "");
-					addAlias(new Alias(key, desc, clazz));
-				} catch (ClassNotFoundException e) {
-					System.err.println("Unable to locate class " + properties.getProperty(key));
-				}
-			}
-		}
-	}
-	
-	/**
-	 * Adds an Alias, replacing any previous entries with the
-	 * same name.
-	 * @param alias the Alias to add
-	 */
-	public void addAlias(Alias alias) {
-		synchronized (aliases) {
-			aliases.put(alias.getName(), alias);
-		}
-	}
-	
-	/**
-	 * Returns a Set that is a snapshot of the Alias list.
-	 * Modifications to this Set will not impact the AliasManager
-	 * in any way.
-	 * @return a Set that is a snapshot of the Alias list.
-	 */
-	public Set getAliases() {
-		Set result = new java.util.TreeSet();
-		synchronized(aliases) {
-			result.addAll(aliases.values());
-		}
-		return (result);
-	}
-
-	/**
-	 * Removes the Alias with the specified name from the AliasManager.
-	 * If no such Alias exists in this AliasManager, this method has no effect.
-	 * @param aliasName the name of the Alias to remove
-	 */
-	public void removeAlias(String aliasName) {
-		synchronized (aliases) {
-			aliases.remove(aliasName);
-		}
-	}
-
-	/**
-	 * Returns the Alias with the specified name
-	 * @param aliasName the name of the Alias to retrieve
-	 * @return the requested Alias, or null if no such Alias
-	 * is defined in this AliasManager.
-	 */
-	public Alias getAlias(String aliasName) {
-		return ((Alias) aliases.get(aliasName));
-	}
-
-}

src/main/java/com/martiansoftware/nailgun/LongUtils.java

-/*   
-
-  Copyright 2004, Martian Software, Inc.
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-  http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-  
-*/
-
-package com.martiansoftware.nailgun;
-
-/**
- * Provides a couple of utility methods that help in reading/writin
- * chunks of data in the Nailgun protocol.
- * 
- * @author <a href="http://www.martiansoftware.com/contact.html">Marty Lamb</a>
- */
-class LongUtils {
-
-	/**
-	 * Encodes the specified long in 4 consecutive bytes (big-endian)
-	 * in the specified array, beginning at the specified offset.
-	 * @param l the long to encode
-	 * @param b the array into which the long should be written
-	 * @param offset the offset into the array at which the writing
-	 * should begin
-	 */
-	public static void toArray(long l, byte[] b, int offset) {
-		b[offset + 3] = (byte) (l % 256);
-		l >>>= 8;
-		b[offset + 2] = (byte) (l % 256);
-		l >>>= 8;
-		b[offset + 1] = (byte) (l % 256);
-		l >>>= 8;
-		b[0] = (byte) (l % 256);
-	}
-	
-	/**
-	 * Reads a 4-byte big-endian long from the specified array,
-	 * beginnin at the specified offset.
-	 * @param b the array containing the encoded long
-	 * @param offset the offset into the array at which the encoded
-	 * long begins
-	 * @return the decoded long
-	 */
-	public static long fromArray(byte[] b, int offset) {
-		return(((long) (b[offset] & 0xff) << 24)
-				+ ((long) (b[offset + 1] & 0xff) << 16)
-				+ ((long) (b[offset + 2] & 0xff) << 8)
-				+ ((long) (b[offset + 3] & 0xff)));
-	}
-}

src/main/java/com/martiansoftware/nailgun/NGConstants.java

-/*   
-
-  Copyright 2004, Martian Software, Inc.
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-  http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-
-*/
-
-package com.martiansoftware.nailgun;
-
-import java.util.Properties;
-
-/**
- * Just a simple holder for various NailGun-related contants.
- * 
- * @author <a href="http://www.martiansoftware.com/contact.html">Marty Lamb</a>
- */
-public class NGConstants {
-	
-	/**
-	 * The default NailGun port (2113)
-	 */
-	public static final int DEFAULT_PORT = 2113;
-	
-	/**
-	 * The exit code sent to clients if an exception occurred on the server
-	 */
-	public static final int EXIT_EXCEPTION = 899;
-	
-	/**
-	 * The exit code sent to clients if an invalid command is sent
-	 */
-	public static final int EXIT_NOSUCHCOMMAND = 898;
-
-	/**
-	 * Chunk type marker for command line arguments
-	 */
-	public static final char CHUNKTYPE_ARGUMENT = 'A';
-
-	/**
-	 * Chunk type marker for client environment variables
-	 */
-	public static final char CHUNKTYPE_ENVIRONMENT = 'E';
-	
-	/**
-	 * Chunk type marker for the command (alias or class)
-	 */
-	public static final char CHUNKTYPE_COMMAND = 'C';
-	
-	/**
-	 * Chunk type marker for client working directory
-	 */	
-	public static final char CHUNKTYPE_WORKINGDIRECTORY = 'D';
-	
-	/**
-	 * Chunk type marker for stdin
-	 */
-	public static final char CHUNKTYPE_STDIN = '0';
-
-	/**
-	 * Chunk type marker for the end of stdin
-	 */
-	public static final char CHUNKTYPE_STDIN_EOF = '.';
-
-	/**
-	 * Chunk type marker for stdout
-	 */
-	public static final char CHUNKTYPE_STDOUT = '1';
-	
-	/**
-	 * Chunk type marker for stderr
-	 */	
-	public static final char CHUNKTYPE_STDERR = '2';
-	
-	/**
-	 * Chunk type marker for client exit chunks
-	 */	
-	public static final char CHUNKTYPE_EXIT = 'X';
-	
-	/**
-	 * Server version number
-	 */
-	public static final String VERSION;
-	
-	/**
-	 * Loads the version number from a file generated by Ant.
-	 */
-	static {
-		Properties props = new Properties();
-		try {
-			props.load(NGConstants.class.getClassLoader().getResourceAsStream("com/martiansoftware/nailgun/nailgun-version.properties"));
-		} catch (java.io.IOException e) {
-			System.err.println("Unable to load nailgun-version.properties.");
-		}
-		VERSION = props.getProperty("version", "UNKNOWN");
-	}
-	
-}

src/main/java/com/martiansoftware/nailgun/NGContext.java

-/*   
-
-  Copyright 2004, Martian Software, Inc.
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-  http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-
- */
-
-package com.martiansoftware.nailgun;
-
-import java.io.InputStream;
-import java.io.PrintStream;
-import java.net.InetAddress;
-import java.net.NetworkInterface;
-import java.util.Properties;
-
-/**
- * <p>Provides quite a bit of potentially useful information to classes
- * specifically written for NailGun. The <a href="NGServer.html">NailGun server</a> itself, its
- * <a href="AliasManager.html">AliasManager</a>, the remote client's environment variables, and other
- * information is available via this class. For all intents and purposes,
- * the NGContext represents a single connection from a NailGun client.</p>
- * 
- * If a class is written with a
- * 
- * <pre><code>
- * public static void nailMain(NGContext context)
- * </code></pre>
- * 
- * method, that method will be called by NailGun instead of the traditional
- * <code>main(String[])</code> method normally used for programs. A fully populated <code>NGContext</code>
- * object will then be provided to <code>nailMain()</code>.
- * 
- * @author <a href="http://www.martiansoftware.com/contact.html">Marty Lamb </a>
- */
-public class NGContext {
-
-	/**
-	 * The remote host's environment variables
-	 */
-	private Properties remoteEnvironment = null;
-
-	/**
-	 * The remote host's address
-	 */
-	private InetAddress remoteHost = null;
-
-	/**
-	 * The port on the remote host that is communicating with NailGun
-	 */
-	private int remotePort = 0;
-
-	/**
-	 * Command line arguments for the nail
-	 */
-	private String[] args = null;
-
-	/**
-	 * A stream to which a client exit code can be printed
-	 */
-	private PrintStream exitStream = null;
-
-	/**
-	 * The NGServer that accepted this connection
-	 */
-	private NGServer server = null;
-
-	/**
-	 * The command that was issued for this connection
-	 */
-	private String command = null;
-
-	private String workingDirectory = null;
-	
-	/**
-	 * The client's stdin
-	 */
-	public InputStream in = null;
-
-	/**
-	 * The client's stdout
-	 */
-	public PrintStream out = null;
-
-	/**
-	 * The client's stderr
-	 */
-	public PrintStream err = null;
-
-	
-	/**
-	 * Creates a new, empty NGContext
-	 */
-	NGContext() {
-		super();
-	}
-	
-	void setExitStream(PrintStream exitStream) {
-		this.exitStream = exitStream;
-	}
-
-	void setPort(int remotePort) {
-		this.remotePort = remotePort;
-	}
-
-	void setCommand(String command) {
-		this.command = command;
-	}
-
-	/**
-	 * Returns the command that was issued by the client (either an alias or the name of a class).
-	 * This allows multiple aliases to point to the same class but result in different behaviors.
-	 * @return the command issued by the client
-	 */
-	public String getCommand() {
-		return (command);
-	}
-	
-	void setWorkingDirectory(String workingDirectory) {
-		this.workingDirectory = workingDirectory;
-	}
-	
-	/**
-	 * Returns the current working directory of the client, as reported by the client.
-	 * This is a String that will use the client's <code>File.separator</code> ('/' or '\'),
-	 * which may differ from the separator on the server. 
-	 * @return the current working directory of the client
-	 */
-	public String getWorkingDirectory() {
-		return (workingDirectory);
-	}
-	
-	void setEnv(Properties remoteEnvironment) {
-		this.remoteEnvironment = remoteEnvironment;
-	}
-
-	void setInetAddress(InetAddress remoteHost) {
-		this.remoteHost = remoteHost;
-	}
-
-	void setArgs(String[] args) {
-		this.args = args;
-	}
-
-	void setNGServer(NGServer server) {
-		this.server = server;
-	}
-
-	/**
-	 * Returns a <code>java.util.Properties</code> object containing a copy
-	 * of the client's environment variables
-	 * @see java.util.Properties
-	 * @return a <code>java.util.Properties</code> object containing a copy
-	 * of the client's environment variables
-	 */
-	public Properties getEnv() {
-		return (remoteEnvironment);
-	}
-
-	/**
-	 * Returns the file separator ('/' or '\\') used by the client's os.
-	 * @return the file separator ('/' or '\\') used by the client's os.
-	 */
-	public String getFileSeparator() {
-		return (remoteEnvironment.getProperty("NAILGUN_FILESEPARATOR"));
-	}
-	
-	/**
-	 * Returns the path separator (':' or ';') used by the client's os.
-	 * @return the path separator (':' or ';') used by the client's os.
-	 */
-	public String getPathSeparator() {
-		return (remoteEnvironment.getProperty("NAILGUN_PATHSEPARATOR"));		
-	}
-	
-	/**
-	 * Returns the address of the client at the other side of this connection.
-	 * @return the address of the client at the other side of this connection.
-	 */
-	public InetAddress getInetAddress() {
-		return (remoteHost);
-	}
-
-	/**
-	 * Returns the command line arguments for the command
-	 * implementation (nail) on the server.
-	 * @return the command line arguments for the command
-	 * implementation (nail) on the server.
-	 */
-	public String[] getArgs() {
-		return (args);
-	}
-
-	/**
-	 * Returns the NGServer that accepted this connection
-	 * @return the NGServer that accepted this connection
-	 */
-	public NGServer getNGServer() {
-		return (server);
-	}
-
-	/**
-	 * Sends an exit command with the specified exit code to
-	 * the client.  The client will exit immediately with
-	 * the specified exit code; you probably want to return
-	 * from nailMain immediately after calling this.
-	 * 
-	 * @param exitCode the exit code with which the client
-	 * should exit
-	 */
-	public void exit(int exitCode) {
-		exitStream.println(exitCode);
-	}
-
-	/**
-	 * Returns the port on the client connected to the NailGun
-	 * server.
-	 * @return the port on the client connected to the NailGun
-	 * server.
-	 */
-	public int getPort() {
-		return (remotePort);
-	}
-	
-	/**
-	 * Throws a <code>java.lang.SecurityException</code> if the client is not
-	 * connected via the loopback address.
-	 */
-	public void assertLoopbackClient() {
-		if (!getInetAddress().isLoopbackAddress()) {
-			throw (new SecurityException("Client is not at loopback address."));
-		}
-	}
-	
-	/**
-	 * Throws a <code>java.lang.SecurityException</code> if the client is not
-	 * connected from the local machine.
-	 */
-	public void assertLocalClient() {
-		NetworkInterface iface = null;
-		try {
-			iface = NetworkInterface.getByInetAddress(getInetAddress());
-		} catch (java.net.SocketException se) {
-			throw (new SecurityException("Unable to determine if client is local.  Assuming he isn't."));
-		}
-		
-		if ((iface == null) && (!getInetAddress().isLoopbackAddress())) {
-			throw (new SecurityException("Client is not local."));
-		}
-	}
-}

src/main/java/com/martiansoftware/nailgun/NGExitException.java

-/*   
-
-  Copyright 2004, Martian Software, Inc.
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-  http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-
-*/
-
-package com.martiansoftware.nailgun;
-
-import  java.io.PrintStream;
-
-import  org.apache.tools.ant.ExitException;
-
-/**
- * Security exception which wraps an exit status code.
- * @author Pete Kirkham
- */
-public class NGExitException extends ExitException {
-        public NGExitException(int status) {
-                super(status);
-        }
-  
-        /**
-         * A lot of code out there, for example ant's Launcher,
-         * runs inside a try/catch (Throwable) which will squash
-         * this exception; most also calll printStackTrace(), so
-         * this re-throws the exception to escape the handling code.
-         */
-        public void printStackTrace (PrintStream out) {
-                throw this;
-        }
-        
-        public void reallyPrintStackTrace (PrintStream out) {
-                super.printStackTrace(out);
-        }
-}

src/main/java/com/martiansoftware/nailgun/NGInputStream.java

-/*   
-
-  Copyright 2004, Martian Software, Inc.
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-  http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-
-*/
-
-package com.martiansoftware.nailgun;
-
-import java.io.FilterInputStream;
-import java.io.IOException;
-
-/**
- * A FilterInputStream that is able to read the chunked stdin stream
- * from a NailGun client.
- * 
- * @author <a href="http://www.martiansoftware.com/contact.html">Marty Lamb</a>
- */
-class NGInputStream extends FilterInputStream {
-
-	private byte[] header;
-	private boolean eof = false;
-	private long remaining = 0;
-	
-	/**
-	 * Creates a new NGInputStream wrapping the specified InputStream
-	 * @param in the InputStream to wrap
-	 */
-	public NGInputStream(java.io.InputStream in) {
-		super(in);
-		header = new byte[5];
-	}
-
-	/**
-	 * Reads a NailGun chunk header from the underlying InputStream.
-	 * 
-	 * @throws IOException if thrown by the underlying InputStream,
-	 * or if an unexpected NailGun chunk type is encountered.
-	 */
-	private void readHeader() throws IOException {
-		if (eof) return;
-		
-		int bytesRead = in.read(header);
-		int thisPass = 0;
-		while (bytesRead < 5) {
-			thisPass = in.read(header, bytesRead, 5 - bytesRead);
-			if (thisPass < 0) {
-				eof = true;
-				return;
-			}
-			bytesRead += thisPass;
-		}
-		switch(header[4]) {
-			case NGConstants.CHUNKTYPE_STDIN:
-						remaining = LongUtils.fromArray(header, 0);
-						break;
-						
-			case NGConstants.CHUNKTYPE_STDIN_EOF:
-						eof = true;
-						break;
-						
-			default:	throw(new IOException("Unknown stream type: " + (char) header[4]));
-		}		
-	}
-	
-	/**
-	 * @see java.io.InputStream#available()
-	 */
-	public int available() throws IOException {
-		if (eof) return(0);
-		if (remaining > 0) return (in.available());
-		return (Math.max(0, in.available() - 5));
-	}
-	
-	/**
-	 * @see java.io.InputStream#markSupported()
-	 */
-	public boolean markSupported() {
-		return (false);
-	}
-	
-	/**
-	 * @see java.io.InputStream#read()
-	 */
-	public int read() throws IOException {
-		// this should be more readable.
-		// this stomps on the first byte of the header array,
-		// which is ok
-		return((read(header, 0, 1) == -1) ? -1 : (int) header[0]);
-	}
-	
-	/**
-	 * @see java.io.InputStream.read(byte[])
-	 */
-	public int read(byte[] b) throws IOException {
-		return (read(b, 0, b.length));
-	}
-	
-	/**
-	 * @see java.io.InputStream.read(byte[],offset,length)
-	 */
-	public int read(byte[] b, int offset, int length) throws IOException {
-		if (remaining == 0) readHeader();
-		if (eof) return(-1);
-
-		int bytesToRead = Math.min((int) remaining, length);
-		int result = in.read(b, offset, bytesToRead);
-		remaining -= result;
-		return (result);
-	}
-
-}

src/main/java/com/martiansoftware/nailgun/NGOutputStream.java

-/*   
-
-  Copyright 2004, Martian Software, Inc.
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-  http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-
-*/
-
-package com.martiansoftware.nailgun;
-
-import java.io.IOException;
-
-/**
- * Wraps an OutputStream to send writes in NailGun chunks.  Because
- * multiple NGOutputStreams wrap the same OutputStream (that is, 
- * the OutputStream obtained from the Socket connection with
- * the client), writes are synchronized on the underlying OutputStream.
- * If this were not the case, write interleaving could completely
- * break the NailGun protocol.
- * 
- * @author <a href="http://www.martiansoftware.com/contact.html">Marty Lamb</a>
- */
-class NGOutputStream extends java.io.FilterOutputStream {
-
-	private byte[] header;
-	
-	/**
-	 * Creates a new NGOutputStream wrapping the specified
-	 * OutputStream and using the specified Nailgun chunk code.
-	 * @param out the OutputStream to wrap
-	 * @param code the NailGun chunk code associated with this
-	 * stream (i.e., '1' for stdout, '2' for stderr).
-	 */
-	public NGOutputStream(java.io.OutputStream out, char code) {
-		super(out);
-		header = new byte[5];
-		header[4] = (byte) code;
-	}
-	
-	/**
-	 * @see java.io.OutputStream.write(byte[])
-	 */
-	public void write(byte[] b) throws IOException {
-		write(b, 0, b.length);
-	}
-	
-	/**
-	 * @see java.io.OutputStream.write(int)
-	 */
-	public void write(int b) throws IOException {
-		byte[] b2 = {(byte) b};
-		write(b2, 0, 1);
-	}
-	
-	/**
-	 * @see java.io.OutputStream.write(byte[],int,int)
-	 */
-	public void write(byte[] b, int offset, int len) throws IOException {
-		LongUtils.toArray(len, header, 0);
-		synchronized(out) {
-			out.write(header, 0, 5);
-			out.write(b, offset, len);
-		}
-		out.flush();
-	}
-}

src/main/java/com/martiansoftware/nailgun/NGSecurityManager.java

-/*   
-
-Copyright 2004, Martian Software, Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-
-*/
-
-package com.martiansoftware.nailgun;
-
-import  java.security.Permission;
-
-import  java.io.PrintStream;
-
-/**
- * Security manager which does nothing other than trap
- * checkExit, or delegate all non-deprecated methods to
- * a base manager.
- * 
- * @author Pete Kirkham
- * 
- */
-public class NGSecurityManager extends SecurityManager {
-        private static final ThreadLocal EXIT = new InheritableThreadLocal();
-        final SecurityManager base;
-        
-        /**
-         * Construct an NGSecurityManager with the given base.
-         * @param base the base security manager, or null for no base.
-         */
-        public NGSecurityManager (SecurityManager base) {
-                this.base = base;
-        }
-
-        public void checkExit (int status) {
-                if (base != null) {
-                        base.checkExit(status);
-                }
-                
-                final PrintStream exit = (PrintStream)EXIT.get();
-                
-                if (exit != null) {
-                        exit.println(status);
-                }
-                
-                throw new NGExitException(status);
-        }
-
-        public void checkPermission(Permission perm) {
-                if (base != null) {
-                        base.checkPermission(perm);
-                }
-        }
-   
-        public void checkPermission(Permission perm, Object context) {
-                if (base != null) {
-                        base.checkPermission(perm, context);
-                }
-        }
-        
-        public static void setExit (PrintStream exit) {
-                EXIT.set(exit);
-        }
-}

src/main/java/com/martiansoftware/nailgun/NGServer.java

-/*   
-
-  Copyright 2004, Martian Software, Inc.
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-  http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-
-*/
-
-package com.martiansoftware.nailgun;
-import java.io.InputStream;
-import java.io.PrintStream;
-import java.lang.reflect.Method;
-import java.net.InetAddress;
-import java.net.ServerSocket;
-import java.net.Socket;
-import java.net.UnknownHostException;
-import java.util.Iterator;
-import java.util.Map;
-
-import com.martiansoftware.nailgun.builtins.DefaultNail;
-
-/**
- * <p>Listens for new connections from NailGun clients and launches
- * NGSession threads to process them.</p>
- * 
- * <p>This class can be run as a standalone server or can be embedded
- * within larger applications as a means of providing command-line
- * interaction with the application.</p>
- * 
- * @author <a href="http://www.martiansoftware.com/contact.html">Marty Lamb</a>
- */
-public class NGServer implements Runnable {
-
-	/**
-	 * The address on which to listen, or null to listen on all
-	 * local addresses
-	 */
-	private InetAddress addr = null;
-	
-	/**
-	 * The port on which to listen, or zero to select a port automatically
-	 */
-	private int port = 0;
-	
-	/**
-	 * The socket doing the listening
-	 */
-	private ServerSocket serversocket;
-	
-	/**
-	 * True if this NGServer has received instructions to shut down
-	 */
-	private boolean shutdown = false;
-	
-	/**
-	 * True if this NGServer has been started and is accepting connections
-	 */
-	private boolean running = false;
-	
-	/**
-	 * This NGServer's AliasManager, which maps aliases to classes
-	 */
-	private AliasManager aliasManager;
-	
-	/**
-	 * If true, fully-qualified classnames are valid commands
-	 */
-	private boolean allowNailsByClassName = true;
-	
-	/**
-	 * The default class to use if an invalid alias or classname is
-	 * specified by the client.
-	 */
-	private Class defaultNailClass = null;
-	
-	/**
-	 * A pool of NGSessions ready to handle client connections
-	 */
-	private NGSessionPool sessionPool = null;
-	
-	/**
-	 * <code>System.out</code> at the time of the NGServer's creation
-	 */
-	public final PrintStream out = System.out;
-
-	/**
-	 * <code>System.err</code> at the time of the NGServer's creation
-	 */
-	public final PrintStream err = System.err;
-	
-	/**
-	 * <code>System.in</code> at the time of the NGServer's creation
-	 */
-	public final InputStream in = System.in;
-	
-	/**
-	 * a collection of all classes executed by this server so far
-	 */
-	private Map allNailStats = null;
-	
-	/**
-	 * Remember the security manager we start with so we can restore it later
-	 */
-	private SecurityManager originalSecurityManager = null;
-	
-	/**
-	 * Creates a new NGServer that will listen at the specified address and
-	 * on the specified port.
-	 * This does <b>not</b> cause the server to start listening.  To do
-	 * so, create a new <code>Thread</code> wrapping this <code>NGServer</code>
-	 * and start it.
-	 * @param addr the address at which to listen, or <code>null</code> to bind
-	 * to all local addresses
-	 * @param port the port on which to listen.
-	 */
-	public NGServer(InetAddress addr, int port) {
-		init(addr, port);
-	}
-	
-	/**
-	 * Creates a new NGServer that will listen on the default port
-	 * (defined in <code>NGConstants.DEFAULT_PORT</code>).
-	 * This does <b>not</b> cause the server to start listening.  To do
-	 * so, create a new <code>Thread</code> wrapping this <code>NGServer</code>
-	 * and start it.
-	 */
-	public NGServer() {
-		init(null, NGConstants.DEFAULT_PORT);
-	}
-	
-	/**
-	 * Sets up the NGServer internals
-	 * @param addr the InetAddress to bind to
-	 * @param port the port on which to listen
-	 */
-	private void init(InetAddress addr, int port) {
-		this.addr = addr;
-		this.port = port;
-		
-		this.aliasManager = new AliasManager();
-		allNailStats = new java.util.HashMap();
-		// allow a maximum of 10 idle threads.  probably too high a number
-		// and definitely should be configurable in the future
-		sessionPool = new NGSessionPool(this, 10);
-	}
-
-	/**
-	 * Sets a flag that determines whether Nails can be executed by class name.
-	 * If this is false, Nails can only be run via aliases (and you should
-	 * probably remove ng-alias from the AliasManager).
-	 * 
-	 * @param allowNailsByClassName true iff Nail lookups by classname are allowed
-	 */
-	public void setAllowNailsByClassName(boolean allowNailsByClassName) {
-		this.allowNailsByClassName = allowNailsByClassName;
-	}
-	
-	/**
-	 * Returns a flag that indicates whether Nail lookups by classname
-	 * are allowed.  If this is false, Nails can only be run via aliases.
-	 * @return a flag that indicates whether Nail lookups by classname
-	 * are allowed.
-	 */
-	public boolean allowsNailsByClassName() {
-		return (allowNailsByClassName);
-	}
-	
-	/**
-	 * Sets the default class to use for the Nail if no Nails can
-	 * be found via alias or classname. (may be <code>null</code>,
-	 * in which case NailGun will use its own default)
-	 * @param defaultNailClass the default class to use for the Nail
-	 * if no Nails can be found via alias or classname.
-	 * (may be <code>null</code>, in which case NailGun will use
-	 * its own default)
-	 */
-	public void setDefaultNailClass(Class defaultNailClass) {
-		this.defaultNailClass = defaultNailClass;
-	}
-	
-	/**
-	 * Returns the default class that will be used if no Nails
-	 * can be found via alias or classname.
-	 * @return the default class that will be used if no Nails
-	 * can be found via alias or classname.
-	 */
-	public Class getDefaultNailClass() {
-		return ((defaultNailClass == null) ? DefaultNail.class : defaultNailClass) ;
-	}
-	
-	/**
-	 * Returns the current NailStats object for the specified class, creating
-	 * a new one if necessary
-	 * @param nailClass the class for which we're gathering stats
-	 * @return a NailStats object for the specified class
-	 */
-	private NailStats getOrCreateStatsFor(Class nailClass) {
-		NailStats result = null;
-		synchronized(allNailStats) {
-			result = (NailStats) allNailStats.get(nailClass);
-			if (result == null) {
-				result = new NailStats(nailClass);
-				allNailStats.put(nailClass, result);
-			}
-		}
-		return (result);
-	}
-	
-	/**
-	 * Provides a means for an NGSession to register the starting of
-	 * a nail execution with the server.
-	 * 
-	 * @param nailClass the nail class that was launched
-	 */
-	void nailStarted(Class nailClass) {
-		NailStats stats = getOrCreateStatsFor(nailClass);
-		stats.nailStarted();
-	}
-	
-	/**
-	 * Provides a means for an NGSession to register the completion of
-	 * a nails execution with the server.
-	 * 
-	 * @param nailClass the nail class that finished
-	 */
-	void nailFinished(Class nailClass) {
-		NailStats stats = (NailStats) allNailStats.get(nailClass);
-		stats.nailFinished();
-	}
-	
-	/**
-	 * Returns a snapshot of this NGServer's nail statistics.  The result is a <code>java.util.Map</code>,
-	 * keyed by class name, with <a href="NailStats.html">NailStats</a> objects as values.
-	 * 
-	 * @return a snapshot of this NGServer's nail statistics.
-	 */
-	public Map getNailStats() {
-		Map result = new java.util.TreeMap();
-		synchronized(allNailStats) {
-			for (Iterator i = allNailStats.keySet().iterator(); i.hasNext();) {
-				Class nailclass = (Class) i.next();
-				result.put(nailclass.getName(), ((NailStats) allNailStats.get(nailclass)).clone());
-			}
-		}
-		return (result);
-	}
-	
-	/**
-	 * Returns the AliasManager in use by this NGServer.
-	 * @return the AliasManager in use by this NGServer.
-	 */
-	public AliasManager getAliasManager() {
-		return (aliasManager);
-	}
-
-	/**
-	 * <p>Shuts down the server.  The server will stop listening
-	 * and its thread will finish.  Any running nails will be allowed
-	 * to finish.</p>
-	 * 
-	 * <p>Any nails that provide a
-	 * <pre><code>public static void nailShutdown(NGServer)</code></pre>
-	 * method will have this method called with this NGServer as its sole
-	 * parameter.</p>
-	 * 
-	 * @param exitVM if true, this method will also exit the JVM after
-	 * calling nailShutdown() on any nails.  This may prevent currently
-	 * running nails from exiting gracefully, but may be necessary in order
-	 * to perform some tasks, such as shutting down any AWT or Swing threads
-	 * implicitly launched by your nails.
-	 */
-	public void shutdown(boolean exitVM) {
-		synchronized(this) {
-			if (shutdown) return;
-			shutdown = true;
-		}
-		
-		try {
-			serversocket.close();
-		} catch (Throwable toDiscard) {}
-		
-		sessionPool.shutdown();
-		
-		Class[] argTypes = new Class[1];
-		argTypes[0] = NGServer.class;
-		Object[] argValues = new Object[1];
-		argValues[0] = this;
-		
-		// make sure that all aliased classes have associated nailstats
-		// so they can be shut down.
-		for (Iterator i = getAliasManager().getAliases().iterator(); i.hasNext();) {
-			Alias alias = (Alias) i.next();
-			getOrCreateStatsFor(alias.getAliasedClass());
-		}
-		
-		synchronized(allNailStats) {
-			for (Iterator i = allNailStats.values().iterator(); i.hasNext();) {
-				NailStats ns = (NailStats) i.next();
-				Class nailClass = ns.getNailClass();
-				
-				// yes, I know this is lazy, relying upon the exception
-				// to handle the case of no nailShutdown method.
-				try {
-					Method nailShutdown = nailClass.getMethod("nailShutdown", argTypes);
-					nailShutdown.invoke(null, argValues);
-				} catch (Throwable toDiscard) {}
-			}
-		}
-		
-		// restore system streams
-		System.setIn(in);
-		System.setOut(out);
-		System.setErr(err);
-		
-		System.setSecurityManager(originalSecurityManager);
-		
-		if (exitVM) {
-			System.exit(0);
-		}
-	}
-	
-	/**
-	 * Returns true iff the server is currently running.
-	 * @return true iff the server is currently running.
-	 */
-	public boolean isRunning() {
-		return (running);
-	}
-	
-	/**
-	 * Returns the port on which this server is (or will be) listening.
-	 * @return the port on which this server is (or will be) listening.
-	 */
-	public int getPort() {
-		return ((serversocket == null) ? port : serversocket.getLocalPort());
-	}
-	
-	/**
-	 * Listens for new connections and launches NGSession threads
-	 * to process them.
-	 */
-	public void run() {
-		running = true;
-		NGSession sessionOnDeck = null;
-		
-		originalSecurityManager = System.getSecurityManager();
-        System.setSecurityManager(
-                new NGSecurityManager(
-                        originalSecurityManager));
-  
-
-		synchronized(System.in) {
-			if (!(System.in instanceof ThreadLocalInputStream)) {
-				System.setIn(new ThreadLocalInputStream(in));
-				System.setOut(new ThreadLocalPrintStream(out));
-				System.setErr(new ThreadLocalPrintStream(err));				
-			}
-		}
-		
-		try {
-			if (addr == null) {
-				serversocket = new ServerSocket(port);
-			} else {
-				serversocket = new ServerSocket(port, 0, addr);
-			}
-			
-			while (!shutdown) {
-				sessionOnDeck = sessionPool.take();
-				Socket socket = serversocket.accept();
-				sessionOnDeck.run(socket);
-			}
-
-		} catch (Throwable t) {
-			// if shutdown is called while the accept() method is blocking,
-			// an exception will be thrown that we don't care about.  filter
-			// those out.
-			if (!shutdown) {
-				t.printStackTrace();
-			}
-		}
-		if (sessionOnDeck != null) {
-			sessionOnDeck.shutdown();
-		}
-		running = false;
-	}
-	
-	private static void usage() {
-		System.err.println("Usage: java com.martiansoftware.nailgun.NGServer");
-		System.err.println("   or: java com.martiansoftware.nailgun.NGServer port");
-		System.err.println("   or: java com.martiansoftware.nailgun.NGServer IPAddress");
-		System.err.println("   or: java com.martiansoftware.nailgun.NGServer IPAddress:port");
-	}
-	
-	/**
-	 * Creates and starts a new <code>NGServer</code>.  A single optional
-	 * argument is valid, specifying the port on which this <code>NGServer</code>
-	 * should listen.  If omitted, <code>NGServer.DEFAULT_PORT</code> will be used.
-	 * @param args a single optional argument specifying the port on which to listen.
-	 * @throws NumberFormatException if a non-numeric port is specified
-	 */
-	public static void main(String[] args) throws NumberFormatException, UnknownHostException {
-
-		if (args.length > 1) {
-			usage();
-			return;
-		}
-
-		// null server address means bind to everything local
-		InetAddress serverAddress = null;
-		int port = NGConstants.DEFAULT_PORT;
-		
-		// parse the sole command line parameter, which
-		// may be an inetaddress to bind to, a port number,
-		// or an inetaddress followed by a port, separated
-		// by a colon
-		if (args.length != 0) {
-			String[] argParts = args[0].split(":");
-			String addrPart = null;
-			String portPart = null;
-			if (argParts.length == 2) {
-				addrPart = argParts[0];
-				portPart = argParts[1];
-			} else if (argParts[0].indexOf('.') >= 0) {
-				addrPart = argParts[0];
-			} else {
-				portPart = argParts[0];
-			}
-			if (addrPart != null) {
-				serverAddress = InetAddress.getByName(addrPart);
-			}
-			if (portPart != null) {
-				port = Integer.parseInt(portPart);
-			}
-		}
-
-		try {
-			Class.forName("clojure.lang.IFn");
-		} catch (ClassNotFoundException ignore) {
-			System.err.println("ERROR: Could not find clojure.lang.IFn on the classpath!");
-			System.err.println("ERROR: This most likely means that Clojure is not on the classpath!");
-			System.err.println("ERROR: Please check your settings!");
-			System.err.println("ERROR: Here is the classpath for your reference:");
-			System.err.println(System.getProperty("java.class.path"));
-			return;
-		}
-
-		NGServer server = new NGServer(serverAddress, port);
-		Thread t = new Thread(server);
-		t.setName("NGServer(" + serverAddress + ", " + port + ")");
-		t.start();
-
-		Runtime.getRuntime().addShutdownHook(new NGServerShutdowner(server));
-		
-		// if the port is 0, it will be automatically determined.
-		// add this little wait so the ServerSocket can fully
-		// initialize and we can see what port it chose.
-		int runningPort = server.getPort();
-		while (runningPort == 0) {
-			try { Thread.sleep(50); } catch (Throwable toIgnore) {}
-			runningPort = server.getPort();
-		}
-		
-		System.out.println("NGServer started on "
-							+ ((serverAddress == null) 
-								? "all interfaces" 
-								: serverAddress.getHostAddress())
-		                    + ", port " 
-							+ runningPort 
-							+ ".");
-	}
-
-	/**
-	 * A shutdown hook that will cleanly bring down the NGServer if it
-	 * is interrupted.
-	 * 
-	 * @author <a href="http://www.martiansoftware.com/contact.html">Marty Lamb</a>
-	 */
-	private static class NGServerShutdowner extends Thread {
-		private NGServer server = null;
-		
-		NGServerShutdowner(NGServer server) {
-			this.server = server;
-		}
-		
-		
-		public void run() {
-			
-			int count = 0;
-			server.shutdown(false);
-			
-			// give the server up to five seconds to stop.  is that enough?
-			// remember that the shutdown will call nailShutdown in any
-			// nails as well
-			while (server.isRunning() && (count < 50)) {
-
-				try {Thread.sleep(100);} catch(InterruptedException e) {}
-				++count;
-			}
-			
-			if (server.isRunning()) {
-				System.err.println("Unable to cleanly shutdown server.  Exiting JVM Anyway.");
-			} else {
-				System.out.println("NGServer shut down.");
-			}
-		}
-	}
-}

src/main/java/com/martiansoftware/nailgun/NGSession.java

-/*   
-
-  Copyright 2004, Martian Software, Inc.
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-  http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-
-*/
-
-package com.martiansoftware.nailgun;
-
-import java.io.InputStream;
-import java.io.PrintStream;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.net.Socket;
-import java.util.List;
-import java.util.Properties;
-
-import org.apache.tools.ant.ExitException;
-
-/**
- * Reads the NailGun stream from the client through the command,
- * then hands off processing to the appropriate class.  The NGSession
- * obtains its sockets from an NGSessionPool, which created this
- * NGSession.
- * 
- * @author <a href="http://www.martiansoftware.com/contact.html">Marty Lamb</a>
- */
-class NGSession extends Thread {
-
-	/**
-	 * The server this NGSession is working for
-	 */
-	private NGServer server = null;
-	
-	/**
-	 * The pool this NGSession came from, and to which it will
-	 * return itself
-	 */
-	private NGSessionPool sessionPool = null;
-	
-	/**
-	 * Synchronization object
-	 */
-	private Object lock = new Object();
-
-	/**
-	 * The next socket this NGSession has been tasked with processing
-	 * (by NGServer)
-	 */
-	private Socket nextSocket = null;
-	
-	/**
-	 * True if the server has been shutdown and this NGSession should
-	 * terminate completely
-	 */
-	private boolean done = false;
-	
-	/**
-	 * The instance number of this NGSession.  That is, if this is the Nth
-	 * NGSession to be created, then this is the value for N.
-	 */
-	private long instanceNumber = 0;
-
-	/**
-	 * A lock shared among all NGSessions
-	 */
-	private static Object sharedLock = new Object();
-	
-	/**
-	 * The instance counter shared among all NGSessions
-	 */
-	private static long instanceCounter = 0;
-	
-	/**
-	 * signature of main(String[]) for reflection operations
-	 */
-	private static Class[] mainSignature;
-
-	/**
-	 * signature of nailMain(NGContext) for reflection operations
-	 */
-	private static Class[] nailMainSignature;
-	
-	static {
-		// initialize the signatures
-		mainSignature = new Class[1];
-		mainSignature[0] = String[].class;
-		
-		nailMainSignature = new Class[1];
-		nailMainSignature[0] = NGContext.class;
-	}
-	
-	/**
-	 * Creates a new NGSession running for the specified NGSessionPool and
-	 * NGServer.
-	 * @param sessionPool The NGSessionPool we're working for
-	 * @param server The NGServer we're working for
-	 */
-	NGSession(NGSessionPool sessionPool, NGServer server) {
-		super();
-		this.sessionPool = sessionPool;
-		this.server = server;
-	
-		synchronized(sharedLock) {
-			this.instanceNumber = ++instanceCounter;
-		}
-//		server.out.println("Created NGSession " + instanceNumber);
-	}
-
-	/**
-	 * Shuts down this NGSession gracefully
-	 */
-	void shutdown() {
-		done = true;
-		synchronized(lock) {
-			nextSocket = null;
-			lock.notifyAll();
-		}
-	}
-
-	/**
-	 * Instructs this NGSession to process the specified socket, after which
-	 * this NGSession will return itself to the pool from which it came.
-	 * @param socket the socket (connected to a client) to process
-	 */
-	public void run(Socket socket) {
-		synchronized(lock) {
-			nextSocket = socket;
-			lock.notify();
-		}
-		Thread.yield();
-	}
-	
-	/**
-	 * Returns the next socket to process.  This will block the NGSession
-	 * thread until there's a socket to process or the NGSession has been
-	 * shut down.
-	 * 
-	 * @return the next socket to process, or <code>null</code> if the NGSession
-	 * has been shut down.
-	 */
-	private Socket nextSocket() {
-		Socket result = null;
-		synchronized(lock) {
-			result = nextSocket;
-			while (!done && result == null) {
-				try {
-					lock.wait();
-				} catch (InterruptedException e) {
-					done = true;
-				}
-				result = nextSocket;
-			}
-			nextSocket = null;
-		}
-		return (result);
-	}
-	
-	/**
-	 * The main NGSession loop.  This gets the next socket to process, runs
-	 * the nail for the socket, and loops until shut down.
-	 */
-	public void run() {
-	
-		updateThreadName(null);
-		
-		Socket socket = nextSocket();
-		while (socket != null) {
-			try {
-				// buffer for reading headers
-				byte[] lbuf = new byte[5];
-				java.io.DataInputStream sockin = new java.io.DataInputStream(socket.getInputStream());
-				java.io.OutputStream sockout = socket.getOutputStream();
-	
-				// client info - command line arguments and environment
-				List remoteArgs = new java.util.ArrayList();
-				Properties remoteEnv = new Properties();
-				
-				String cwd = null;			// working directory
-				String command = null;		// alias or class name
-				
-				// read everything from the client up to and including the command
-				while (command == null) {
-					sockin.readFully(lbuf);
-					long bytesToRead = LongUtils.fromArray(lbuf, 0);
-					char chunkType = (char) lbuf[4];
-					
-					byte[] b = new byte[(int) bytesToRead];
-					sockin.readFully(b);
-					String line = new String(b, "US-ASCII");
-	
-					switch(chunkType) {
-									
-						case NGConstants.CHUNKTYPE_ARGUMENT:
-									//	command line argument
-									remoteArgs.add(line);
-									break;
-
-						case NGConstants.CHUNKTYPE_ENVIRONMENT:
-									//	parse environment into property
-									int equalsIndex = line.indexOf('=');
-									if (equalsIndex > 0) {
-										remoteEnv.setProperty(
-												line.substring(0, equalsIndex),
-												line.substring(equalsIndex + 1));
-									}
-									String key = line.substring(0, equalsIndex);
-									break;
-									
-						case NGConstants.CHUNKTYPE_COMMAND:
-									// 	command (alias or classname)
-									command = line;
-									break;
-									
-						case NGConstants.CHUNKTYPE_WORKINGDIRECTORY:
-									//	client working directory
-									cwd = line;
-									break;
-									
-						default:	// freakout?
-					}
-				}
-	
-				updateThreadName(socket.getInetAddress().getHostAddress() + ": " + command);
-				
-				// can't create NGInputStream until we've received a command, because at
-				// that point the stream from the client will only include stdin and stdin-eof
-				// chunks
-				InputStream in = new NGInputStream(sockin);
-				PrintStream out = new PrintStream(new NGOutputStream(sockout, NGConstants.CHUNKTYPE_STDOUT));
-				PrintStream err = new PrintStream(new NGOutputStream(sockout, NGConstants.CHUNKTYPE_STDERR));
-				PrintStream exit = new PrintStream(new NGOutputStream(sockout, NGConstants.CHUNKTYPE_EXIT));
-	
-				// ThreadLocal streams for System.in/out/err redirection
-				((ThreadLocalInputStream) System.in).init(in);
-				((ThreadLocalPrintStream) System.out).init(out);
-				((ThreadLocalPrintStream) System.err).init(err);
-				
-				try {
-					Alias alias = server.getAliasManager().getAlias(command);
-					Class cmdclass = null;
-					if (alias != null) {
-						cmdclass = alias.getAliasedClass();
-					} else if (server.allowsNailsByClassName()) {
-						cmdclass = Class.forName(command);
-					} else {
-						cmdclass = server.getDefaultNailClass();
-					}
-
-					Object[] methodArgs = new Object[1];
-					Method mainMethod = null; // will be either main(String[]) or nailMain(NGContext)
-					String[] cmdlineArgs = (String[]) remoteArgs.toArray(new String[remoteArgs.size()]);
-					
-					try {
-						mainMethod = cmdclass.getMethod("nailMain", nailMainSignature);
-						NGContext context = new NGContext();
-						context.setArgs(cmdlineArgs);
-						context.in = in;
-						context.out = out;
-						context.err = err;
-						context.setCommand(command);
-						context.setExitStream(exit);
-						context.setNGServer(server);
-						context.setEnv(remoteEnv);
-						context.setInetAddress(socket.getInetAddress());
-						context.setPort(socket.getPort());
-						context.setWorkingDirectory(cwd);
-						methodArgs[0] = context;
-					} catch (NoSuchMethodException toDiscard) {
-						// that's ok - we'll just try main(String[]) next.
-					}
-					
-					if (mainMethod == null) {
-						mainMethod = cmdclass.getMethod("main", mainSignature);
-						methodArgs[0] = cmdlineArgs;
-					}
-					
-					if (mainMethod != null) {
-						server.nailStarted(cmdclass);
-                        NGSecurityManager.setExit(exit);
-
-						try {
-							mainMethod.invoke(null, methodArgs);
-						} catch (InvocationTargetException ite) {
-							throw(ite.getCause());
-						} catch (Throwable t) {
-							throw(t);
-						} finally {
-							server.nailFinished(cmdclass);
-						}
-						exit.println(0);
-					}