Commits

Meikel Brandmeyer committed 6a2be11

Move to gradle build system

Fixes #20

Comments (0)

Files changed (62)

+usePlugin 'clojure'
+
+group = 'vimclojure'
+version = '2.2.0-SNAPSHOT'
+
+aotCompile = true
+
+gradleHomeRepo repositories
+clojureSnapshotsRepo repositories
+
+repositories {
+    mavenCentral()
+}
+
+configurations {
+    clojure {
+        visible = false
+        description = 'Compile only configuration for clojure'
+    }
+}
+
+dependencies {
+    clojure 'org.clojure:clojure:1.0.0'
+}
+
+sourceSets.main.compileClasspath = configurations.clojure
+
+compileClojure.dependsOn compileJava
+
+defaultTasks 'build'
+
+configureClojarsDeploy(uploadArchives)
+
+// Install the Vim part of the plugin
+void installFiles(File directory, String pattern, File destination) {
+    destination.mkdirs()
+    ant.copy(todir: destination) {
+        fileset dir: directory, includes: pattern
+    }
+}
+
+task installVim << {
+    File installDir
+
+    if (hasProperty('vimdir')) {
+        installDir = new File(vimdir)
+    } else if (System.getProperty('os.name').toLowerCase().startsWith("win")) {
+        installDir = new File(System.getProperty('user.home') + "/vimfiles")
+    } else {
+        installDir = new File(Systm.getProperty('user.home') + "/.vim")
+    }
+
+    // The Vim files:
+    [ 'autoload', 'indent', 'syntax', 'ftdetect', 'ftplugin' ].each {
+        File subDir = new File(installDir, it)
+        installFiles it, '**/*.vim', subDir
+    }
+
+    // The Docs and other text files:
+    [ 'doc', 'ftplugin/clojure' ].each {
+        File subDir = new File(installDir, it)
+        installFiles it, '**/*.txt', subDir
+    }
+}

build.xml

