~hudson-ubuntu/+junk/hudson-winstone

« back to all changes in this revision

Viewing changes to src/java/winstone/Launcher.java

  • Committer: James Page
  • Date: 2011-02-16 13:54:56 UTC
  • Revision ID: james.page@canonical.com-20110216135456-m2hlkk9blblou019
InitialĀ releaseĀ 

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright 2003-2006 Rick Knowles <winstone-devel at lists sourceforge net>
 
3
 * Distributed under the terms of either:
 
4
 * - the common development and distribution license (CDDL), v1.0; or
 
5
 * - the GNU Lesser General Public License, v2.1 or later
 
6
 */
 
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
/**
 
30
 * Implements the main launcher daemon thread. This is the class that gets
 
31
 * launched by the command line, and owns the server socket, etc.
 
32
 * 
 
33
 * @author <a href="mailto:rick_knowles@hotmail.com">Rick Knowles</a>
 
34
 * @version $Id: Launcher.java,v 1.29 2007/04/23 02:55:35 rickknowles Exp $
 
35
 */
 
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; // wait 2s for control connection
 
48
    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
    /**
 
61
     * Constructor - initialises the web app, object pools, control port and the
 
62
     * available protocol listeners.
 
63
     */
 
64
    public Launcher(Map args) throws IOException {
 
65
        
 
66
        boolean useJNDI = WebAppConfiguration.booleanArg(args, "useJNDI", false);
 
67
        
 
68
        // Set jndi resource handler if not set (workaround for JamVM bug)
 
69
        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
        // Check for java home
 
86
        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
            // first try - if it doesn't exist, try up one dir since we might have 
 
97
            // the JRE home by mistake
 
98
            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
        // Add tools jar to classloader path
 
111
        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
        // Set up common lib class loader
 
120
        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[jars.size()]), 
 
139
                getClass().getClassLoader());
 
140
        
 
141
        Logger.log(Logger.MAX, RESOURCES, "Launcher.CLClassLoader",
 
142
                commonLibCL.toString());
 
143
        Logger.log(Logger.MAX, RESOURCES, "Launcher.CLClassLoader",
 
144
                commonLibCLPaths.toString());
 
145
                                        
 
146
        this.objectPool = new ObjectPool(args);
 
147
 
 
148
        // Optionally set up clustering if enabled and libraries are available
 
149
        String useCluster = (String) args.get("useCluster");
 
150
        boolean switchOnCluster = (useCluster != null)
 
151
                && (useCluster.equalsIgnoreCase("true") || useCluster
 
152
                        .equalsIgnoreCase("yes"));
 
153
        if (switchOnCluster) {
 
154
            if (this.controlPort < 0) {
 
155
                Logger.log(Logger.INFO, RESOURCES,
 
156
                        "Launcher.ClusterOffNoControlPort");
 
157
            } else {
 
158
                String clusterClassName = WebAppConfiguration.stringArg(args, "clusterClassName",
 
159
                        CLUSTER_CLASS).trim();
 
160
                try {
 
161
                    Class clusterClass = Class.forName(clusterClassName);
 
162
                    Constructor clusterConstructor = clusterClass
 
163
                            .getConstructor(new Class[] { Map.class, Integer.class });
 
164
                    this.cluster = (Cluster) clusterConstructor
 
165
                            .newInstance(new Object[] { args, new Integer(this.controlPort) });
 
166
                } catch (ClassNotFoundException err) {
 
167
                    Logger.log(Logger.DEBUG, RESOURCES, "Launcher.ClusterNotFound");
 
168
                } catch (Throwable err) {
 
169
                    Logger.log(Logger.WARNING, RESOURCES, "Launcher.ClusterStartupError", err);
 
170
                }
 
171
            }
 
172
        }
 
173
        
 
174
        // If jndi is enabled, run the container wide jndi populator
 
