1 7 package winstone; 8 9 import java.io.File ; 10 import java.io.FileInputStream ; 11 import java.io.FileOutputStream ; 12 import java.io.IOException ; 13 import java.io.InputStream ; 14 import java.io.InterruptedIOException ; 15 import java.io.ObjectInputStream ; 16 import java.io.OutputStream ; 17 import java.lang.reflect.Constructor ; 18 import java.net.ServerSocket ; 19 import java.net.Socket ; 20 import java.net.URL ; 21 import java.net.URLClassLoader ; 22 import java.util.ArrayList ; 23 import java.util.HashMap ; 24 import java.util.Iterator ; 25 import java.util.List ; 26 import java.util.Map ; 27 import java.util.Properties ; 28 29 36 public class Launcher implements Runnable { 37 38 static final String HTTP_LISTENER_CLASS = "winstone.HttpListener"; 39 static final String HTTPS_LISTENER_CLASS = "winstone.ssl.HttpsListener"; 40 static final String AJP_LISTENER_CLASS = "winstone.ajp13.Ajp13Listener"; 41 static final String CLUSTER_CLASS = "winstone.cluster.SimpleCluster"; 42 static final String DEFAULT_JNDI_MGR_CLASS = "winstone.jndi.ContainerJNDIManager"; 43 44 public static final byte SHUTDOWN_TYPE = (byte) '0'; 45 public static final byte RELOAD_TYPE = (byte) '4'; 46 47 private int CONTROL_TIMEOUT = 2000; private int DEFAULT_CONTROL_PORT = -1; 49 50 private Thread controlThread; 51 public final static WinstoneResourceBundle RESOURCES = new WinstoneResourceBundle("winstone.LocalStrings"); 52 private int controlPort; 53 private HostGroup hostGroup; 54 private ObjectPool objectPool; 55 private List listeners; 56 private Map args; 57 private Cluster cluster; 58 private JNDIManager globalJndiManager; 59 60 64 public Launcher(Map args) throws IOException { 65 66 boolean useJNDI = WebAppConfiguration.booleanArg(args, "useJNDI", false); 67 68 if (useJNDI) try { 70 Class ctxFactoryClass = Class.forName("winstone.jndi.java.javaURLContextFactory"); 71 if (System.getProperty("java.naming.factory.initial") == null) { 72 System.setProperty("java.naming.factory.initial", ctxFactoryClass.getName()); 73 } 74 if (System.getProperty("java.naming.factory.url.pkgs") == null) { 75 System.setProperty("java.naming.factory.url.pkgs", "winstone.jndi"); 76 } 77 } catch (ClassNotFoundException err) {} 78 79 Logger.log(Logger.MAX, RESOURCES, "Launcher.StartupArgs", args + ""); 80 81 this.args = args; 82 this.controlPort = (args.get("controlPort") == null ? DEFAULT_CONTROL_PORT 83 : Integer.parseInt((String ) args.get("controlPort"))); 84 85 List jars = new ArrayList (); 87 List commonLibCLPaths = new ArrayList (); 88 String defaultJavaHome = System.getProperty("java.home"); 89 String javaHome = WebAppConfiguration.stringArg(args, "javaHome", defaultJavaHome); 90 Logger.log(Logger.DEBUG, RESOURCES, "Launcher.UsingJavaHome", javaHome); 91 String toolsJarLocation = WebAppConfiguration.stringArg(args, "toolsJar", null); 92 File toolsJar = null; 93 if (toolsJarLocation == null) { 94 toolsJar = new File (javaHome, "lib/tools.jar"); 95 96 if (!toolsJar.exists()) { 99 File javaHome2 = new File (javaHome).getParentFile(); 100 File toolsJar2 = new File (javaHome2, "lib/tools.jar"); 101 if (toolsJar2.exists()) { 102 javaHome = javaHome2.getCanonicalPath(); 103 toolsJar = toolsJar2; 104 } 105 } 106 } else { 107 toolsJar = new File (toolsJarLocation); 108 } 109 110 if (toolsJar.exists()) { 112 jars.add(toolsJar.toURL()); 113 commonLibCLPaths.add(toolsJar); 114 Logger.log(Logger.DEBUG, RESOURCES, "Launcher.AddedCommonLibJar", 115 toolsJar.getName()); 116 } else if (WebAppConfiguration.booleanArg(args, "useJasper", false)) 117 Logger.log(Logger.WARNING, RESOURCES, "Launcher.ToolsJarNotFound"); 118 119 String commonLibCLFolder = WebAppConfiguration.stringArg(args, 121 "commonLibFolder", "lib"); 122 File libFolder = new File (commonLibCLFolder); 123 if (libFolder.exists() && libFolder.isDirectory()) { 124 Logger.log(Logger.DEBUG, RESOURCES, "Launcher.UsingCommonLib", 125 libFolder.getCanonicalPath()); 126 File children[] = libFolder.listFiles(); 127 for (int n = 0; n < children.length; n++) 128 if (children[n].getName().endsWith(".jar") 129 || children[n].getName().endsWith(".zip")) { 130 jars.add(children[n].toURL()); 131 commonLibCLPaths.add(children[n]); 132 Logger.log(Logger.DEBUG, RESOURCES, "Launcher.AddedCommonLibJar", 133 children[n].getName()); 134 } 135 } else { 136 Logger.log(Logger.DEBUG, RESOURCES, "Launcher.NoCommonLib"); 137 } 138 ClassLoader commonLibCL = new URLClassLoader ((URL []) jars.toArray(new URL [0]), 139 getClass().getClassLoader()); 140 141 Logger.log(Logger.MAX, RESOURCES, "Launcher.CLClassLoader", 142 commonLibCL.toString()); 143 144 this.objectPool = new ObjectPool(args); 145 146 String useCluster = (String ) args.get("useCluster"); 148 boolean switchOnCluster = (useCluster != null) 149 && (useCluster.equalsIgnoreCase("true") || useCluster 150 .equalsIgnoreCase("yes")); 151 if (switchOnCluster) { 152 if (this.controlPort < 0) { 153 Logger.log(Logger.INFO, RESOURCES, 154 "Launcher.ClusterOffNoControlPort"); 155 } else { 156 String clusterClassName = WebAppConfiguration.stringArg(args, "clusterClassName", 157 CLUSTER_CLASS).trim(); 158 try { 159 Class clusterClass = Class.forName(clusterClassName); 160 Constructor clusterConstructor = clusterClass 161 .getConstructor(new Class [] { Map .class, Integer .class }); 162 this.cluster = (Cluster) clusterConstructor 163 .newInstance(new Object [] { args, new Integer (this.controlPort) }); 164 } catch (ClassNotFoundException err) { 165 Logger.log(Logger.DEBUG, RESOURCES, "Launcher.ClusterNotFound"); 166 } catch (Throwable err) { 167 Logger.log(Logger.WARNING, RESOURCES, "Launcher.ClusterStartupError", err); 168 } 169 } 170 } 171 172 if (useJNDI) { 174 String jndiMgrClassName = WebAppConfiguration.stringArg(args, "containerJndiClassName", 175 DEFAULT_JNDI_MGR_CLASS).trim(); 176 try { 177 Class jndiMgrClass = Class.forName(jndiMgrClassName, true, commonLibCL); 179 Constructor jndiMgrConstr = jndiMgrClass.getConstructor(new Class [] { 180 Map .class, List .class, ClassLoader .class }); 181 this.globalJndiManager = (JNDIManager) jndiMgrConstr.newInstance(new Object [] { 182 args, null, commonLibCL }); 183 this.globalJndiManager.setup(); 184 } catch (ClassNotFoundException err) { 185 Logger.log(Logger.DEBUG, RESOURCES, 186 "Launcher.JNDIDisabled"); 187 } catch (Throwable err) { 188 Logger.log(Logger.ERROR, RESOURCES, 189 "Launcher.JNDIError", jndiMgrClassName, err); 190 } 191 } 192 193 this.hostGroup = new HostGroup(this.cluster, this.objectPool, commonLibCL, 195 (File []) commonLibCLPaths.toArray(new File [0]), args); 196 197 this.listeners = new ArrayList (); 199 spawnListener(HTTP_LISTENER_CLASS); 200 spawnListener(AJP_LISTENER_CLASS); 201 try { 202 Class.forName("javax.net.ServerSocketFactory"); 203 spawnListener(HTTPS_LISTENER_CLASS); 204 } catch (ClassNotFoundException err) { 205 Logger.log(Logger.DEBUG, RESOURCES, 206 "Launcher.NeedsJDK14", HTTPS_LISTENER_CLASS); 207 } 208 209 this.controlThread = new Thread (this, RESOURCES.getString( 210 "Launcher.ThreadName", "" + this.controlPort)); 211 this.controlThread.setDaemon(false); 212 this.controlThread.start(); 213 214 Runtime.getRuntime().addShutdownHook(new ShutdownHook(this)); 215 216 } 217 218 224 protected void spawnListener(String listenerClassName) { 225 try { 226 Class listenerClass = Class.forName(listenerClassName); 227 Constructor listenerConstructor = listenerClass 228 .getConstructor(new Class [] { Map .class, 229 ObjectPool.class, HostGroup.class}); 230 Listener listener = (Listener) listenerConstructor 231 .newInstance(new Object [] { args, this.objectPool, 232 this.hostGroup }); 233 if (listener.start()) { 234 this.listeners.add(listener); 235 } 236 } catch (ClassNotFoundException err) { 237 Logger.log(Logger.INFO, RESOURCES, 238 "Launcher.ListenerNotFound", listenerClassName); 239 } catch (Throwable err) { 240 Logger.log(Logger.ERROR, RESOURCES, 241 "Launcher.ListenerStartupError", listenerClassName, err); 242 } 243 } 244 245 248 public void run() { 249 boolean interrupted = false; 250 try { 251 ServerSocket controlSocket = null; 252 253 if (this.controlPort > 0) { 254 controlSocket = new ServerSocket (this.controlPort); 255 controlSocket.setSoTimeout(CONTROL_TIMEOUT); 256 } 257 258 Logger.log(Logger.INFO, RESOURCES, "Launcher.StartupOK", 259 new String [] {RESOURCES.getString("ServerVersion"), 260 (this.controlPort > 0 ? "" + this.controlPort 261 : RESOURCES.getString("Launcher.ControlDisabled"))}); 262 263 while (!interrupted) { 265 268 Socket accepted = null; 270 try { 271 if (controlSocket != null) { 272 accepted = controlSocket.accept(); 273 if (accepted != null) { 274 handleControlRequest(accepted); 275 } 276 } else { 277 Thread.sleep(CONTROL_TIMEOUT); 278 } 279 } catch (InterruptedIOException err) { 280 } catch (InterruptedException err) { 281 interrupted = true; 282 } catch (Throwable err) { 283 Logger.log(Logger.ERROR, RESOURCES, 284 "Launcher.ShutdownError", err); 285 } finally { 286 if (accepted != null) { 287 try {accepted.close();} catch (IOException err) {} 288 } 289 if (Thread.interrupted()) { 290 interrupted = true; 291 } 292 } 293 } 294 295 if (controlSocket != null) { 297 controlSocket.close(); 298 } 299 } catch (Throwable err) { 300 Logger.log(Logger.ERROR, RESOURCES, "Launcher.ShutdownError", err); 301 } 302 Logger.log(Logger.INFO, RESOURCES, "Launcher.ControlThreadShutdownOK"); 303 } 304 305 protected void handleControlRequest(Socket csAccepted) throws IOException { 306 InputStream inSocket = null; 307 OutputStream outSocket = null; 308 ObjectInputStream inControl = null; 309 try { 310 inSocket = csAccepted.getInputStream(); 311 int reqType = inSocket.read(); 312 if ((byte) reqType == SHUTDOWN_TYPE) { 313 Logger.log(Logger.INFO, RESOURCES, 314 "Launcher.ShutdownRequestReceived"); 315 shutdown(); 316 } else if ((byte) reqType == RELOAD_TYPE) { 317 inControl = new ObjectInputStream (inSocket); 318 String host = inControl.readUTF(); 319 String prefix = inControl.readUTF(); 320 Logger.log(Logger.INFO, RESOURCES, "Launcher.ReloadRequestReceived", host + prefix); 321 HostConfiguration hostConfig = this.hostGroup.getHostByName(host); 322 hostConfig.reloadWebApp(prefix); 323 } else if (this.cluster != null) { 324 outSocket = csAccepted.getOutputStream(); 325 this.cluster.clusterRequest((byte) reqType, 326 inSocket, outSocket, csAccepted, 327 this.hostGroup); 328 } 329 } finally { 330 if (inControl != null) { 331 try {inControl.close();} catch (IOException err) {} 332 } 333 if (inSocket != null) { 334 try {inSocket.close();} catch (IOException err) {} 335 } 336 if (outSocket != null) { 337 try {outSocket.close();} catch (IOException err) {} 338 } 339 } 340 } 341 342 public void shutdown() { 343 for (Iterator i = this.listeners.iterator(); i.hasNext();) 345 ((Listener) i.next()).destroy(); 346 this.objectPool.destroy(); 347 if (this.cluster != null) 348 this.cluster.destroy(); 349 this.hostGroup.destroy(); 350 if (this.globalJndiManager != null) { 351 this.globalJndiManager.tearDown(); 352 } 353 354 if (this.controlThread != null) { 355 this.controlThread.interrupt(); 356 } 357 Thread.yield(); 358 359 Logger.log(Logger.INFO, RESOURCES, "Launcher.ShutdownOK"); 360 } 361 362 public boolean isRunning() { 363 return (this.controlThread != null) && this.controlThread.isAlive(); 364 } 365 366 370 public static void main(String argv[]) throws IOException { 371 Map args = getArgsFromCommandLine(argv); 372 373 if (args.containsKey("usage") || args.containsKey("help")) { 374 printUsage(); 375 return; 376 } 377 378 deployEmbeddedWarfile(args); 380 381 if (!args.containsKey("webroot") && !args.containsKey("warfile") 383 && !args.containsKey("webappsDir")&& !args.containsKey("hostsDir")) { 384 printUsage(); 385 return; 386 } 387 try { 389 new Launcher(args); 390 } catch (Throwable err) { 391 Logger.log(Logger.ERROR, RESOURCES, "Launcher.ContainerStartupError", err); 392 } 393 } 394 395 public static Map getArgsFromCommandLine(String argv[]) throws IOException { 396 Map args = loadArgsFromCommandLineAndConfig(argv, "nonSwitch"); 397 398 String firstNonSwitchArgument = (String ) args.get("nonSwitch"); 400 args.remove("nonSwitch"); 401 402 if (firstNonSwitchArgument != null) { 404 File webapp = new File (firstNonSwitchArgument); 405 if (webapp.exists()) { 406 if (webapp.isDirectory()) { 407 args.put("webroot", firstNonSwitchArgument); 408 } else if (webapp.isFile()) { 409 args.put("warfile", firstNonSwitchArgument); 410 } 411 } 412 } 413 return args; 414 } 415 416 public static Map loadArgsFromCommandLineAndConfig(String argv[], String nonSwitchArgName) 417 throws IOException { 418 Map args = new HashMap (); 419 420 String embeddedPropertiesFilename = RESOURCES.getString( 422 "Launcher.EmbeddedPropertiesFile"); 423 424 InputStream embeddedPropsStream = Launcher.class.getResourceAsStream( 425 embeddedPropertiesFilename); 426 if (embeddedPropsStream != null) { 427 loadPropsFromStream(embeddedPropsStream, args); 428 embeddedPropsStream.close(); 429 } 430 431 String configFilename = RESOURCES.getString("Launcher.DefaultPropertyFile"); 433 for (int n = 0; n < argv.length; n++) { 434 String option = argv[n]; 435 if (option.startsWith("--")) { 436 int equalPos = option.indexOf('='); 437 String paramName = option.substring(2, 438 equalPos == -1 ? option.length() : equalPos); 439 if (equalPos != -1) { 440 args.put(paramName, option.substring(equalPos + 1)); 441 } else { 442 args.put(paramName, "true"); 443 } 444 if (paramName.equals("config")) { 445 configFilename = (String ) args.get(paramName); 446 } 447 } else { 448 args.put(nonSwitchArgName, option); 449 } 450 } 451 452 File configFile = new File (configFilename); 454 if (configFile.exists() && configFile.isFile()) { 455 InputStream inConfig = new FileInputStream (configFile); 456 loadPropsFromStream(inConfig, args); 457 inConfig.close(); 458 initLogger(args); 459 Logger.log(Logger.DEBUG, RESOURCES, "Launcher.UsingPropertyFile", 460 configFilename); 461 } else { 462 initLogger(args); 463 } 464 return args; 465 } 466 467 protected static void deployEmbeddedWarfile(Map args) throws IOException { 468 String embeddedWarfileName = RESOURCES.getString("Launcher.EmbeddedWarFile"); 469 InputStream embeddedWarfile = Launcher.class.getResourceAsStream( 470 embeddedWarfileName); 471 if (embeddedWarfile != null) { 472 File tempWarfile = File.createTempFile("embedded", ".war").getAbsoluteFile(); 473 tempWarfile.getParentFile().mkdirs(); 474 tempWarfile.deleteOnExit(); 475 476 String embeddedWebroot = RESOURCES.getString("Launcher.EmbeddedWebroot"); 477 File tempWebroot = new File (tempWarfile.getParentFile(), embeddedWebroot); 478 tempWebroot.mkdirs(); 479 480 Logger.log(Logger.DEBUG, RESOURCES, "Launcher.CopyingEmbeddedWarfile", 481 tempWarfile.getAbsolutePath()); 482 OutputStream out = new FileOutputStream (tempWarfile, true); 483 int read = 0; 484 byte buffer[] = new byte[2048]; 485 while ((read = embeddedWarfile.read(buffer)) != -1) { 486 out.write(buffer, 0, read); 487 } 488 out.close(); 489 embeddedWarfile.close(); 490 491 args.put("warfile", tempWarfile.getAbsolutePath()); 492 args.put("webroot", tempWebroot.getAbsolutePath()); 493 args.remove("webappsDir"); 494 args.remove("hostsDir"); 495 } 496 } 497 498 protected static void loadPropsFromStream(InputStream inConfig, Map args) throws IOException { 499 Properties props = new Properties (); 500 props.load(inConfig); 501 for (Iterator i = props.keySet().iterator(); i.hasNext(); ) { 502 String key = (String ) i.next(); 503 if (!args.containsKey(key.trim())) { 504 args.put(key.trim(), props.getProperty(key).trim()); 505 } 506 } 507 props.clear(); 508 } 509 510 public static void initLogger(Map args) throws IOException { 511 int logLevel = WebAppConfiguration.intArg(args, "debug", Logger.INFO); 513 boolean showThrowingThread = WebAppConfiguration.booleanArg(args, "logThrowingThread", false); 515 OutputStream logStream = null; 516 if (args.get("logfile") != null) { 517 logStream = new FileOutputStream ((String ) args.get("logfile")); 518 } else if (WebAppConfiguration.booleanArg(args, "logToStdErr", false)) { 519 logStream = System.err; 520 } else { 521 logStream = System.out; 522 } 523 Logger.init(logLevel, logStream, showThrowingThread); 525 } 526 527 protected static void printUsage() { 528 System.out.println(RESOURCES.getString("Launcher.UsageInstructions", 529 RESOURCES.getString("ServerVersion"))); 530 } 531 } 532 | Popular Tags |