-<project name="vimclojure" default="all"
-    xmlns:ivy="antlib:org.apache.ivy.ant">
-
-    <property name="src.dir" location="src"/>
-    <property name="classes.dir" location="classes"/>
-    <property name="build.dir" location="build"/>
-    <property name="lib.dir" location="lib"/>
-
-    <property name="jar.file" location="${build.dir}/vimclojure.jar"/>
-    <property name="srcjar.file" location="${build.dir}/vimclojure-source.jar"/>
-
-    <property name="current.version" value="2.1"/>
-
-    <property name="ivy.install.version" value="2.1.0-rc1"/>
-    <property name="ivy.jar.file" value="${lib.dir}/ivy.jar"/>
-
-    <property file="local.properties"/>
-
-    <target name="init" description="--> create build directories">
-        <tstamp/>
-        <mkdir dir="${classes.dir}"/>
-        <mkdir dir="${build.dir}"/>
-        <mkdir dir="${lib.dir}"/>
-    </target>
-
-    <condition property="ivy.available">
-        <available resource="org/apache/ivy/ant/antlib.xml"/>
-    </condition>
-
-    <condition property="ivy.disabled">
-        <isset property="clojure.jar"/>
-    </condition>
-
-    <condition property="ivy.needed">
-        <and>
-            <not><istrue value="${ivy.available}"/></not>
-            <not><istrue value="${ivy.disabled}"/></not>
-        </and>
-    </condition>
-
-    <target name="download-ivy" depends="init" if="ivy.needed"
-        description="--> download Ivy if necessary">
-        <get src="http://repo1.maven.org/maven2/org/apache/ivy/ivy/${ivy.install.version}/ivy-${ivy.install.version}.jar"
-            dest="${ivy.jar.file}"
-            usetimestamp="true"/>
-    </target>
-
-    <target name="install-ivy" depends="download-ivy" if="ivy.needed"
-        description="--> install Ivy if necessary">
-        <path id="ivy.lib.path">
-            <fileset dir="${lib.dir}" includes="*.jar"/>
-        </path>
-        <taskdef resource="org/apache/ivy/ant/antlib.xml"
-            uri="antlib:org.apache.ivy.ant"
-            classpathref="ivy.lib.path"/>
-    </target>
-
-    <target name="resolve" depends="install-ivy,init" unless="ivy.disabled"
-        description="--> resolve dependencies with Ivy">
-        <ivy:resolve />
-        <ivy:retrieve />
-    </target>
-
-    <target name="aot" depends="nailgun-server,resolve,init"
-        description="--> AOT compile clojure sources">
-        <java classname="clojure.lang.Compile" failonerror="true">
-            <classpath>
-                <path location="${classes.dir}"/>
-                <path location="${src.dir}"/>
-                <path location="${clojure.jar}"/>
-                <path location="${clojure-contrib.jar}"/>
-                <fileset dir="${lib.dir}" includes="**/*.jar"/>
-            </classpath>
-            <sysproperty key="clojure.compile.path" value="${classes.dir}"/>
-            <arg value="de.kotka.vimclojure.gencompletions"/>
-            <arg value="de.kotka.vimclojure.util"/>
-            <arg value="de.kotka.vimclojure.repl"/>
-            <arg value="de.kotka.vimclojure.backend"/>
-            <arg value="de.kotka.vimclojure.nails"/>
-        </java>
-    </target>
-
-    <target name="nailgun-server" depends="resolve,init"
-        description="--> compile the nailgun server">
-        <javac destdir="${classes.dir}" srcdir="${src.dir}"
-            includes="org/apache/**/*.java"/>
-        <javac destdir="${classes.dir}" srcdir="${src.dir}"
-            includes="com/martiansoftware/**/*.java"/>
-        <copy todir="${classes.dir}">
-            <fileset dir="${src.dir}" includes="com/martiansoftware/**"
-                excludes="com/martiansoftware/**/*.java"/>
-        </copy>
-    </target>
-
-    <target name="nailgun-client" if="nailgun-client"
-        description="--> compile the nailgun client using make">
-        <exec executable="make">
-            <arg value="${nailgun-client}"/>
-        </exec>
-    </target>
-
-    <target name="artifacts" depends="aot,nailgun-server"
-        description="--> create source and artifact jars">
-        <jar jarfile="${jar.file}">
-            <path location="README.txt"/>
-            <path location="LICENSE.txt"/>
-            <fileset dir="${classes.dir}" includes="de/kotka/**"/>
-            <fileset dir="${classes.dir}" includes="org/apache/**"/>
-            <fileset dir="${classes.dir}" includes="com/martiansoftware/**"/>
-            <fileset dir="${classes.dir}" includes="clojure/proxy/**"/>
-            <manifest>
-                <attribute name="Class-Path" value="."/>
-            </manifest>
-        </jar>
-        <jar jarfile="${srcjar.file}">
-            <path location="README.txt"/>
-            <path location="LICENSE.txt"/>
-            <fileset dir="${src.dir}" includes="**/*"/>
-        </jar>
-    </target>
-
-    <target name="all" depends="artifacts,nailgun-client"
-        description="--> build the whole project"/>
-
-    <target name="clean" description="--> clean generated files">
-        <delete dir="${classes.dir}"/>
-        <delete dir="${build.dir}"/>
-        <delete file="${nailgun-client}"/>
-    </target>
-
-    <target name="clean-lib" description="--> clean library files">
-        <delete dir="${lib.dir}"/>
-    </target>
-
-    <target name="clean-local" depends="install-ivy" unless="ivy.disabled"
-        description="--> clean local repository files">
-        <ivy:info />
-        <delete dir="${ivy.local.default.root}/${ivy.organisation}/${ivy.module}"/>
-    </target>
-
-    <target name="clean-all" depends="clean-lib,clean"
-        description="--> clean all project files"/>
-
-    <target name="install"
-        description="--> install the vim plugin">
-        <condition property="do.custom.install">
-            <isset property="vimdir"/>
-        </condition>
-        <condition property="do.windows.install">
-            <and>
-                <not><isset property="vimdir"/></not>
-                <os family="windows"/>
-            </and>
-        </condition>
-        <condition property="do.unix.install">
-            <and>
-                <not><isset property="vimdir"/></not>
-                <os family="unix"/>
-            </and>
-        </condition>
-        <antcall target="do-install"/>
-    </target>
-
-    <target name="do-install"
-        depends="do-windows-install,do-unix-install,do-custom-install"/>
-
-    <target name="do-windows-install" if="do.windows.install">
-        <property name="vimdir" location="${user.home}/vimfiles"/>
-        <antcall target="real-do-install"/>
-    </target>
-
-    <target name="do-unix-install" if="do.unix.install">
-        <property name="vimdir" location="${user.home}/.vim"/>
-        <antcall target="real-do-install"/>
-    </target>
-
-    <target name="do-custom-install" if="do.custom.install">
-        <antcall target="real-do-install"/>
-    </target>
-
-    <target name="real-do-install">
-        <mkdir dir="${vimdir}/autoload"/>
-        <mkdir dir="${vimdir}/doc"/>
-        <mkdir dir="${vimdir}/indent"/>
-        <mkdir dir="${vimdir}/syntax"/>
-        <mkdir dir="${vimdir}/ftdetect"/>
-        <mkdir dir="${vimdir}/ftplugin"/>
-        <mkdir dir="${vimdir}/ftplugin/clojure"/>
-
-        <copy todir="${vimdir}/autoload">
-            <fileset dir="autoload" includes="vimclojure.vim"/>
-        </copy>
-        <copy todir="${vimdir}/doc">
-            <fileset dir="doc" includes="clojure.txt"/>
-        </copy>
-        <copy todir="${vimdir}/indent">
-            <fileset dir="indent" includes="clojure.vim"/>
-        </copy>
-        <copy todir="${vimdir}/syntax">
-            <fileset dir="syntax" includes="clojure.vim"/>
-        </copy>
-        <copy todir="${vimdir}/ftdetect">
-            <fileset dir="ftdetect" includes="clojure.vim"/>
-        </copy>
-        <copy todir="${vimdir}/ftplugin">
-            <fileset dir="ftplugin" includes="clojure.vim"/>
-        </copy>
-        <copy todir="${vimdir}/ftplugin/clojure">
-            <fileset dir="ftplugin/clojure" includes="*.txt"/>
-        </copy>
-    </target>
-
-    <target name="publish"
-        description="--> publish artifacts in the shared repository">
-        <ivy:info />
-        <ivy:buildnumber
-            organisation="${ivy.organisation}"
-            module="${ivy.module}"
-            revision="${current.version}"/>
-        <ivy:publish
-            resolver="shared"
-            artifactspattern="${build.dir}/[artifact].[ext]"
-            pubrevision="${ivy.new.revision}"
-            update="true"
-            status="release"/>
-    </target>
-
-    <target name="publish-local"
-        description="--> publish artifacts in the local repository">
-        <tstamp>
-            <format property="now" pattern="yyyyMMddHHmmss"/>
-        </tstamp>
-        <ivy:info />
-        <ivy:publish
-            resolver="local"
-            artifactspattern="${build.dir}/[artifact].[ext]"
-            pubrevision="${now}"
-            pubdate="${now}"
-            status="integration"
-            forcedeliver="true"/>
-    </target>
-
-</project>