175
        if (useJNDI) {
 
176
            String jndiMgrClassName = WebAppConfiguration.stringArg(args, "containerJndiClassName",
 
177
                    DEFAULT_JNDI_MGR_CLASS).trim();
 
178
            try {
 
179
                // Build the realm
 
180
                Class jndiMgrClass = Class.forName(jndiMgrClassName, true, commonLibCL);
 
181
                Constructor jndiMgrConstr = jndiMgrClass.getConstructor(new Class[] { 
 
182
                        Map.class, List.class, ClassLoader.class });
 
183
                this.globalJndiManager = (JNDIManager) jndiMgrConstr.newInstance(new Object[] { 
 
184
                        args, null, commonLibCL });
 
185
                this.globalJndiManager.setup();
 
186
            } catch (ClassNotFoundException err) {
 
187
                Logger.log(Logger.DEBUG, RESOURCES,
 
188
                        "Launcher.JNDIDisabled");
 
189
            } catch (Throwable err) {
 
190
                Logger.log(Logger.ERROR, RESOURCES,
 
191
                        "Launcher.JNDIError", jndiMgrClassName, err);
 
192
            }
 
193
        }
 
194
        
 
195
        // Open the web apps
 
196
        this.hostGroup = new HostGroup(this.cluster, this.objectPool, commonLibCL, 
 
197
                (File []) commonLibCLPaths.toArray(new File[0]), args);
 
198
 
 
199
        // Create connectors (http, https and ajp)
 
200
        this.listeners = new ArrayList();
 
201
        spawnListener(HTTP_LISTENER_CLASS);
 
202
        spawnListener(AJP_LISTENER_CLASS);
 
203
        try {
 
204
            Class.forName("javax.net.ServerSocketFactory");
 
205
            spawnListener(HTTPS_LISTENER_CLASS);
 
206
        } catch (ClassNotFoundException err) {
 
207
            Logger.log(Logger.DEBUG, RESOURCES, 
 
208
                    "Launcher.NeedsJDK14", HTTPS_LISTENER_CLASS);
 
209
        }
 
210
 
 
211
        this.controlThread = new Thread(this, RESOURCES.getString(
 
212
                "Launcher.ThreadName", "" + this.controlPort));
 
213
        this.controlThread.setDaemon(false);
 
214
        this.controlThread.start();
 
215
 
 
216
        Runtime.getRuntime().addShutdownHook(new ShutdownHook(this));
 
217
 
 
218
    }
 
219
 
 
220
    /**
 
221
     * Instantiates listeners. Note that an exception thrown in the 
 
222
     * constructor is interpreted as the listener being disabled, so 
 
223
     * don't do anything too adventurous in the constructor, or if you do, 
 
224
     * catch and log any errors locally before rethrowing.
 
225
     */
 
226
    protected void spawnListener(String listenerClassName) {
 
227
        try {
 
228
            Class listenerClass = Class.forName(listenerClassName);
 
229
            Constructor listenerConstructor = listenerClass
 
230
                    .getConstructor(new Class[] { Map.class,
 
231
                            ObjectPool.class, HostGroup.class});
 
232
            Listener listener = (Listener) listenerConstructor
 
233
                    .newInstance(new Object[] { args, this.objectPool, 
 
234
                            this.hostGroup });
 
235
            if (listener.start()) {
 
236
                this.listeners.add(listener);
 
237
            }
 
238
        } catch (ClassNotFoundException err) {
 
239
            Logger.log(Logger.INFO, RESOURCES, 
 
240
                    "Launcher.ListenerNotFound", listenerClassName);
 
241
        } catch (Throwable err) {
 
242
            Logger.log(Logger.ERROR, RESOURCES, 
 
243
                    "Launcher.ListenerStartupError", listenerClassName, err);
 
244
        }
 
245
    }
 
246
 
 
247
    /**
 
248
     * The main run method. This handles the normal thread processing.
 
249
     */
 
