001: /*
002: * Copyright 1999-2004 The Apache Software Foundation
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: /* @version $Id: SimpleDaemon.java 155409 2005-02-26 12:57:06Z dirkv $ */
018:
019: package org.apache.commons.daemon;
020:
021: import java.io.*;
022: import java.net.*;
023: import java.text.SimpleDateFormat;
024: import java.util.Date;
025: import java.util.Enumeration;
026: import java.util.Vector;
027: import org.apache.commons.daemon.Daemon;
028: import org.apache.commons.daemon.DaemonController;
029: import org.apache.commons.daemon.DaemonContext;
030:
031: public class SimpleDaemon implements Daemon, Runnable {
032:
033: private ServerSocket server = null;
034: private Thread thread = null;
035: private DaemonController controller = null;
036: private boolean stopping = false;
037: private String directory = null;
038: private Vector handlers = null;
039:
040: public SimpleDaemon() {
041: super ();
042: System.err.println("SimpleDaemon: instance " + this .hashCode()
043: + " created");
044: this .handlers = new Vector();
045: }
046:
047: protected void finalize() {
048: System.err.println("SimpleDaemon: instance " + this .hashCode()
049: + " garbage collected");
050: }
051:
052: /**
053: * init and destroy were added in jakarta-tomcat-daemon.
054: */
055: public void init(DaemonContext context) throws Exception {
056: System.err.println("SimpleDaemon: instance " + this .hashCode()
057: + " init");
058:
059: int port = 1200;
060:
061: String[] a = context.getArguments();
062:
063: if (a.length > 0)
064: port = Integer.parseInt(a[0]);
065: if (a.length > 1)
066: this .directory = a[1];
067: else
068: this .directory = "/tmp";
069:
070: /* Dump a message */
071: System.err.println("SimpleDaemon: loading on port " + port);
072:
073: /* Set up this simple daemon */
074: this .controller = context.getController();
075: this .server = new ServerSocket(port);
076: this .thread = new Thread(this );
077: }
078:
079: public void start() {
080: /* Dump a message */
081: System.err.println("SimpleDaemon: starting");
082:
083: /* Start */
084: this .thread.start();
085: }
086:
087: public void stop() throws IOException, InterruptedException {
088: /* Dump a message */
089: System.err.println("SimpleDaemon: stopping");
090:
091: /* Close the ServerSocket. This will make our thread to terminate */
092: this .stopping = true;
093: this .server.close();
094:
095: /* Wait for the main thread to exit and dump a message */
096: this .thread.join(5000);
097: System.err.println("SimpleDaemon: stopped");
098: }
099:
100: public void destroy() {
101: System.err.println("SimpleDaemon: instance " + this .hashCode()
102: + " destroy");
103: }
104:
105: public void run() {
106: int number = 0;
107:
108: System.err.println("SimpleDaemon: started acceptor loop");
109: try {
110: while (!this .stopping) {
111: Socket socket = this .server.accept();
112: Handler handler = new Handler(socket, this ,
113: this .controller);
114: handler.setConnectionNumber(number++);
115: handler.setDirectoryName(this .directory);
116: new Thread(handler).start();
117: }
118: } catch (IOException e) {
119: /* Don't dump any error message if we are stopping. A IOException
120: is generated when the ServerSocket is closed in stop() */
121: if (!this .stopping)
122: e.printStackTrace(System.err);
123: }
124:
125: /* Terminate all handlers that at this point are still open */
126: Enumeration openhandlers = this .handlers.elements();
127: while (openhandlers.hasMoreElements()) {
128: Handler handler = (Handler) openhandlers.nextElement();
129: System.err.println("SimpleDaemon: dropping connection "
130: + handler.getConnectionNumber());
131: handler.close();
132: }
133:
134: System.err.println("SimpleDaemon: exiting acceptor loop");
135: }
136:
137: protected void addHandler(Handler handler) {
138: synchronized (handler) {
139: this .handlers.add(handler);
140: }
141: }
142:
143: protected void removeHandler(Handler handler) {
144: synchronized (handler) {
145: this .handlers.remove(handler);
146: }
147: }
148:
149: public static class Handler implements Runnable {
150:
151: private DaemonController controller = null;
152: private SimpleDaemon parent = null;
153: private String directory = null;
154: private Socket socket = null;
155: private int number = 0;
156:
157: public Handler(Socket s, SimpleDaemon p, DaemonController c) {
158: super ();
159: this .socket = s;
160: this .parent = p;
161: this .controller = c;
162: }
163:
164: public void run() {
165: this .parent.addHandler(this );
166: System.err.println("SimpleDaemon: connection "
167: + this .number + " opened from "
168: + this .socket.getInetAddress());
169: try {
170: InputStream in = this .socket.getInputStream();
171: OutputStream out = this .socket.getOutputStream();
172: handle(in, out);
173: this .socket.close();
174: } catch (IOException e) {
175: e.printStackTrace(System.err);
176: }
177: System.err.println("SimpleDaemon: connection "
178: + this .number + " closed");
179: this .parent.removeHandler(this );
180: }
181:
182: public void close() {
183: try {
184: this .socket.close();
185: } catch (IOException e) {
186: e.printStackTrace(System.err);
187: }
188: }
189:
190: public void setConnectionNumber(int number) {
191: this .number = number;
192: }
193:
194: public int getConnectionNumber() {
195: return (this .number);
196: }
197:
198: public void setDirectoryName(String directory) {
199: this .directory = directory;
200: }
201:
202: public String getDirectoryName() {
203: return (this .directory);
204: }
205:
206: public void log(String name) throws IOException {
207: OutputStream file = new FileOutputStream(name, true);
208: PrintStream out = new PrintStream(file);
209: SimpleDateFormat fmt = new SimpleDateFormat();
210:
211: out.println(fmt.format(new Date()));
212: out.close();
213: file.close();
214: }
215:
216: public void handle(InputStream in, OutputStream os) {
217: PrintStream out = new PrintStream(os);
218:
219: while (true) {
220: try {
221: /* If we don't have data in the System InputStream, we want
222: to ask to the user for an option. */
223: if (in.available() == 0) {
224: out.println();
225: out
226: .println("Please select one of the following:");
227: out.println(" 1) Shutdown");
228: out.println(" 2) Reload");
229: out.println(" 3) Create a file");
230: out.println(" 4) Disconnect");
231: out.print("Your choiche: ");
232: }
233:
234: /* Read an option from the client */
235: int x = in.read();
236:
237: switch (x) {
238: /* If the socket was closed, we simply return */
239: case -1:
240: return;
241:
242: /* Attempt to shutdown */
243: case '1':
244: out.println("Attempting a shutdown...");
245: try {
246: this .controller.shutdown();
247: } catch (IllegalStateException e) {
248: out.println();
249: out.println("Can't shutdown now");
250: e.printStackTrace(out);
251: }
252: break;
253:
254: /* Attempt to reload */
255: case '2':
256: out.println("Attempting a reload...");
257: try {
258: this .controller.reload();
259: } catch (IllegalStateException e) {
260: out.println();
261: out.println("Can't reload now");
262: e.printStackTrace(out);
263: }
264: break;
265:
266: /* Disconnect */
267: case '3':
268: String name = this .getDirectoryName()
269: + "/SimpleDaemon."
270: + this .getConnectionNumber() + ".tmp";
271: try {
272: this .log(name);
273: out.println("File '" + name + "' created");
274: } catch (IOException e) {
275: e.printStackTrace(out);
276: }
277: break;
278:
279: /* Disconnect */
280: case '4':
281: out.println("Disconnecting...");
282: return;
283:
284: /* Discard any carriage return / newline characters */
285: case '\r':
286: case '\n':
287: break;
288:
289: /* We got something that we weren't supposed to get */
290: default:
291: out
292: .println("Unknown option '" + (char) x
293: + "'");
294: break;
295:
296: }
297:
298: /* If we get an IOException we return (disconnect) */
299: } catch (IOException e) {
300: System.err.println("SimpleDaemon: IOException in "
301: + "connection "
302: + this.getConnectionNumber());
303: return;
304: }
305: }
306: }
307: }
308: }
|