Source Code Cross Referenced for NGServer.java in  » Net » NailGun » com » martiansoftware » nailgun » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Net » NailGun » com.martiansoftware.nailgun 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


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.lang.reflect.Method;
024:        import java.net.InetAddress;
025:        import java.net.ServerSocket;
026:        import java.net.Socket;
027:        import java.net.UnknownHostException;
028:        import java.util.Iterator;
029:        import java.util.Map;
030:
031:        import com.martiansoftware.nailgun.builtins.DefaultNail;
032:
033:        /**
034:         * <p>Listens for new connections from NailGun clients and launches
035:         * NGSession threads to process them.</p>
036:         * 
037:         * <p>This class can be run as a standalone server or can be embedded
038:         * within larger applications as a means of providing command-line
039:         * interaction with the application.</p>
040:         * 
041:         * @author <a href="http://www.martiansoftware.com/contact.html">Marty Lamb</a>
042:         */
043:        public class NGServer implements  Runnable {
044:
045:            /**
046:             * The address on which to listen, or null to listen on all
047:             * local addresses
048:             */
049:            private InetAddress addr = null;
050:
051:            /**
052:             * The port on which to listen, or zero to select a port automatically
053:             */
054:            private int port = 0;
055:
056:            /**
057:             * The socket doing the listening
058:             */
059:            private ServerSocket serversocket;
060:
061:            /**
062:             * True if this NGServer has received instructions to shut down
063:             */
064:            private boolean shutdown = false;
065:
066:            /**
067:             * True if this NGServer has been started and is accepting connections
068:             */
069:            private boolean running = false;
070:
071:            /**
072:             * This NGServer's AliasManager, which maps aliases to classes
073:             */
074:            private AliasManager aliasManager;
075:
076:            /**
077:             * If true, fully-qualified classnames are valid commands
078:             */
079:            private boolean allowNailsByClassName = true;
080:
081:            /**
082:             * The default class to use if an invalid alias or classname is
083:             * specified by the client.
084:             */
085:            private Class defaultNailClass = null;
086:
087:            /**
088:             * A pool of NGSessions ready to handle client connections
089:             */
090:            private NGSessionPool sessionPool = null;
091:
092:            /**
093:             * <code>System.out</code> at the time of the NGServer's creation
094:             */
095:            public final PrintStream out = System.out;
096:
097:            /**
098:             * <code>System.err</code> at the time of the NGServer's creation
099:             */
100:            public final PrintStream err = System.err;
101:
102:            /**
103:             * <code>System.in</code> at the time of the NGServer's creation
104:             */
105:            public final InputStream in = System.in;
106:
107:            /**
108:             * a collection of all classes executed by this server so far
109:             */
110:            private Map allNailStats = null;
111:
112:            /**
113:             * Remember the security manager we start with so we can restore it later
114:             */
115:            private SecurityManager originalSecurityManager = null;
116:
117:            /**
118:             * Creates a new NGServer that will listen at the specified address and
119:             * on the specified port.
120:             * This does <b>not</b> cause the server to start listening.  To do
121:             * so, create a new <code>Thread</code> wrapping this <code>NGServer</code>
122:             * and start it.
123:             * @param addr the address at which to listen, or <code>null</code> to bind
124:             * to all local addresses
125:             * @param port the port on which to listen.
126:             */
127:            public NGServer(InetAddress addr, int port) {
128:                init(addr, port);
129:            }
130:
131:            /**
132:             * Creates a new NGServer that will listen on the default port
133:             * (defined in <code>NGConstants.DEFAULT_PORT</code>).
134:             * This does <b>not</b> cause the server to start listening.  To do
135:             * so, create a new <code>Thread</code> wrapping this <code>NGServer</code>
136:             * and start it.
137:             */
138:            public NGServer() {
139:                init(null, NGConstants.DEFAULT_PORT);
140:            }
141:
142:            /**
143:             * Sets up the NGServer internals
144:             * @param addr the InetAddress to bind to
145:             * @param port the port on which to listen
146:             */
147:            private void init(InetAddress addr, int port) {
148:                this .addr = addr;
149:                this .port = port;
150:
151:                this .aliasManager = new AliasManager();
152:                allNailStats = new java.util.HashMap();
153:                // allow a maximum of 10 idle threads.  probably too high a number
154:                // and definitely should be configurable in the future
155:                sessionPool = new NGSessionPool(this , 10);
156:            }
157:
158:            /**
159:             * Sets a flag that determines whether Nails can be executed by class name.
160:             * If this is false, Nails can only be run via aliases (and you should
161:             * probably remove ng-alias from the AliasManager).
162:             * 
163:             * @param allowNailsByClassName true iff Nail lookups by classname are allowed
164:             */
165:            public void setAllowNailsByClassName(boolean allowNailsByClassName) {
166:                this .allowNailsByClassName = allowNailsByClassName;
167:            }
168:
169:            /**
170:             * Returns a flag that indicates whether Nail lookups by classname
171:             * are allowed.  If this is false, Nails can only be run via aliases.
172:             * @return a flag that indicates whether Nail lookups by classname
173:             * are allowed.
174:             */
175:            public boolean allowsNailsByClassName() {
176:                return (allowNailsByClassName);
177:            }
178:
179:            /**
180:             * Sets the default class to use for the Nail if no Nails can
181:             * be found via alias or classname. (may be <code>null</code>,
182:             * in which case NailGun will use its own default)
183:             * @param defaultNailClass the default class to use for the Nail
184:             * if no Nails can be found via alias or classname.
185:             * (may be <code>null</code>, in which case NailGun will use
186:             * its own default)
187:             */
188:            public void setDefaultNailClass(Class defaultNailClass) {
189:                this .defaultNailClass = defaultNailClass;
190:            }
191:
192:            /**
193:             * Returns the default class that will be used if no Nails
194:             * can be found via alias or classname.
195:             * @return the default class that will be used if no Nails
196:             * can be found via alias or classname.
197:             */
198:            public Class getDefaultNailClass() {
199:                return ((defaultNailClass == null) ? DefaultNail.class
200:                        : defaultNailClass);
201:            }
202:
203:            /**
204:             * Returns the current NailStats object for the specified class, creating
205:             * a new one if necessary
206:             * @param nailClass the class for which we're gathering stats
207:             * @return a NailStats object for the specified class
208:             */
209:            private NailStats getOrCreateStatsFor(Class nailClass) {
210:                NailStats result = null;
211:                synchronized (allNailStats) {
212:                    result = (NailStats) allNailStats.get(nailClass);
213:                    if (result == null) {
214:                        result = new NailStats(nailClass);
215:                        allNailStats.put(nailClass, result);
216:                    }
217:                }
218:                return (result);
219:            }
220:
221:            /**
222:             * Provides a means for an NGSession to register the starting of
223:             * a nail execution with the server.
224:             * 
225:             * @param nailClass the nail class that was launched
226:             */
227:            void nailStarted(Class nailClass) {
228:                NailStats stats = getOrCreateStatsFor(nailClass);
229:                stats.nailStarted();
230:            }
231:
232:            /**
233:             * Provides a means for an NGSession to register the completion of
234:             * a nails execution with the server.
235:             * 
236:             * @param nailClass the nail class that finished
237:             */
238:            void nailFinished(Class nailClass) {
239:                NailStats stats = (NailStats) allNailStats.get(nailClass);
240:                stats.nailFinished();
241:            }
242:
243:            /**
244:             * Returns a snapshot of this NGServer's nail statistics.  The result is a <code>java.util.Map</code>,
245:             * keyed by class name, with <a href="NailStats.html">NailStats</a> objects as values.
246:             * 
247:             * @return a snapshot of this NGServer's nail statistics.
248:             */
249:            public Map getNailStats() {
250:                Map result = new java.util.TreeMap();
251:                synchronized (allNailStats) {
252:                    for (Iterator i = allNailStats.keySet().iterator(); i
253:                            .hasNext();) {
254:                        Class nailclass = (Class) i.next();
255:                        result.put(nailclass.getName(),
256:                                ((NailStats) allNailStats.get(nailclass))
257:                                        .clone());
258:                    }
259:                }
260:                return (result);
261:            }
262:
263:            /**
264:             * Returns the AliasManager in use by this NGServer.
265:             * @return the AliasManager in use by this NGServer.
266:             */
267:            public AliasManager getAliasManager() {
268:                return (aliasManager);
269:            }
270:
271:            /**
272:             * <p>Shuts down the server.  The server will stop listening
273:             * and its thread will finish.  Any running nails will be allowed
274:             * to finish.</p>
275:             * 
276:             * <p>Any nails that provide a
277:             * <pre><code>public static void nailShutdown(NGServer)</code></pre>
278:             * method will have this method called with this NGServer as its sole
279:             * parameter.</p>
280:             * 
281:             * @param exitVM if true, this method will also exit the JVM after
282:             * calling nailShutdown() on any nails.  This may prevent currently
283:             * running nails from exiting gracefully, but may be necessary in order
284:             * to perform some tasks, such as shutting down any AWT or Swing threads
285:             * implicitly launched by your nails.
286:             */
287:            public void shutdown(boolean exitVM) {
288:                synchronized (this ) {
289:                    if (shutdown)
290:                        return;
291:                    shutdown = true;
292:                }
293:
294:                try {
295:                    serversocket.close();
296:                } catch (Throwable toDiscard) {
297:                }
298:
299:                sessionPool.shutdown();
300:
301:                Class[] argTypes = new Class[1];
302:                argTypes[0] = NGServer.class;
303:                Object[] argValues = new Object[1];
304:                argValues[0] = this ;
305:
306:                // make sure that all aliased classes have associated nailstats
307:                // so they can be shut down.
308:                for (Iterator i = getAliasManager().getAliases().iterator(); i
309:                        .hasNext();) {
310:                    Alias alias = (Alias) i.next();
311:                    getOrCreateStatsFor(alias.getAliasedClass());
312:                }
313:
314:                synchronized (allNailStats) {
315:                    for (Iterator i = allNailStats.values().iterator(); i
316:                            .hasNext();) {
317:                        NailStats ns = (NailStats) i.next();
318:                        Class nailClass = ns.getNailClass();
319:
320:                        // yes, I know this is lazy, relying upon the exception
321:                        // to handle the case of no nailShutdown method.
322:                        try {
323:                            Method nailShutdown = nailClass.getMethod(
324:                                    "nailShutdown", argTypes);
325:                            nailShutdown.invoke(null, argValues);
326:                        } catch (Throwable toDiscard) {
327:                        }
328:                    }
329:                }
330:
331:                // restore system streams
332:                System.setIn(in);
333:                System.setOut(out);
334:                System.setErr(err);
335:
336:                System.setSecurityManager(originalSecurityManager);
337:
338:                if (exitVM) {
339:                    System.exit(0);
340:                }
341:            }
342:
343:            /**
344:             * Returns true iff the server is currently running.
345:             * @return true iff the server is currently running.
346:             */
347:            public boolean isRunning() {
348:                return (running);
349:            }
350:
351:            /**
352:             * Returns the port on which this server is (or will be) listening.
353:             * @return the port on which this server is (or will be) listening.
354:             */
355:            public int getPort() {
356:                return ((serversocket == null) ? port : serversocket
357:                        .getLocalPort());
358:            }
359:
360:            /**
361:             * Listens for new connections and launches NGSession threads
362:             * to process them.
363:             */
364:            public void run() {
365:                running = true;
366:                NGSession sessionOnDeck = null;
367:
368:                originalSecurityManager = System.getSecurityManager();
369:                System.setSecurityManager(new NGSecurityManager(
370:                        originalSecurityManager));
371:
372:                synchronized (System.in) {
373:                    if (!(System.in instanceof  ThreadLocalInputStream)) {
374:                        System.setIn(new ThreadLocalInputStream(in));
375:                        System.setOut(new ThreadLocalPrintStream(out));
376:                        System.setErr(new ThreadLocalPrintStream(err));
377:                    }
378:                }
379:
380:                try {
381:                    if (addr == null) {
382:                        serversocket = new ServerSocket(port);
383:                    } else {
384:                        serversocket = new ServerSocket(port, 0, addr);
385:                    }
386:
387:                    while (!shutdown) {
388:                        sessionOnDeck = sessionPool.take();
389:                        Socket socket = serversocket.accept();
390:                        sessionOnDeck.run(socket);
391:                    }
392:
393:                } catch (Throwable t) {
394:                    // if shutdown is called while the accept() method is blocking,
395:                    // an exception will be thrown that we don't care about.  filter
396:                    // those out.
397:                    if (!shutdown) {
398:                        t.printStackTrace();
399:                    }
400:                }
401:                if (sessionOnDeck != null) {
402:                    sessionOnDeck.shutdown();
403:                }
404:                running = false;
405:            }
406:
407:            private static void usage() {
408:                System.err
409:                        .println("Usage: java com.martiansoftware.nailgun.NGServer");
410:                System.err
411:                        .println("   or: java com.martiansoftware.nailgun.NGServer port");
412:                System.err
413:                        .println("   or: java com.martiansoftware.nailgun.NGServer IPAddress");
414:                System.err
415:                        .println("   or: java com.martiansoftware.nailgun.NGServer IPAddress:port");
416:            }
417:
418:            /**
419:             * Creates and starts a new <code>NGServer</code>.  A single optional
420:             * argument is valid, specifying the port on which this <code>NGServer</code>
421:             * should listen.  If omitted, <code>NGServer.DEFAULT_PORT</code> will be used.
422:             * @param args a single optional argument specifying the port on which to listen.
423:             * @throws NumberFormatException if a non-numeric port is specified
424:             */
425:            public static void main(String[] args)
426:                    throws NumberFormatException, UnknownHostException {
427:
428:                if (args.length > 1) {
429:                    usage();
430:                    return;
431:                }
432:
433:                // null server address means bind to everything local
434:                InetAddress serverAddress = null;
435:                int port = NGConstants.DEFAULT_PORT;
436:
437:                // parse the sole command line parameter, which
438:                // may be an inetaddress to bind to, a port number,
439:                // or an inetaddress followed by a port, separated
440:                // by a colon
441:                if (args.length != 0) {
442:                    String[] argParts = args[0].split(":");
443:                    String addrPart = null;
444:                    String portPart = null;
445:                    if (argParts.length == 2) {
446:                        addrPart = argParts[0];
447:                        portPart = argParts[1];
448:                    } else if (argParts[0].indexOf('.') >= 0) {
449:                        addrPart = argParts[0];
450:                    } else {
451:                        portPart = argParts[0];
452:                    }
453:                    if (addrPart != null) {
454:                        serverAddress = InetAddress.getByName(addrPart);
455:                    }
456:                    if (portPart != null) {
457:                        port = Integer.parseInt(portPart);
458:                    }
459:                }
460:
461:                NGServer server = new NGServer(serverAddress, port);
462:                Thread t = new Thread(server);
463:                t.setName("NGServer(" + serverAddress + ", " + port + ")");
464:                t.start();
465:
466:                Runtime.getRuntime().addShutdownHook(
467:                        new NGServerShutdowner(server));
468:
469:                // if the port is 0, it will be automatically determined.
470:                // add this little wait so the ServerSocket can fully
471:                // initialize and we can see what port it chose.
472:                int runningPort = server.getPort();
473:                while (runningPort == 0) {
474:                    try {
475:                        Thread.sleep(50);
476:                    } catch (Throwable toIgnore) {
477:                    }
478:                    runningPort = server.getPort();
479:                }
480:
481:                System.out.println("NGServer started on "
482:                        + ((serverAddress == null) ? "all interfaces"
483:                                : serverAddress.getHostAddress()) + ", port "
484:                        + runningPort + ".");
485:            }
486:
487:            /**
488:             * A shutdown hook that will cleanly bring down the NGServer if it
489:             * is interrupted.
490:             * 
491:             * @author <a href="http://www.martiansoftware.com/contact.html">Marty Lamb</a>
492:             */
493:            private static class NGServerShutdowner extends Thread {
494:                private NGServer server = null;
495:
496:                NGServerShutdowner(NGServer server) {
497:                    this .server = server;
498:                }
499:
500:                public void run() {
501:
502:                    int count = 0;
503:                    server.shutdown(false);
504:
505:                    // give the server up to five seconds to stop.  is that enough?
506:                    // remember that the shutdown will call nailShutdown in any
507:                    // nails as well
508:                    while (server.isRunning() && (count < 50)) {
509:
510:                        try {
511:                            Thread.sleep(100);
512:                        } catch (InterruptedException e) {
513:                        }
514:                        ++count;
515:                    }
516:
517:                    if (server.isRunning()) {
518:                        System.err
519:                                .println("Unable to cleanly shutdown server.  Exiting JVM Anyway.");
520:                    } else {
521:                        System.out.println("NGServer shut down.");
522:                    }
523:                }
524:            }
525:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.