ivy.xml

-<ivy-module version="2.0">
-
-    <info organisation="de.kotka" module="vimclojure" status="integration"/>
-
-    <configurations>
-        <conf name="default"/>
-    </configurations>
-
-    <publications>
-        <artifact name="vimclojure" type="jar" conf="default"/>
-    </publications>
-
-    <dependencies>
-        <dependency org="org.clojure" name="clojure"
-            rev="fe6eddf66e8e6a66c9f462b125a7740e900dde21"
-            conf="default->compiled"/>
-        <dependency org="org.clojure.contrib" name="def"
-            rev="6fea921c91d453c750586c960ec92caacf4fa5e6"
-            conf="default->compiled"/>
-        <dependency org="org.clojure.contrib" name="pprint"
-            rev="6fea921c91d453c750586c960ec92caacf4fa5e6"
-            conf="default->compiled"/>
-    </dependencies>
-
-</ivy-module>

ivysettings.xml

-<ivysettings>
-
-    <!-- Load the standard Ivy settings. Which just extend them for Clojure. -->
-    <include url="${ivy.default.settings.dir}/ivysettings.xml"/>
-
-    <!-- Include the Kotka ivyrep for Clojure and Contrib -->
-    <include url="http://kotka.de/ivy/ivysettings.xml"/>
-
-</ivysettings>

src/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/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/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/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/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/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/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/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/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/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);
-			}
-		}
-
-		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/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;
-