250
    public void run() {
 
251
        boolean interrupted = false;
 
252
        try {
 
253
            ServerSocket controlSocket = null;
 
254
 
 
255
            if (this.controlPort > 0) {
 
256
                controlSocket = new ServerSocket(this.controlPort);
 
257
                controlSocket.setSoTimeout(CONTROL_TIMEOUT);
 
258
            }
 
259
 
 
260
            Logger.log(Logger.INFO, RESOURCES, "Launcher.StartupOK",
 
261
                    new String[] {RESOURCES.getString("ServerVersion"),
 
262
                                    (this.controlPort > 0 ? "" + this.controlPort
 
263
                                            : RESOURCES.getString("Launcher.ControlDisabled"))});
 
264
 
 
265
            // Enter the main loop
 
266
            while (!interrupted) {
 
267
//                this.objectPool.removeUnusedRequestHandlers();
 
268
//                this.hostGroup.invalidateExpiredSessions();
 
269
 
 
270
                // Check for control request
 
271
                Socket accepted = null;
 
272
                try {
 
273
                    if (controlSocket != null) {
 
274
                        accepted = controlSocket.accept();
 
275
                        if (accepted != null) {
 
276
                            handleControlRequest(accepted);
 
277
                        }
 
278
                    } else {
 
279
                        Thread.sleep(CONTROL_TIMEOUT);
 
280
                    }
 
281
                } catch (InterruptedIOException err) {
 
282
                } catch (InterruptedException err) {
 
283
                    interrupted = true;
 
284
                } catch (Throwable err) {
 
285
                    Logger.log(Logger.ERROR, RESOURCES,
 
286
                            "Launcher.ShutdownError", err);
 
287
                } finally {
 
288
                    if (accepted != null) {
 
289
                        try {accepted.close();} catch (IOException err) {}
 
290
                    }
 
291
                    if (Thread.interrupted()) {
 
292
                        interrupted = true;
 
293
                    }
 
294
                }
 
295
            }
 
296
 
 
297
            // Close server socket
 
298
            if (controlSocket != null) {
 
299
                controlSocket.close();
 
300
            }
 
301
        } catch (Throwable err) {
 
302
            Logger.log(Logger.ERROR, RESOURCES, "Launcher.ShutdownError", err);
 
303
        }
 
304
        Logger.log(Logger.INFO, RESOURCES, "Launcher.ControlThreadShutdownOK");
 
305
    }
 
306
 
 
307
    protected void handleControlRequest(Socket csAccepted) throws IOException {
 
308
        InputStream inSocket = null;
 
309
        OutputStream outSocket = null;
 
310
        ObjectInputStream inControl = null;
 
311
        try {
 
312
            inSocket = csAccepted.getInputStream();
 
313
            int reqType = inSocket.read();
 
314
            if ((byte) reqType == SHUTDOWN_TYPE) {
 
315
                Logger.log(Logger.INFO, RESOURCES,
 
316
                        "Launcher.ShutdownRequestReceived");
 
317
                shutdown();
 
318
            } else if ((byte) reqType == RELOAD_TYPE) {
 
319
                inControl = new ObjectInputStream(inSocket);
 
320
                String host = inControl.readUTF();
 
321
                String prefix = inControl.readUTF();
 
322
                Logger.log(Logger.INFO, RESOURCES, "Launcher.ReloadRequestReceived", host + prefix);
 
323
                HostConfiguration hostConfig = this.hostGroup.getHostByName(host);
 
324
                hostConfig.reloadWebApp(prefix);
 
325
            } else if (this.cluster != null) {
 
326
                outSocket = csAccepted.getOutputStream();
 
327
                this.cluster.clusterRequest((byte) reqType,
 
328
                        inSocket, outSocket, csAccepted,
 
329
                        this.hostGroup);
 
330
            }
 
331
        } finally {
 
332
            if (inControl != null) {
 
333
                try {inControl.close();} catch (IOException err) {}
 
334
            }
 
335
            if (inSocket != null) {
 
336
                try {inSocket.close();} catch (IOException err) {}
 
337
            }
 
338
            if (outSocket != null) {
 
339
                try {outSocket.close();} catch (IOException err) {}
 
340
            }
 
341
        }
 
342
    }
 
343
    
 
344
    public void shutdown() {
 
345
        // Release all listeners/pools/webapps
 
346
        for (Iterator i = this.listeners.iterator(); i.hasNext();)
 
347
            ((Listener) i.next()).destroy();
 
348
        this.objectPool.destroy();
 
349
        if (this.cluster != null)
 
350
            this.cluster.destroy();
 
351
        this.hostGroup.destroy();
 
352
        if (this.globalJndiManager != null) {
 
353
            this.globalJndiManager.tearDown();
 
354
        }
 
355
 
 
356
        if (this.controlThread != null) {
 
357
            this.controlThread.interrupt();
 
358
        }
 
359
        Thread.yield();
 
360
 
 
361
        Logger.log(Logger.INFO, RESOURCES, "Launcher.ShutdownOK");
 
362
    }
 
