pax_global_header 0000666 0000000 0000000 00000000064 12056774730 0014525 g ustar 00root root 0000000 0000000 52 comment=cd3ff159548c2ba60fcd1f3341611b1bf6e8997b
nailgun-nailgun-all-0.9.1/ 0000775 0000000 0000000 00000000000 12056774730 0015372 5 ustar 00root root 0000000 0000000 nailgun-nailgun-all-0.9.1/.gitignore 0000664 0000000 0000000 00000000072 12056774730 0017361 0 ustar 00root root 0000000 0000000 /nailgun-server/target/
/nailgun-examples/target/
/target/ nailgun-nailgun-all-0.9.1/Makefile 0000664 0000000 0000000 00000001773 12056774730 0017042 0 ustar 00root root 0000000 0000000 # This Makefile has only been tested on linux. It uses
# MinGW32 to cross-compile for windows. To install and
# configure MinGW32 on linux, see http://www.mingw.org
# This is where the mingw32 compiler exists in Ubuntu 8.04.
# Your compiler location may vary.
WIN32_CC=/usr/bin/i586-mingw32msvc-gcc
CC=gcc
CFLAGS=-Wall -pedantic -s -O3
SRCDIR=nailgun-client
ng: ${SRCDIR}/ng.c
@echo "Building ng client. To build a Windows binary, type 'make ng.exe'"
${CC} ${CFLAGS} -o ng ${SRCDIR}/ng.c
install: ng
install ng /usr/local/bin
ng.exe: ${SRCDIR}/ng.c
${WIN32_CC} -o ng.exe ${SRCDIR}/ng.c -lwsock32 -O3 ${CFLAGS}
# any idea why the command line is so sensitive to the order of
# the arguments? If CFLAGS is at the beginning, it won't link.
clean:
@echo ""
@echo "If you have a Windows binary, 'make clean' won't delete it."
@echo "You must remove this manually. Most users won't have MinGW"
@echo "installed - so I'd rather not delete something you can't rebuild."
@echo ""
rm -f ng
# rm -f ng.exe
nailgun-nailgun-all-0.9.1/README.md 0000664 0000000 0000000 00000001221 12056774730 0016645 0 ustar 00root root 0000000 0000000 nailgun
=======
Nailgun is a client, protocol, and server for running Java programs from
the command line without incurring the JVM startup overhead.
Programs run in the server (which is implemented in Java), and are
triggered by the client (written in C), which handles all I/O.
The server and examples are built using maven. From the project directory,
"mvn clean install" will do it.
The client is built using make. From the project directory,
"make && sudo make install" will do it. To create the windows client
you will additionally need to "make ng.exe".
For more information, see [the nailgun website](http://martiansoftware.com/nailgun/).
nailgun-nailgun-all-0.9.1/nailgun-client/ 0000775 0000000 0000000 00000000000 12056774730 0020303 5 ustar 00root root 0000000 0000000 nailgun-nailgun-all-0.9.1/nailgun-client/ng.c 0000664 0000000 0000000 00000046460 12056774730 0021065 0 ustar 00root root 0000000 0000000 /*
Copyright 2004-2012, 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.
*/
/**
* @author Marty Lamb
* @author Pete Kirkham (Win32 port)
*/
#ifdef WIN32
#include Provides quite a bit of potentially useful information to classes
* specifically written for NailGun. The NailGun server itself, its
* AliasManager, 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. Listens for new connections from NailGun clients and launches NGSession
* threads to process them. 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. Shuts down the server. The server will stop listening and its thread
* will finish. Any running nails will be allowed to finish. Any nails that provide a
* mycommand
" command to the com.yourdomain.yourpackage.YourClass
* class. Obviously, it's a lot easier to type "ng mycommand
" than the fully
* qualified class name.
*
* @author Marty Lamb
*/
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 main()
or nailMain()
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 Class
object providing a static main()
or nailMain()
method
* for this command.
* @return the Class
object providing a static main()
or nailMain()
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 not
* 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 names - no other fields are compared.
* @see Comparable#compareTo(Object)
*/
public int compareTo(Object o) {
return (name.compareTo(((Alias) o).getName()));
}
}
nailgun-nailgun-all-0.9.1/nailgun-server/src/main/java/com/martiansoftware/nailgun/AliasManager.java0000664 0000000 0000000 00000010346 12056774730 0033603 0 ustar 00root root 0000000 0000000 /*
Copyright 2004-2012, 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 Alias for more details.
*
* @author Marty Lamb
*/
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:
*
each of
* which may have an optional
* [alias name]=[fully qualified classname]
*
* For example, to create an alias called "
* [alias name].desc=[alias description]
myprog
" for class
* com.mydomain.myapp.MyProg
, the following properties would be
* defined:
*
*
*
* @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));
}
}
nailgun-nailgun-all-0.9.1/nailgun-server/src/main/java/com/martiansoftware/nailgun/NGConstants.java 0000664 0000000 0000000 00000006510 12056774730 0033456 0 ustar 00root root 0000000 0000000 /*
Copyright 2004-2012, 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 Marty Lamb
*/
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 byte CHUNKTYPE_ARGUMENT = 'A';
/**
* Chunk type marker for client environment variables
*/
public static final byte CHUNKTYPE_ENVIRONMENT = 'E';
/**
* Chunk type marker for the command (alias or class)
*/
public static final byte CHUNKTYPE_COMMAND = 'C';
/**
* Chunk type marker for client working directory
*/
public static final byte CHUNKTYPE_WORKINGDIRECTORY = 'D';
/**
* Chunk type marker for stdin
*/
public static final byte CHUNKTYPE_STDIN = '0';
/**
* Chunk type marker for the end of stdin
*/
public static final byte CHUNKTYPE_STDIN_EOF = '.';
/**
* Chunk type marker for stdout
*/
public static final byte CHUNKTYPE_STDOUT = '1';
/**
* Chunk type marker for stderr
*/
public static final byte CHUNKTYPE_STDERR = '2';
/**
* Chunk type marker for client exit chunks
*/
public static final byte CHUNKTYPE_EXIT = 'X';
/**
* Chunk type marker for a "startinput" chunk. This chunk type is sent from
* the server to the client and indicates that the client should begin
* sending stdin to the server. It is automatically sent the first time the
* client's inputstream is read.
*/
public static final byte CHUNKTYPE_STARTINPUT = 'S';
/**
* Server version number
*/
public static final String VERSION;
/**
* Returns the Nailgun version number
*
* @return the Nailgun version number
*/
public static String getVersion() {
String result = "[unknown]";
return result;
}
/**
* Loads the version number from a file generated by Maven.
*/
static {
Properties props = new Properties();
try {
props.load(NGConstants.class.getResourceAsStream("/META-INF/maven/com.martiansoftware/nailgun-server/pom.properties"));
} catch (Exception e) {
System.err.println("Unable to load nailgun-version.properties.");
}
VERSION = props.getProperty("version", "[UNKNOWN]");
}
}
nailgun-nailgun-all-0.9.1/nailgun-server/src/main/java/com/martiansoftware/nailgun/NGContext.java 0000664 0000000 0000000 00000015344 12056774730 0033133 0 ustar 00root root 0000000 0000000 /*
Copyright 2004-2012, 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;
/**
* myprog=com.mydomain.myapp.MyProg
*myprog.desc=Runs my program.
*
*
* method, that method will be called by NailGun instead of the traditional
*
* public static void nailMain(NGContext context)
*
main(String[])
method normally used for programs. A fully populated NGContext
* object will then be provided to nailMain()
.
*
* @author Marty Lamb
*/
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 File.separator
('/' 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 java.util.Properties
object containing a copy
* of the client's environment variables
* @see java.util.Properties
* @return a java.util.Properties
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 java.lang.SecurityException
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 java.lang.SecurityException
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."));
}
}
} NGExitException.java 0000664 0000000 0000000 00000007346 12056774730 0034223 0 ustar 00root root 0000000 0000000 nailgun-nailgun-all-0.9.1/nailgun-server/src/main/java/com/martiansoftware/nailgun /*
* This class is based upon org.apache.tools.ant.ExitException and is
* subject to the following:
*
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 2001-2003 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "Ant" and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* System.out
at the time of the NGServer's creation
*/
public final PrintStream out = System.out;
/**
* System.err
at the time of the NGServer's creation
*/
public final PrintStream err = System.err;
/**
* System.in
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 with the specified session pool size. This does
* not cause the server to start listening. To do so, create a new
* Thread
wrapping this
* NGServer
and start it.
*
* @param addr the address at which to listen, or
* null
to bind to all local addresses
* @param port the port on which to listen.
* @param sessionPoolSize the max number of idle sessions allowed by the
* pool
*/
public NGServer(InetAddress addr, int port, int sessionPoolSize) {
init(addr, port, sessionPoolSize);
}
/**
* Creates a new NGServer that will listen at the specified address and on
* the specified port with the default session pool size. This does
* not cause the server to start listening. To do so, create a new
* Thread
wrapping this
* NGServer
and start it.
*
* @param addr the address at which to listen, or
* null
to bind to all local addresses
* @param port the port on which to listen.
* @param sessionPoolSize the max number of idle sessions allowed by the
* pool
*/
public NGServer(InetAddress addr, int port) {
init(addr, port, DEFAULT_SESSIONPOOLSIZE);
}
/**
* Creates a new NGServer that will listen on the default port (defined in
* NGConstants.DEFAULT_PORT
). This does not cause the
* server to start listening. To do so, create a new
* Thread
wrapping this
* NGServer
and start it.
*/
public NGServer() {
init(null, NGConstants.DEFAULT_PORT, DEFAULT_SESSIONPOOLSIZE);
}
/**
* Sets up the NGServer internals
*
* @param addr the InetAddress to bind to
* @param port the port on which to listen
* @param sessionPoolSize the max number of idle sessions allowed by the
* pool
*/
private void init(InetAddress addr, int port, int sessionPoolSize) {
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, sessionPoolSize);
}
/**
* 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
* null
, 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
* null
, 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
* java.util.Map
, keyed by class name, with NailStats 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);
}
/**
*
method
* will have this method called with this NGServer as its sole
* parameter.public static void nailShutdown(NGServer)
NGServer
. A single optional argument is valid, specifying
* the port on which this
* NGServer
should listen. If omitted,
* NGServer.DEFAULT_PORT
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, DEFAULT_SESSIONPOOLSIZE);
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 "
+ NGConstants.VERSION
+ " 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 Marty
* Lamb
*/
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.");
}
}
}
}
nailgun-nailgun-all-0.9.1/nailgun-server/src/main/java/com/martiansoftware/nailgun/NGSession.java 0000664 0000000 0000000 00000027147 12056774730 0033136 0 ustar 00root root 0000000 0000000 /*
Copyright 2004-2012, 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.DataInputStream;
import java.io.DataOutputStream;
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;
/**
* 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 Marty Lamb
*/
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
* null
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 {
DataInputStream sockin = new DataInputStream(socket.getInputStream());
DataOutputStream sockout = new DataOutputStream(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) {
int bytesToRead = sockin.readInt();
byte chunkType = sockin.readByte();
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, sockout);
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);
}
} catch (NGExitException exitEx) {
exit.println(exitEx.getStatus());
server.out.println(Thread.currentThread().getName() + " exited with status " + exitEx.getStatus());
} catch (Throwable t) {
t.printStackTrace();
exit.println(NGConstants.EXIT_EXCEPTION); // remote exception constant
}
sockout.flush();
socket.close();
} catch (Throwable t) {
t.printStackTrace();
}
((ThreadLocalInputStream) System.in).init(null);
((ThreadLocalPrintStream) System.out).init(null);
((ThreadLocalPrintStream) System.err).init(null);
updateThreadName(null);
sessionPool.give(this);
socket = nextSocket();
}
// server.out.println("Shutdown NGSession " + instanceNumber);
}
/**
* Updates the current thread name (useful for debugging).
*/
private void updateThreadName(String detail) {
setName("NGSession " + instanceNumber + ": " + ((detail == null) ? "(idle)" : detail));
}
}
NGSessionPool.java 0000664 0000000 0000000 00000005663 12056774730 0033710 0 ustar 00root root 0000000 0000000 nailgun-nailgun-all-0.9.1/nailgun-server/src/main/java/com/martiansoftware/nailgun /*
Copyright 2004-2012, 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 NGSession pooling functionality. One parameter, "maxIdle",
* governs its behavior by setting the maximum number of idle NGSession
* threads it will allow. It creates a pool of size maxIdle - 1, because
* one NGSession is kept "on deck" by the NGServer in order to eke out
* a little extra responsiveness.
*
* @author Marty Lamb
*/
class NGSessionPool {
/**
* number of sessions to store in the pool
*/
int poolSize = 0;
/**
* the pool itself
*/
NGSession[] pool = null;
/**
* The number of sessions currently in the pool
*/
int poolEntries = 0;
/**
* reference to server we're working for
*/
NGServer server = null;
/**
* have we been shut down?
*/
boolean done = false;
/**
* synchronization object
*/
private Object lock = new Object();
/**
* Creates a new NGSessionRunner operating for the specified server, with
* the specified number of threads
* @param server the server to work for
* @param poolsize the maximum number of idle threads to allow
*/
NGSessionPool(NGServer server, int poolsize) {
this.server = server;
this.poolSize = Math.min(0, poolsize);
pool = new NGSession[poolSize];
poolEntries = 0;
}
/**
* Returns an NGSession from the pool, or creates one if necessary
* @return an NGSession ready to work
*/
NGSession take() {
NGSession result;
synchronized(lock) {
if (poolEntries == 0) {
result = new NGSession(this, server);
result.start();
} else {
--poolEntries;
result = pool[poolEntries];
}
}
return (result);
}
/**
* Returns an NGSession to the pool. The pool may choose to shutdown
* the thread if the pool is full
* @param session the NGSession to return to the pool
*/
void give(NGSession session) {
boolean shutdown = false;
synchronized(lock) {
if (done || poolEntries == poolSize) {
shutdown = true;
} else {
pool[poolEntries] = session;
++poolEntries;
}
}
if (shutdown) session.shutdown();
}
/**
* Shuts down the pool. Running nails are allowed to finish.
*/
void shutdown() {
done = true;
synchronized(lock) {
while (poolEntries > 0) {
take().shutdown();
}
}
}
}
nailgun-nailgun-all-0.9.1/nailgun-server/src/main/java/com/martiansoftware/nailgun/NailStats.java 0000664 0000000 0000000 00000006222 12056774730 0033157 0 ustar 00root root 0000000 0000000 /*
Copyright 2004-2012, 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;
/**
* Collects and provides statistics on a nail.
* * @author Marty Lamb */ public class NailStats implements Cloneable { private Class nailclass; private long runCounter; private long refCounter; private Object lock; /** * Creates a new NailStats object for the specified class * @param nailclass the class for which we'll collect statistics */ NailStats(Class nailclass) { this.nailclass = nailclass; runCounter = 0; refCounter = 0; lock = new Object(); } /** * Logs the fact that an instance of this nail has started */ void nailStarted() { synchronized(lock) { ++runCounter; ++refCounter; } } /** * Logs the fact that an instance of this nail has finished */ void nailFinished() { synchronized(lock) { --refCounter; } } /** * Returns the number of times this nail has been run. Nails * that have started but not yet finished are included in this * number. * @return the number of times this nail has been run. */ public long getRunCount() { return (runCounter); } /** * Returns the number of sessions currently running this nail. * @return the number of sessions currently running this nail. */ public long getRefCount() { return (refCounter); } /** * Returns the class for which we're tracking statistics * @return the class for which we're tracking statistics */ public Class getNailClass() { return (nailclass); } /** * @see java.lang.Object#hashCode */ public int hashCode() { return (nailclass.hashCode()); } /** * Returns true iff the specifiedNailStats
object
* is tracking the same class.
* @param o the NailStats object to check
* @return true iff the specified NailStats
object
* is tracking the same class.
*/
public boolean equals(Object o) {
NailStats other = (NailStats) o;
return (nailclass.equals(other.nailclass));
}
/**
* Creates a copy of this NailStats
object.
* @return a copy of this NailStats
object.
*/
public Object clone() {
Object result = null;
try {
result = super.clone();
} catch (CloneNotSupportedException toDiscard) {}
return (result);
}
/**
* Returns a String representation of this NailStats
* object, in the form "classname: runcount/refcount".
* *return a String representation of this NailStats
* object.
*/
public String toString() {
return (nailclass.getName() + ": " + getRunCount() + "/" + getRefCount());
}
}
ThreadLocalInputStream.java 0000664 0000000 0000000 00000007764 12056774730 0035570 0 ustar 00root root 0000000 0000000 nailgun-nailgun-all-0.9.1/nailgun-server/src/main/java/com/martiansoftware/nailgun /*
Copyright 2004-2012, 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;
import java.io.InputStream;
/**
* The class name is pretty descriptive. This creates an InputStream
* much like a FilterInputStream, but with the wrapped InputStream
* being local to the current Thread. By setting System.in to a
* ThreadLocalInputStream, different Threads can read from different
* InputStreams simply by using System.in. Of course, the init()
* method must be called by the Thread that wishes to use the
* wrapped stream.
*
* @author Marty Lamb
*/
class ThreadLocalInputStream extends InputStream {
/**
* The InputStreams for the various threads
*/
private InheritableThreadLocal streams = null;
private InputStream defaultInputStream = null;
/**
* @param defaultInputStream the InputStream that will be used if the
* current thread has not called init()
*/
ThreadLocalInputStream(InputStream defaultInputStream) {
super();
streams = new InheritableThreadLocal();
this.defaultInputStream = defaultInputStream;
init(null);
}
/**
* Sets the InputStream for the current thread
* @param streamForCurrentThread the InputStream for the current thread
*/
void init(InputStream streamForCurrentThread) {
streams.set(streamForCurrentThread);
}
/**
* Returns this thread's InputStream
* @return this thread's InputStream
*/
InputStream getInputStream() {
InputStream result = (InputStream) streams.get();
return ((result == null) ? defaultInputStream : result);
}
// BEGIN delegated java.io.InputStream methods
/**
* @see java.io.InputStream#available()
*/
public int available() throws IOException {
return (getInputStream().available());
}
/**
* @see java.io.InputStream#close()
*/
public void close() throws IOException {
getInputStream().close();
}
/**
* @see java.io.InputStream#mark(int)
*/
public void mark(int readlimit) {
getInputStream().mark(readlimit);
}
/**
* @see java.io.InputStream#markSupported()
*/
public boolean markSupported() {
return (getInputStream().markSupported());
}
/**
* @see java.io.InputStream#read()
*/
public int read() throws IOException {
return (getInputStream().read());
}
/**
* @see java.io.InputStream#read(byte[])
*/
public int read(byte[] b) throws IOException {
return (getInputStream().read(b));
}
/**
* @see java.io.InputStream#read(byte[],int,int)
*/
public int read(byte[] b, int off, int len) throws IOException {
return (getInputStream().read(b, off, len));
}
/**
* @see java.io.InputStream#reset()
*/
public void reset() throws IOException {
getInputStream().reset();
}
/**
* @see java.io.InputStream#skip(long)
*/
public long skip(long n) throws IOException {
return (getInputStream().skip(n));
}
// BEGIN delegated java.io.InputStream methods
// Note: Should java.lang.Object methods be delegated? If not, and
// someone synchronizes on this stream, processes might be blocked
// that shouldn't be. It would certainly be stupid to delegate
// finalize(). Not so clear are hashcode(), equals(), notify(), and
// the wait() methods.
}
ThreadLocalPrintStream.java 0000664 0000000 0000000 00000014340 12056774730 0035551 0 ustar 00root root 0000000 0000000 nailgun-nailgun-all-0.9.1/nailgun-server/src/main/java/com/martiansoftware/nailgun /*
Copyright 2004-2012, 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;
import java.io.PrintStream;
/**
* The class name is pretty descriptive. This creates a PrintStream
* much like a FilterOutputStream, but with the wrapped PrintStream
* being local to the current Thread. By setting System.out to a
* ThreadLocalPrintStream, different Threads can write to different
* PrintStreams simply by using System.out. Of course, the init()
* method must be called by the Thread that wishes to use the
* wrapped stream.
*
* @author Marty Lamb
*/
class ThreadLocalPrintStream extends PrintStream {
/**
* The PrintStreams for the various threads
*/
private InheritableThreadLocal streams = null;
private PrintStream defaultPrintStream = null;
/**
* Creates a new InheritedThreadLocalPrintStream
* @param defaultPrintStream the PrintStream that will be used if the
* current thread has not called init()
*/
public ThreadLocalPrintStream(PrintStream defaultPrintStream) {
super(defaultPrintStream);
streams = new InheritableThreadLocal();
this.defaultPrintStream = defaultPrintStream;
init(null);
}
/**
* Sets the PrintStream for the current thread
* @param streamForCurrentThread the PrintStream for the current thread
*/
void init(PrintStream streamForCurrentThread) {
streams.set(streamForCurrentThread);
}
/**
* Returns this thread's PrintStream
* @return this thread's PrintStream
*/
PrintStream getPrintStream() {
PrintStream result = (PrintStream) streams.get();
return ((result == null) ? defaultPrintStream : result);
}
// BEGIN delegated java.io.PrintStream methods
/**
* @see java.io.PrintStream#checkError()
*/
public boolean checkError() {
return (getPrintStream().checkError());
}
/**
* @see java.io.PrintStream#close()
*/
public void close() {
getPrintStream().close();
}
/**
* @see java.io.PrintStream#flush()
*/
public void flush() {
getPrintStream().flush();
}
/**
* @see java.io.PrintStream#print(boolean)
*/
public void print(boolean b) {
getPrintStream().print(b);
}
/**
* @see java.io.PrintStream#print(char)
*/
public void print(char c) {
getPrintStream().print(c);
}
/**
* @see java.io.PrintStream#print(char[])
*/
public void print(char[] s) {
getPrintStream().print(s);
}
/**
* @see java.io.PrintStream#print(double)
*/
public void print(double d) {
getPrintStream().print(d);
}
/**
* @see java.io.PrintStream#print(float)
*/
public void print(float f) {
getPrintStream().print(f);
}
/**
* @see java.io.PrintStream#print(int)
*/
public void print(int i) {
getPrintStream().print(i);
}
/**
* @see java.io.PrintStream#print(long)
*/
public void print(long l) {
getPrintStream().print(l);
}
/**
* @see java.io.PrintStream#print(Object)
*/
public void print(Object obj) {
getPrintStream().print(obj);
}
/**
* @see java.io.PrintStream#print(String)
*/
public void print(String s) {
getPrintStream().print(s);
}
/**
* @see java.io.PrintStream#println()
*/
public void println() {
getPrintStream().println();
}
/**
* @see java.io.PrintStream#println(boolean)
*/
public void println(boolean x) {
getPrintStream().println(x);
}
/**
* @see java.io.PrintStream#println(char)
*/
public void println(char x) {
getPrintStream().println(x);
}
/**
* @see java.io.PrintStream#println(char[])
*/
public void println(char[] x) {
getPrintStream().println(x);
}
/**
* @see java.io.PrintStream#println(double)
*/
public void println(double x) {
getPrintStream().println(x);
}
/**
* @see java.io.PrintStream#println(float)
*/
public void println(float x) {
getPrintStream().println(x);
}
/**
* @see java.io.PrintStream#println(int)
*/
public void println(int x) {
getPrintStream().println(x);
}
/**
* @see java.io.PrintStream#println(long)
*/
public void println(long x) {
getPrintStream().println(x);
}
/**
* @see java.io.PrintStream#println(Object)
*/
public void println(Object x) {
getPrintStream().println(x);
}
/**
* @see java.io.PrintStream#println(String)
*/
public void println(String x) {
getPrintStream().println(x);
}
/**
* @see java.io.PrintStream#write(byte[],int,int)
*/
public void write(byte[] buf, int off, int len) {
getPrintStream().write(buf, off, len);
}
/**
* @see java.io.PrintStream#write(int)
*/
public void write(int b) {
getPrintStream().write(b);
}
// END delegated java.io.PrintStream methods
// BEGIN delegated java.io.FilterOutputStream methods
/**
* @see java.io.FilterOutputStream#write(byte[])
*/
public void write(byte[] b) throws IOException {
getPrintStream().write(b);
}
// END delegated java.io.FilterOutputStream methods
// Note: Should java.lang.Object methods be delegated? If not, and
// someone synchronizes on this stream, processes might be blocked
// that shouldn't be. It would certainly be stupid to delegate
// finalize(). Not so clear are hashcode(), equals(), notify(), and
// the wait() methods.
}
nailgun-nailgun-all-0.9.1/nailgun-server/src/main/java/com/martiansoftware/nailgun/builtins/ 0000775 0000000 0000000 00000000000 12056774730 0032241 5 ustar 00root root 0000000 0000000 DefaultNail.java 0000664 0000000 0000000 00000002351 12056774730 0035216 0 ustar 00root root 0000000 0000000 nailgun-nailgun-all-0.9.1/nailgun-server/src/main/java/com/martiansoftware/nailgun/builtins /*
Copyright 2004-2012, 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.builtins;
import com.martiansoftware.nailgun.NGContext;
import com.martiansoftware.nailgun.NGConstants;
/**
* The default nail class used by the server when an invalid command (nonexisting
* classname or alias) is issued. This simply displays an error message to the
* client's stdout and has the client exit with value NGConstants.EXIT_NOSUCHCOMMAND.
*
* @author Marty Lamb
*/
public class DefaultNail {
public static void nailMain(NGContext context) {
context.err.println("No such command: " + context.getCommand());
context.exit(NGConstants.EXIT_NOSUCHCOMMAND);
}
}
NGAlias.java 0000664 0000000 0000000 00000005403 12056774730 0034305 0 ustar 00root root 0000000 0000000 nailgun-nailgun-all-0.9.1/nailgun-server/src/main/java/com/martiansoftware/nailgun/builtins /*
Copyright 2004-2012, 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.builtins;
import java.util.Iterator;
import java.util.Set;
import com.martiansoftware.nailgun.Alias;
import com.martiansoftware.nailgun.NGContext;
import com.martiansoftware.nailgun.NGServer;
/**
* Provides a means to view and add aliases. This is aliased by default
* to the command "ng-alias
".
No command line validation is performed. If you trigger an exception, * your client will display it.
* *To view the current alias list, issue the command: *
ng-alias
* with no arguments.
*
* To add or replace an alias, issue the command: *
ng-alias [alias name] [fully qualified aliased class name]
*
*
* @author Marty Lamb
*/
public class NGAlias {
private static String padl(String s, int len) {
StringBuffer buf = new StringBuffer(s);
while(buf.length() < len) buf.append(" ");
return (buf.toString());
}
public static void nailMain(NGContext context) throws ClassNotFoundException {
String[] args = context.getArgs();
NGServer server = context.getNGServer();
if (args.length == 0) {
Set aliases = server.getAliasManager().getAliases();
// let's pad this nicely. first, find the longest alias
// name. then pad the others to that width.
int maxAliasLength = 0;
int maxClassnameLength = 0;
for (Iterator i = aliases.iterator(); i.hasNext();) {
Alias alias = (Alias) i.next();
maxAliasLength = Math.max(maxAliasLength, alias.getName().length());
maxClassnameLength = Math.max(maxClassnameLength, alias.getAliasedClass().getName().length());
}
for (Iterator i = aliases.iterator(); i.hasNext();) {
Alias alias = (Alias) i.next();
context.out.println(padl(alias.getName(), maxAliasLength)
+ "\t"
+ padl(alias.getAliasedClass().getName(), maxClassnameLength));
context.out.println(padl("", maxAliasLength) + "\t" + alias.getDescription());
context.out.println();
}
} else if (args.length == 2) {
server.getAliasManager().addAlias(new Alias(args[0], "", Class.forName(args[1])));
}
}
}
NGClasspath.java 0000664 0000000 0000000 00000005443 12056774730 0035202 0 ustar 00root root 0000000 0000000 nailgun-nailgun-all-0.9.1/nailgun-server/src/main/java/com/martiansoftware/nailgun/builtins /*
Copyright 2004-2012, 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.builtins;
import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import com.martiansoftware.nailgun.NGContext;
/**
* Provides a means to display and add to the system classpath at runtime. * If called with no arguments, the classpath is displayed. Otherwise, each * argument is turned into a java.io.File and added to the classpath. Relative * paths will be resolved relative to the directory in which the nailgun server * is running. This is very likely to change in the future.
* *This is aliased by default to the command "ng-cp
".
Displays all NailStats tracked by the server.
* *This can be run standalone with no arguments. It will also run automatically
* upon NGServer
shutdown, sending its output to the server's System.out
.
This is aliased by default to the command "ng-stats
".
Shuts down the currently running server.
* *This is aliased by default to the command "ng-stop
".