001: /*
002:
003: Copyright 2004, Martian Software, Inc.
004:
005: Licensed under the Apache License, Version 2.0 (the "License");
006: you may not use this file except in compliance with the License.
007: You may obtain a copy of the License at
008:
009: http://www.apache.org/licenses/LICENSE-2.0
010:
011: Unless required by applicable law or agreed to in writing, software
012: distributed under the License is distributed on an "AS IS" BASIS,
013: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: See the License for the specific language governing permissions and
015: limitations under the License.
016:
017: */
018:
019: package com.martiansoftware.nailgun;
020:
021: import java.io.InputStream;
022: import java.io.PrintStream;
023: import java.net.InetAddress;
024: import java.net.NetworkInterface;
025: import java.util.Properties;
026:
027: /**
028: * <p>Provides quite a bit of potentially useful information to classes
029: * specifically written for NailGun. The <a href="NGServer.html">NailGun server</a> itself, its
030: * <a href="AliasManager.html">AliasManager</a>, the remote client's environment variables, and other
031: * information is available via this class. For all intents and purposes,
032: * the NGContext represents a single connection from a NailGun client.</p>
033: *
034: * If a class is written with a
035: *
036: * <pre><code>
037: * public static void nailMain(NGContext context)
038: * </code></pre>
039: *
040: * method, that method will be called by NailGun instead of the traditional
041: * <code>main(String[])</code> method normally used for programs. A fully populated <code>NGContext</code>
042: * object will then be provided to <code>nailMain()</code>.
043: *
044: * @author <a href="http://www.martiansoftware.com/contact.html">Marty Lamb </a>
045: */
046: public class NGContext {
047:
048: /**
049: * The remote host's environment variables
050: */
051: private Properties remoteEnvironment = null;
052:
053: /**
054: * The remote host's address
055: */
056: private InetAddress remoteHost = null;
057:
058: /**
059: * The port on the remote host that is communicating with NailGun
060: */
061: private int remotePort = 0;
062:
063: /**
064: * Command line arguments for the nail
065: */
066: private String[] args = null;
067:
068: /**
069: * A stream to which a client exit code can be printed
070: */
071: private PrintStream exitStream = null;
072:
073: /**
074: * The NGServer that accepted this connection
075: */
076: private NGServer server = null;
077:
078: /**
079: * The command that was issued for this connection
080: */
081: private String command = null;
082:
083: private String workingDirectory = null;
084:
085: /**
086: * The client's stdin
087: */
088: public InputStream in = null;
089:
090: /**
091: * The client's stdout
092: */
093: public PrintStream out = null;
094:
095: /**
096: * The client's stderr
097: */
098: public PrintStream err = null;
099:
100: /**
101: * Creates a new, empty NGContext
102: */
103: NGContext() {
104: super ();
105: }
106:
107: void setExitStream(PrintStream exitStream) {
108: this .exitStream = exitStream;
109: }
110:
111: void setPort(int remotePort) {
112: this .remotePort = remotePort;
113: }
114:
115: void setCommand(String command) {
116: this .command = command;
117: }
118:
119: /**
120: * Returns the command that was issued by the client (either an alias or the name of a class).
121: * This allows multiple aliases to point to the same class but result in different behaviors.
122: * @return the command issued by the client
123: */
124: public String getCommand() {
125: return (command);
126: }
127:
128: void setWorkingDirectory(String workingDirectory) {
129: this .workingDirectory = workingDirectory;
130: }
131:
132: /**
133: * Returns the current working directory of the client, as reported by the client.
134: * This is a String that will use the client's <code>File.separator</code> ('/' or '\'),
135: * which may differ from the separator on the server.
136: * @return the current working directory of the client
137: */
138: public String getWorkingDirectory() {
139: return (workingDirectory);
140: }
141:
142: void setEnv(Properties remoteEnvironment) {
143: this .remoteEnvironment = remoteEnvironment;
144: }
145:
146: void setInetAddress(InetAddress remoteHost) {
147: this .remoteHost = remoteHost;
148: }
149:
150: void setArgs(String[] args) {
151: this .args = args;
152: }
153:
154: void setNGServer(NGServer server) {
155: this .server = server;
156: }
157:
158: /**
159: * Returns a <code>java.util.Properties</code> object containing a copy
160: * of the client's environment variables
161: * @see java.util.Properties
162: * @return a <code>java.util.Properties</code> object containing a copy
163: * of the client's environment variables
164: */
165: public Properties getEnv() {
166: return (remoteEnvironment);
167: }
168:
169: /**
170: * Returns the file separator ('/' or '\\') used by the client's os.
171: * @return the file separator ('/' or '\\') used by the client's os.
172: */
173: public String getFileSeparator() {
174: return (remoteEnvironment.getProperty("NAILGUN_FILESEPARATOR"));
175: }
176:
177: /**
178: * Returns the path separator (':' or ';') used by the client's os.
179: * @return the path separator (':' or ';') used by the client's os.
180: */
181: public String getPathSeparator() {
182: return (remoteEnvironment.getProperty("NAILGUN_PATHSEPARATOR"));
183: }
184:
185: /**
186: * Returns the address of the client at the other side of this connection.
187: * @return the address of the client at the other side of this connection.
188: */
189: public InetAddress getInetAddress() {
190: return (remoteHost);
191: }
192:
193: /**
194: * Returns the command line arguments for the command
195: * implementation (nail) on the server.
196: * @return the command line arguments for the command
197: * implementation (nail) on the server.
198: */
199: public String[] getArgs() {
200: return (args);
201: }
202:
203: /**
204: * Returns the NGServer that accepted this connection
205: * @return the NGServer that accepted this connection
206: */
207: public NGServer getNGServer() {
208: return (server);
209: }
210:
211: /**
212: * Sends an exit command with the specified exit code to
213: * the client. The client will exit immediately with
214: * the specified exit code; you probably want to return
215: * from nailMain immediately after calling this.
216: *
217: * @param exitCode the exit code with which the client
218: * should exit
219: */
220: public void exit(int exitCode) {
221: exitStream.println(exitCode);
222: }
223:
224: /**
225: * Returns the port on the client connected to the NailGun
226: * server.
227: * @return the port on the client connected to the NailGun
228: * server.
229: */
230: public int getPort() {
231: return (remotePort);
232: }
233:
234: /**
235: * Throws a <code>java.lang.SecurityException</code> if the client is not
236: * connected via the loopback address.
237: */
238: public void assertLoopbackClient() {
239: if (!getInetAddress().isLoopbackAddress()) {
240: throw (new SecurityException(
241: "Client is not at loopback address."));
242: }
243: }
244:
245: /**
246: * Throws a <code>java.lang.SecurityException</code> if the client is not
247: * connected from the local machine.
248: */
249: public void assertLocalClient() {
250: NetworkInterface iface = null;
251: try {
252: iface = NetworkInterface.getByInetAddress(getInetAddress());
253: } catch (java.net.SocketException se) {
254: throw (new SecurityException(
255: "Unable to determine if client is local. Assuming he isn't."));
256: }
257:
258: if ((iface == null) && (!getInetAddress().isLoopbackAddress())) {
259: throw (new SecurityException("Client is not local."));
260: }
261: }
262: }
|