363
 
 
364
    public boolean isRunning() {
 
365
        return (this.controlThread != null) && this.controlThread.isAlive();
 
366
    }
 
367
    
 
368
    /**
 
369
     * Main method. This basically just accepts a few args, then initialises the
 
370
     * listener thread. For now, just shut it down with a control-C.
 
371
     */
 
372
    public static void main(String argv[]) throws IOException {
 
373
        Map args = getArgsFromCommandLine(argv);
 
374
        
 
375
        if (args.containsKey("usage") || args.containsKey("help")) {
 
376
            printUsage();
 
377
            return;
 
378
        }
 
379
 
 
380
        // Check for embedded war
 
381
        deployEmbeddedWarfile(args);
 
382
        
 
383
        // Check for embedded warfile
 
384
        if (!args.containsKey("webroot") && !args.containsKey("warfile") 
 
385
                && !args.containsKey("webappsDir")&& !args.containsKey("hostsDir")) {
 
386
            printUsage();
 
387
            return;
 
388
        }
 
389
        // Launch
 
390
        try {
 
391
            new Launcher(args);
 
392
        } catch (Throwable err) {
 
393
            Logger.log(Logger.ERROR, RESOURCES, "Launcher.ContainerStartupError", err);
 
394
        }
 
395
    }
 
396
    
 
397
    public static Map getArgsFromCommandLine(String argv[]) throws IOException {
 
398
        Map args = loadArgsFromCommandLineAndConfig(argv, "nonSwitch");
 
399
        
 
400
        // Small hack to allow re-use of the command line parsing inside the control tool
 
401
        String firstNonSwitchArgument = (String) args.get("nonSwitch");
 
402
        args.remove("nonSwitch");
 
403
        
 
404
        // Check if the non-switch arg is a file or folder, and overwrite the config
 
405
        if (firstNonSwitchArgument != null) {
 
406
            File webapp = new File(firstNonSwitchArgument);
 
407
            if (webapp.exists()) {
 
408
                if (webapp.isDirectory()) {
 
409
                    args.put("webroot", firstNonSwitchArgument);
 
410
                } else if (webapp.isFile()) {
 
411
                    args.put("warfile", firstNonSwitchArgument);
 
412
                }
 
413
            }
 
414
        }
 
415
        return args;
 
416
    }
 
417
 
 
418
    public static Map loadArgsFromCommandLineAndConfig(String argv[], String nonSwitchArgName) 
 
419
            throws IOException {
 
420
        Map args = new HashMap();
 
421
        
 
422
        // Load embedded properties file 
 
423
        String embeddedPropertiesFilename = RESOURCES.getString(
 
424
                "Launcher.EmbeddedPropertiesFile");
 
425
        
 
426
        InputStream embeddedPropsStream = Launcher.class.getResourceAsStream(
 
427
                embeddedPropertiesFilename);
 
428
        if (embeddedPropsStream != null) {
 
429
            loadPropsFromStream(embeddedPropsStream, args);
 
430
            embeddedPropsStream.close();
 
431
        }
 
432
        
 
433
        // Get command line args
 
434
        String configFilename = RESOURCES.getString("Launcher.DefaultPropertyFile");
 
435
        for (int n = 0; n < argv.length; n++) {
 
436
            String option = argv[n];
 
437
            if (option.startsWith("--")) {
 
438
                int equalPos = option.indexOf('=');
 
439
                String paramName = option.substring(2, 
 
440
                        equalPos == -1 ? option.length() : equalPos);
 
441
                if (equalPos != -1) {
 
442
                    args.put(paramName, option.substring(equalPos + 1));
 
443
                } else {
 
444
                    args.put(paramName, "true");
 
445
                }
 
446
                if (paramName.equals("config")) {
 
447
                    configFilename = (String) args.get(paramName);
 
448
                }
 
449
            } else {
 
450
                args.put(nonSwitchArgName, option);
 
451
            }
 
452
        }
 
453
 
 
454
        // Load default props if available
 
455
        File configFile = new File(configFilename);
 
456
        if (configFile.exists() && configFile.isFile()) {
 
457
            InputStream inConfig = new FileInputStream(configFile);
 
458
            loadPropsFromStream(inConfig, args);
 
459
            inConfig.close();
 
460
            initLogger(args);
 
461
            Logger.log(Logger.DEBUG, RESOURCES, "Launcher.UsingPropertyFile",
 
462
                    configFilename);
 
463
        } else {
 
464
            initLogger(args);
 
465
        }
 
466
        return args;
 
467
    }
 
