1 18 19 package com.martiansoftware.nailgun; 20 import java.io.InputStream ; 21 import java.io.PrintStream ; 22 import java.lang.reflect.Method ; 23 import java.net.InetAddress ; 24 import java.net.ServerSocket ; 25 import java.net.Socket ; 26 import java.net.UnknownHostException ; 27 import java.util.Iterator ; 28 import java.util.Map ; 29 30 import com.martiansoftware.nailgun.builtins.DefaultNail; 31 32 42 public class NGServer implements Runnable { 43 44 48 private InetAddress addr = null; 49 50 53 private int port = 0; 54 55 58 private ServerSocket serversocket; 59 60 63 private boolean shutdown = false; 64 65 68 private boolean running = false; 69 70 73 private AliasManager aliasManager; 74 75 78 private boolean allowNailsByClassName = true; 79 80 84 private Class defaultNailClass = null; 85 86 89 private NGSessionPool sessionPool = null; 90 91 94 public final PrintStream out = System.out; 95 96 99 public final PrintStream err = System.err; 100 101 104 public final InputStream in = System.in; 105 106 109 private Map allNailStats = null; 110 111 114 private SecurityManager originalSecurityManager = null; 115 116 126 public NGServer(InetAddress addr, int port) { 127 init(addr, port); 128 } 129 130 137 public NGServer() { 138 init(null, NGConstants.DEFAULT_PORT); 139 } 140 141 146 private void init(InetAddress addr, int port) { 147 this.addr = addr; 148 this.port = port; 149 150 this.aliasManager = new AliasManager(); 151 allNailStats = new java.util.HashMap (); 152 sessionPool = new NGSessionPool(this, 10); 155 } 156 157 164 public void setAllowNailsByClassName(boolean allowNailsByClassName) { 165 this.allowNailsByClassName = allowNailsByClassName; 166 } 167 168 174 public boolean allowsNailsByClassName() { 175 return (allowNailsByClassName); 176 } 177 178 187 public void setDefaultNailClass(Class defaultNailClass) { 188 this.defaultNailClass = defaultNailClass; 189 } 190 191 197 public Class getDefaultNailClass() { 198 return ((defaultNailClass == null) ? DefaultNail.class : defaultNailClass) ; 199 } 200 201 207 private NailStats getOrCreateStatsFor(Class nailClass) { 208 NailStats result = null; 209 synchronized(allNailStats) { 210 result = (NailStats) allNailStats.get(nailClass); 211 if (result == null) { 212 result = new NailStats(nailClass); 213 allNailStats.put(nailClass, result); 214 } 215 } 216 return (result); 217 } 218 219 225 void nailStarted(Class nailClass) { 226 NailStats stats = getOrCreateStatsFor(nailClass); 227 stats.nailStarted(); 228 } 229 230 236 void nailFinished(Class nailClass) { 237 NailStats stats = (NailStats) allNailStats.get(nailClass); 238 stats.nailFinished(); 239 } 240 241 247 public Map getNailStats() { 248 Map result = new java.util.TreeMap (); 249 synchronized(allNailStats) { 250 for (Iterator i = allNailStats.keySet().iterator(); i.hasNext();) { 251 Class nailclass = (Class ) i.next(); 252 result.put(nailclass.getName(), ((NailStats) allNailStats.get(nailclass)).clone()); 253 } 254 } 255 return (result); 256 } 257 258 262 public AliasManager getAliasManager() { 263 return (aliasManager); 264 } 265 266 282 public void shutdown(boolean exitVM) { 283 synchronized(this) { 284 if (shutdown) return; 285 shutdown = true; 286 } 287 288 try { 289 serversocket.close(); 290 } catch (Throwable toDiscard) {} 291 292 sessionPool.shutdown(); 293 294 Class [] argTypes = new Class [1]; 295 argTypes[0] = NGServer.class; 296 Object [] argValues = new Object [1]; 297 argValues[0] = this; 298 299 for (Iterator i = getAliasManager().getAliases().iterator(); i.hasNext();) { 302 Alias alias = (Alias) i.next(); 303 getOrCreateStatsFor(alias.getAliasedClass()); 304 } 305 306 synchronized(allNailStats) { 307 for (Iterator i = allNailStats.values().iterator(); i.hasNext();) { 308 NailStats ns = (NailStats) i.next(); 309 Class nailClass = ns.getNailClass(); 310 311 try { 314 Method nailShutdown = nailClass.getMethod("nailShutdown", argTypes); 315 nailShutdown.invoke(null, argValues); 316 } catch (Throwable toDiscard) {} 317 } 318 } 319 320 System.setIn(in); 322 System.setOut(out); 323 System.setErr(err); 324 325 System.setSecurityManager(originalSecurityManager); 326 327 if (exitVM) { 328 System.exit(0); 329 } 330 } 331 332 336 public boolean isRunning() { 337 return (running); 338 } 339 340 344 public int getPort() { 345 return ((serversocket == null) ? port : serversocket.getLocalPort()); 346 } 347 348 352 public void run() { 353 running = true; 354 NGSession sessionOnDeck = null; 355 356 originalSecurityManager = System.getSecurityManager(); 357 System.setSecurityManager( 358 new NGSecurityManager( 359 originalSecurityManager)); 360 361 362 synchronized(System.in) { 363 if (!(System.in instanceof ThreadLocalInputStream)) { 364 System.setIn(new ThreadLocalInputStream(in)); 365 System.setOut(new ThreadLocalPrintStream(out)); 366 System.setErr(new ThreadLocalPrintStream(err)); 367 } 368 } 369 370 try { 371 if (addr == null) { 372 serversocket = new ServerSocket (port); 373 } else { 374 serversocket = new ServerSocket (port, 0, addr); 375 } 376 377 while (!shutdown) { 378 sessionOnDeck = sessionPool.take(); 379 Socket socket = serversocket.accept(); 380 sessionOnDeck.run(socket); 381 } 382 383 } catch (Throwable t) { 384 if (!shutdown) { 388 t.printStackTrace(); 389 } 390 } 391 if (sessionOnDeck != null) { 392 sessionOnDeck.shutdown(); 393 } 394 running = false; 395 } 396 397 private static void usage() { 398 System.err.println("Usage: java com.martiansoftware.nailgun.NGServer"); 399 System.err.println(" or: java com.martiansoftware.nailgun.NGServer port"); 400 System.err.println(" or: java com.martiansoftware.nailgun.NGServer IPAddress"); 401 System.err.println(" or: java com.martiansoftware.nailgun.NGServer IPAddress:port"); 402 } 403 404 411 public static void main(String [] args) throws NumberFormatException , UnknownHostException { 412 413 if (args.length > 1) { 414 usage(); 415 return; 416 } 417 418 InetAddress serverAddress = null; 420 int port = NGConstants.DEFAULT_PORT; 421 422 if (args.length != 0) { 427 String [] argParts = args[0].split(":"); 428 String addrPart = null; 429 String portPart = null; 430 if (argParts.length == 2) { 431 addrPart = argParts[0]; 432 portPart = argParts[1]; 433 } else if (argParts[0].indexOf('.') >= 0) { 434 addrPart = argParts[0]; 435 } else { 436 portPart = argParts[0]; 437 } 438 if (addrPart != null) { 439 serverAddress = InetAddress.getByName(addrPart); 440 } 441 if (portPart != null) { 442 port = Integer.parseInt(portPart); 443 } 444 } 445 446 NGServer server = new NGServer(serverAddress, port); 447 Thread t = new Thread (server); 448 t.setName("NGServer(" + serverAddress + ", " + port + ")"); 449 t.start(); 450 451 Runtime.getRuntime().addShutdownHook(new NGServerShutdowner(server)); 452 453 int runningPort = server.getPort(); 457 while (runningPort == 0) { 458 try { Thread.sleep(50); } catch (Throwable toIgnore) {} 459 runningPort = server.getPort(); 460 } 461 462 System.out.println("NGServer started on " 463 + ((serverAddress == null) 464 ? "all interfaces" 465 : serverAddress.getHostAddress()) 466 + ", port " 467 + runningPort 468 + "."); 469 } 470 471 477 private static class NGServerShutdowner extends Thread { 478 private NGServer server = null; 479 480 NGServerShutdowner(NGServer server) { 481 this.server = server; 482 } 483 484 485 public void run() { 486 487 int count = 0; 488 server.shutdown(false); 489 490 while (server.isRunning() && (count < 50)) { 494 495 try {Thread.sleep(100);} catch(InterruptedException e) {} 496 ++count; 497 } 498 499 if (server.isRunning()) { 500 System.err.println("Unable to cleanly shutdown server. Exiting JVM Anyway."); 501 } else { 502 System.out.println("NGServer shut down."); 503 } 504 } 505 } 506 } 507 | Popular Tags |