468
    
 
469
    protected static void deployEmbeddedWarfile(Map args) throws IOException {
 
470
        String embeddedWarfileName = RESOURCES.getString("Launcher.EmbeddedWarFile");
 
471
        InputStream embeddedWarfile = Launcher.class.getResourceAsStream(
 
472
                embeddedWarfileName);
 
473
        if (embeddedWarfile != null) {
 
474
            File tempWarfile = File.createTempFile("embedded", ".war").getAbsoluteFile();
 
475
            tempWarfile.getParentFile().mkdirs();
 
476
            tempWarfile.deleteOnExit();
 
477
 
 
478
            String embeddedWebroot = RESOURCES.getString("Launcher.EmbeddedWebroot");
 
479
            File tempWebroot = new File(tempWarfile.getParentFile(), embeddedWebroot);
 
480
            tempWebroot.mkdirs();
 
481
            
 
482
            Logger.log(Logger.DEBUG, RESOURCES, "Launcher.CopyingEmbeddedWarfile",
 
483
                    tempWarfile.getAbsolutePath());
 
484
            OutputStream out = new FileOutputStream(tempWarfile, true);
 
485
            int read = 0;
 
486
            byte buffer[] = new byte[2048];
 
487
            while ((read = embeddedWarfile.read(buffer)) != -1) {
 
488
                out.write(buffer, 0, read);
 
489
            }
 
490
            out.close();
 
491
            embeddedWarfile.close();
 
492
            
 
493
            args.put("warfile", tempWarfile.getAbsolutePath());
 
494
            args.put("webroot", tempWebroot.getAbsolutePath());
 
495
            args.remove("webappsDir");
 
496
            args.remove("hostsDir");
 
497
        }
 
498
    }
 
499
    
 
500
    protected static void loadPropsFromStream(InputStream inConfig, Map args) throws IOException {
 
501
        Properties props = new Properties();
 
502
        props.load(inConfig);
 
503
        for (Iterator i = props.keySet().iterator(); i.hasNext(); ) {
 
504
            String key = (String) i.next();
 
505
            if (!args.containsKey(key.trim())) {
 
506
                args.put(key.trim(), props.getProperty(key).trim());
 
507
            }
 
508
        }
 
509
        props.clear();
 
510
    }
 
511
    
 
512
    public static void initLogger(Map args) throws IOException {
 
513
        // Reset the log level
 
514
        int logLevel = WebAppConfiguration.intArg(args, "debug", Logger.INFO);
 
515
//        boolean showThrowingLineNo = WebAppConfiguration.booleanArg(args, "logThrowingLineNo", false);
 
516
        boolean showThrowingThread = WebAppConfiguration.booleanArg(args, "logThrowingThread", false);
 
517
        OutputStream logStream = null;
 
518
        if (args.get("logfile") != null) {
 
519
            logStream = new FileOutputStream((String) args.get("logfile"));
 
520
        } else if (WebAppConfiguration.booleanArg(args, "logToStdErr", false)) {
 
521
            logStream = System.err;
 
522
        } else {
 
523
            logStream = System.out;
 
524
        }
 
525
//        Logger.init(logLevel, logStream, showThrowingLineNo, showThrowingThread);
 
526
        Logger.init(logLevel, logStream, showThrowingThread);
 
527
    }
 
528
 
 
529
    protected static void printUsage() {
 
530
        // if the caller overrides the usage, use that instead.
 
531
        String usage = USAGE;
 
532
        if(usage==null)
 
533
            usage = RESOURCES.getString("Launcher.UsageInstructions",
 
534
                RESOURCES.getString("ServerVersion"));
 
535
        System.out.println(usage);
 
536
    }
 
537
 
 
538
    /**
 
539
     * Overridable usage screen
 
540
     */
 
541
    public static String USAGE;
 
542
}