Source Code Cross Referenced for WrapperManager.java in  » Collaboration » Java-Service-Wrapper » org » tanukisoftware » wrapper » 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 » Collaboration » Java Service Wrapper » org.tanukisoftware.wrapper 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        package org.tanukisoftware.wrapper;
0002:
0003:        /*
0004:         * Copyright (c) 1999, 2006 Tanuki Software Inc.
0005:         * 
0006:         * Permission is hereby granted, free of charge, to any person
0007:         * obtaining a copy of the Java Service Wrapper and associated
0008:         * documentation files (the "Software"), to deal in the Software
0009:         * without  restriction, including without limitation the rights
0010:         * to use, copy, modify, merge, publish, distribute, sub-license,
0011:         * and/or sell copies of the Software, and to permit persons to
0012:         * whom the Software is furnished to do so, subject to the
0013:         * following conditions:
0014:         * 
0015:         * The above copyright notice and this permission notice shall be
0016:         * included in all copies or substantial portions of the Software.
0017:         * 
0018:         * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
0019:         * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 
0020:         * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
0021:         * NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 
0022:         * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 
0023:         * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
0024:         * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0025:         * OTHER DEALINGS IN THE SOFTWARE.
0026:         * 
0027:         * 
0028:         * Portions of the Software have been derived from source code
0029:         * developed by Silver Egg Technology under the following license:
0030:         * 
0031:         * Copyright (c) 2001 Silver Egg Technology
0032:         * 
0033:         * Permission is hereby granted, free of charge, to any person
0034:         * obtaining a copy of this software and associated documentation
0035:         * files (the "Software"), to deal in the Software without 
0036:         * restriction, including without limitation the rights to use, 
0037:         * copy, modify, merge, publish, distribute, sub-license, and/or 
0038:         * sell copies of the Software, and to permit persons to whom the
0039:         * Software is furnished to do so, subject to the following 
0040:         * conditions:
0041:         * 
0042:         * The above copyright notice and this permission notice shall be
0043:         * included in all copies or substantial portions of the Software.
0044:         */
0045:
0046:        import java.io.DataInputStream;
0047:        import java.io.File;
0048:        import java.io.InputStream;
0049:        import java.io.InterruptedIOException;
0050:        import java.io.IOException;
0051:        import java.io.OutputStream;
0052:        import java.io.PrintStream;
0053:        import java.lang.reflect.Constructor;
0054:        import java.lang.reflect.InvocationTargetException;
0055:        import java.lang.reflect.Method;
0056:        import java.net.BindException;
0057:        import java.net.ConnectException;
0058:        import java.net.InetAddress;
0059:        import java.net.ServerSocket;
0060:        import java.net.Socket;
0061:        import java.net.SocketException;
0062:        import java.net.UnknownHostException;
0063:        import java.security.AccessControlException;
0064:        import java.security.AccessController;
0065:        import java.security.PrivilegedAction;
0066:        import java.util.ArrayList;
0067:        import java.util.Iterator;
0068:        import java.util.List;
0069:        import java.util.Properties;
0070:        import java.util.StringTokenizer;
0071:
0072:        import org.tanukisoftware.wrapper.event.WrapperControlEvent;
0073:        import org.tanukisoftware.wrapper.event.WrapperEvent;
0074:        import org.tanukisoftware.wrapper.event.WrapperEventListener;
0075:        import org.tanukisoftware.wrapper.event.WrapperPingEvent;
0076:        import org.tanukisoftware.wrapper.event.WrapperServiceControlEvent;
0077:        import org.tanukisoftware.wrapper.event.WrapperTickEvent;
0078:        import org.tanukisoftware.wrapper.resources.ResourceManager;
0079:        import org.tanukisoftware.wrapper.security.WrapperEventPermission;
0080:        import org.tanukisoftware.wrapper.security.WrapperPermission;
0081:        import org.tanukisoftware.wrapper.security.WrapperServicePermission;
0082:
0083:        /**
0084:         * Handles all communication with the native portion of the Wrapper code.
0085:         *	The native wrapper code will launch Java in a separate process and set
0086:         *	up a server socket which the Java code is expected to open a socket to
0087:         *	on startup.  When the server socket is created, a port will be chosen
0088:         *	depending on what is available to the system.  This port will then be
0089:         *	passed to the Java process as property named "wrapper.port".
0090:         *
0091:         * For security reasons, the native code will only allow connections from
0092:         *	localhost and will expect to receive the key specified in a property
0093:         *	named "wrapper.key".
0094:         *
0095:         * This class is implemented as a singleton class.
0096:         *
0097:         * Generate JNI Headers with the following command in the build/classes
0098:         *  directory:
0099:         *    javah -jni -classpath ./ org.tanukisoftware.wrapper.WrapperManager
0100:         *
0101:         * @author Leif Mortenson <leif@tanukisoftware.com>
0102:         */
0103:        public final class WrapperManager implements  Runnable {
0104:            private static final String WRAPPER_CONNECTION_THREAD_NAME = "Wrapper-Connection";
0105:
0106:            private static final int DEFAULT_PORT = 15003;
0107:            private static final int DEFAULT_SO_TIMEOUT = 10000;
0108:            private static final int DEFAULT_CPU_TIMEOUT = 10000;
0109:
0110:            /** The number of milliseconds in one tick.  Used for internal system
0111:             *   time independent time keeping. */
0112:            private static final int TICK_MS = 100;
0113:            private static final int TIMER_FAST_THRESHOLD = 2 * 24 * 3600
0114:                    * 1000 / TICK_MS; // 2 days.
0115:            private static final int TIMER_SLOW_THRESHOLD = 2 * 24 * 3600
0116:                    * 1000 / TICK_MS; // 2 days.
0117:
0118:            private static final byte WRAPPER_MSG_START = (byte) 100;
0119:            private static final byte WRAPPER_MSG_STOP = (byte) 101;
0120:            private static final byte WRAPPER_MSG_RESTART = (byte) 102;
0121:            private static final byte WRAPPER_MSG_PING = (byte) 103;
0122:            private static final byte WRAPPER_MSG_STOP_PENDING = (byte) 104;
0123:            private static final byte WRAPPER_MSG_START_PENDING = (byte) 105;
0124:            private static final byte WRAPPER_MSG_STARTED = (byte) 106;
0125:            private static final byte WRAPPER_MSG_STOPPED = (byte) 107;
0126:            private static final byte WRAPPER_MSG_KEY = (byte) 110;
0127:            private static final byte WRAPPER_MSG_BADKEY = (byte) 111;
0128:            private static final byte WRAPPER_MSG_LOW_LOG_LEVEL = (byte) 112;
0129:            private static final byte WRAPPER_MSG_PING_TIMEOUT = (byte) 113;
0130:            private static final byte WRAPPER_MSG_SERVICE_CONTROL_CODE = (byte) 114;
0131:            private static final byte WRAPPER_MSG_PROPERTIES = (byte) 115;
0132:
0133:            /** Log commands are actually 116 + the LOG LEVEL. */
0134:            private static final byte WRAPPER_MSG_LOG = (byte) 116;
0135:
0136:            /** Received when the user presses CTRL-C in the console on Windows or UNIX platforms. */
0137:            public static final int WRAPPER_CTRL_C_EVENT = 200;
0138:
0139:            /** Received when the user clicks on the close button of a Console on Windows. */
0140:            public static final int WRAPPER_CTRL_CLOSE_EVENT = 201;
0141:
0142:            /** Received when the user logs off of a Windows system. */
0143:            public static final int WRAPPER_CTRL_LOGOFF_EVENT = 202;
0144:
0145:            /** Received when a Windows system is shutting down. */
0146:            public static final int WRAPPER_CTRL_SHUTDOWN_EVENT = 203;
0147:
0148:            /** Received when a SIG TERM is received on a UNIX system. */
0149:            public static final int WRAPPER_CTRL_TERM_EVENT = 204;
0150:
0151:            /** Received when a SIG HUP is received on a UNIX system. */
0152:            public static final int WRAPPER_CTRL_HUP_EVENT = 205;
0153:
0154:            /** Log message at debug log level. */
0155:            public static final int WRAPPER_LOG_LEVEL_DEBUG = 1;
0156:            /** Log message at info log level. */
0157:            public static final int WRAPPER_LOG_LEVEL_INFO = 2;
0158:            /** Log message at status log level. */
0159:            public static final int WRAPPER_LOG_LEVEL_STATUS = 3;
0160:            /** Log message at warn log level. */
0161:            public static final int WRAPPER_LOG_LEVEL_WARN = 4;
0162:            /** Log message at error log level. */
0163:            public static final int WRAPPER_LOG_LEVEL_ERROR = 5;
0164:            /** Log message at fatal log level. */
0165:            public static final int WRAPPER_LOG_LEVEL_FATAL = 6;
0166:            /** Log message at advice log level. */
0167:            public static final int WRAPPER_LOG_LEVEL_ADVICE = 7;
0168:
0169:            /** Service Control code which can be sent to start a service. */
0170:            public static final int SERVICE_CONTROL_CODE_START = 0x10000;
0171:
0172:            /** Service Control code which can be sent or received to stop a service. */
0173:            public static final int SERVICE_CONTROL_CODE_STOP = 1;
0174:
0175:            /** Service Control code which can be sent to pause a service. */
0176:            public static final int SERVICE_CONTROL_CODE_PAUSE = 2;
0177:
0178:            /** Service Control code which can be sent to resume a paused service. */
0179:            public static final int SERVICE_CONTROL_CODE_CONTINUE = 3;
0180:
0181:            /** Service Control code which can be sent to or received interrogate the status of a service. */
0182:            public static final int SERVICE_CONTROL_CODE_INTERROGATE = 4;
0183:
0184:            /** Service Control code which can be received when the system is shutting down. */
0185:            public static final int SERVICE_CONTROL_CODE_SHUTDOWN = 5;
0186:
0187:            /** Reference to the original value of System.out. */
0188:            private static PrintStream m_out;
0189:
0190:            /** Reference to the original value of System.err. */
0191:            private static PrintStream m_err;
0192:
0193:            /** Flag that will be set to true once a SecurityManager has been detected and tested. */
0194:            private static boolean m_securityManagerChecked = false;
0195:
0196:            private static boolean m_disposed = false;
0197:            private static boolean m_started = false;
0198:            private static WrapperManager m_instance = null;
0199:            private static Thread m_hook = null;
0200:            private static boolean m_hookTriggered = false;
0201:
0202:            /* Flag which records when the shutdownJVM method has completed. */
0203:            private static boolean m_shutdownJVMComplete = false;
0204:
0205:            private static String[] m_args;
0206:            private static int m_port = DEFAULT_PORT;
0207:            private static int m_jvmPort;
0208:            private static int m_jvmPortMin;
0209:            private static int m_jvmPortMax;
0210:            private static String m_key;
0211:            private static int m_soTimeout = DEFAULT_SO_TIMEOUT;
0212:            private static long m_cpuTimeout = DEFAULT_CPU_TIMEOUT;
0213:
0214:            /** Tick count when the start method completed. */
0215:            private static int m_startedTicks;
0216:
0217:            /** The lowest configured log level in the Wrapper's configuration.  This 
0218:             *   is set to a high value by default to disable all logging if the
0219:             *   Wrapper does not register its low level or is not present. */
0220:            private static int m_lowLogLevel = WRAPPER_LOG_LEVEL_ADVICE + 1;
0221:
0222:            /** The maximum amount of time in ms to allow to pass without the JVM
0223:             *   pinging the server before the JVM is terminated to allow a resynch. */
0224:            private static int m_pingTimeout = 30000;
0225:
0226:            /** Flag, set when the JVM is launched that is used to remember whether
0227:             *   or not system signals are supposed to be ignored. */
0228:            private static boolean m_ignoreSignals = false;
0229:
0230:            /** Thread which processes all communications with the native code. */
0231:            private static Thread m_commRunner;
0232:            private static boolean m_commRunnerStarted = false;
0233:            private static Thread m_eventRunner;
0234:            private static int m_eventRunnerTicks;
0235:            private static Thread m_startupRunner;
0236:
0237:            /** True if the system time should be used for internal timeouts. */
0238:            private static boolean m_useSystemTime;
0239:
0240:            /** The threashold of how many ticks the timer can be fast before a
0241:             *   warning is displayed. */
0242:            private static int m_timerFastThreshold;
0243:
0244:            /** The threashold of how many ticks the timer can be slow before a
0245:             *   warning is displayed. */
0246:            private static int m_timerSlowThreshold;
0247:
0248:            /**
0249:             * Bit depth of the currently running JVM.  Will be 32 or 64.
0250:             *  A 64-bit JVM means that the system is also 64-bit, but a 32-bit JVM
0251:             *  can be run either on a 32 or 64-bit system.
0252:             */
0253:            private static int m_jvmBits;
0254:
0255:            /** An integer which stores the number of ticks since the
0256:             *   JVM was launched.  Using an int rather than a long allows the value
0257:             *   to be used without requiring any synchronization.  This is only
0258:             *   used if the m_useSystemTime flag is false. */
0259:            private static volatile int m_ticks;
0260:
0261:            private static WrapperListener m_listener;
0262:
0263:            private static int m_lastPingTicks;
0264:            private static ServerSocket m_serverSocket;
0265:            private static Socket m_socket;
0266:            private static boolean m_shuttingDown = false;
0267:            private static boolean m_appearHung = false;
0268:
0269:            private static Method m_addShutdownHookMethod = null;
0270:            private static Method m_removeShutdownHookMethod = null;
0271:
0272:            private static boolean m_service = false;
0273:            private static boolean m_debug = false;
0274:            private static int m_jvmId = 0;
0275:            private static boolean m_stopping = false;
0276:            private static Thread m_stoppingThread;
0277:            private static int m_exitCode;
0278:            private static boolean m_libraryOK = false;
0279:            private static byte[] m_commandBuffer = new byte[512];
0280:
0281:            /** The contents of the wrapper configuration. */
0282:            private static WrapperProperties m_properties;
0283:
0284:            /** List of registered WrapperEventListeners and their registered masks. */
0285:            private static List m_wrapperEventListenerMaskList = new ArrayList();
0286:
0287:            /** Array of registered WrapperEventListeners and their registered masks.
0288:             *   Should not be referenced directly.  Access by calling
0289:             *   getWrapperEventListenerMasks(). */
0290:            private static WrapperEventListenerMask[] m_wrapperEventListenerMasks = null;
0291:
0292:            /** Flag used to tell whether or not WrapperCoreEvents should be produced. */
0293:            private static boolean m_produceCoreEvents = false;
0294:
0295:            // message resources: eventually these will be split up
0296:            private static ResourceManager m_res = ResourceManager
0297:                    .getResourceManager();
0298:            private static ResourceManager m_error = m_res;
0299:            private static ResourceManager m_warning = m_res;
0300:            private static ResourceManager m_info = m_res;
0301:
0302:            /*---------------------------------------------------------------
0303:             * Class Initializer
0304:             *-------------------------------------------------------------*/
0305:            /**
0306:             * When the WrapperManager class is first loaded, it attempts to load the
0307:             *	configuration file specified using the 'wrapper.config' system property.
0308:             *	When the JVM is launched from the Wrapper native code, the
0309:             *	'wrapper.config' and 'wrapper.key' parameters are specified.
0310:             *	The 'wrapper.key' parameter is a password which is used to verify that
0311:             *	connections are only coming from the native Wrapper which launched the
0312:             *	current JVM.
0313:             */
0314:            static {
0315:                // The wraper.jar must be given AllPermissions if a security manager
0316:                //  has been configured.  This is not a problem if one of the standard
0317:                //  Wrapper helper classes is used to launch the JVM.
0318:                // If however a custom WrapperListener is being implemented then this
0319:                //  class will most likely be loaded by code that is neither part of
0320:                //  the system, nor part of the Wrapper code base.  To avoid having
0321:                //  to also give those classes AllPermissions as well, we do all of
0322:                //  initialization in a Privileged block.  This means that the code
0323:                //  only requires that the wrapper.jar has been given the required
0324:                //  permissions.
0325:                AccessController.doPrivileged(new PrivilegedAction() {
0326:                    public Object run() {
0327:                        privilegedClassInit();
0328:                        return null;
0329:                    }
0330:                });
0331:            }
0332:
0333:            /**
0334:             * The body of the static initializer is moved into a seperate method so
0335:             *  it can be run as a PrivilegedAction.
0336:             */
0337:            private static void privilegedClassInit() {
0338:                // Store references to the original System.out and System.err
0339:                //  PrintStreams.  The WrapperManager will always output to the
0340:                //  original streams so its output will always end up in the
0341:                //  wrapper.log file even if the end user code redirects the
0342:                //  output to another log file.
0343:                // This is also important to be protect the Wrapper's functionality
0344:                //  from the case where the user PrintStream enters a deadlock state.
0345:                m_out = System.out;
0346:                m_err = System.err;
0347:
0348:                // Always create an empty properties object in case we are not running
0349:                //  in the Wrapper or the properties are never sent.
0350:                m_properties = new WrapperProperties();
0351:                m_properties.lock();
0352:
0353:                // This must be done before attempting to access any System Properties
0354:                //  as that could cause a SecurityException if it is too strict.
0355:                checkSecurityManager();
0356:
0357:                // Check for the debug flag
0358:                m_debug = WrapperSystemPropertyUtil.getBooleanProperty(
0359:                        "wrapper.debug", false);
0360:
0361:                if (m_debug) {
0362:                    m_out
0363:                            .println("WrapperManager class initialized by thread: "
0364:                                    + Thread.currentThread().getName()
0365:                                    + "  Using classloader: "
0366:                                    + WrapperManager.class.getClassLoader());
0367:                }
0368:
0369:                //
0370:                // WARNING - The following banner is displayed to inform the user that they
0371:                //           are using the Java Service Wrapper.  This banner must remain
0372:                //           clearly visible in the logs of any application making use of
0373:                //           the Wrapper.  This includes any applications based on the
0374:                //           wrapper source.
0375:                //           If you are here then you are benefiting from this project,
0376:                //           please have the courtesy to respect its license.
0377:                m_out.println("Wrapper (Version " + getVersion()
0378:                        + ") http://wrapper.tanukisoftware.org");
0379:                m_out
0380:                        .println("  Copyright 1999-2006 Tanuki Software, Inc.  All Rights Reserved.");
0381:                m_out.println();
0382:
0383:                // Check for the jvmID
0384:                m_jvmId = WrapperSystemPropertyUtil.getIntProperty(
0385:                        "wrapper.jvmid", 1);
0386:                if (m_debug) {
0387:                    m_out.println("Wrapper Manager: JVM #" + m_jvmId);
0388:                }
0389:
0390:                // Decide whether this is a 32 or 64 bit version of Java.
0391:                m_jvmBits = Integer.getInteger("sun.arch.data.model", -1)
0392:                        .intValue();
0393:                if (m_debug) {
0394:                    if (m_jvmBits > 0) {
0395:                        m_out.println("Running a " + m_jvmBits + "-bit JVM.");
0396:                    } else {
0397:                        m_out
0398:                                .println("The bit depth of this JVM could not be determined.");
0399:                    }
0400:                }
0401:
0402:                // Initialize the timerTicks to a very high value.  This means that we will
0403:                // always encounter the first rollover (200 * WRAPPER_MS / 1000) seconds
0404:                // after the Wrapper the starts, which means the rollover will be well
0405:                // tested.
0406:                m_ticks = Integer.MAX_VALUE - 200;
0407:
0408:                m_useSystemTime = WrapperSystemPropertyUtil.getBooleanProperty(
0409:                        "wrapper.use_system_time", false);
0410:                m_timerFastThreshold = WrapperSystemPropertyUtil
0411:                        .getIntProperty("wrapper.timer_fast_threshold",
0412:                                TIMER_FAST_THRESHOLD)
0413:                        * 1000 / TICK_MS;
0414:                m_timerSlowThreshold = WrapperSystemPropertyUtil
0415:                        .getIntProperty("wrapper.timer_slow_threshold",
0416:                                TIMER_SLOW_THRESHOLD)
0417:                        * 1000 / TICK_MS;
0418:
0419:                // Check to see if we should register a shutdown hook
0420:                boolean disableShutdownHook = WrapperSystemPropertyUtil
0421:                        .getBooleanProperty("wrapper.disable_shutdown_hook",
0422:                                false);
0423:
0424:                // Locate the add and remove shutdown hook methods using reflection so
0425:                //  that this class can be compiled on 1.2.x versions of java.
0426:                try {
0427:                    m_addShutdownHookMethod = Runtime.class.getMethod(
0428:                            "addShutdownHook", new Class[] { Thread.class });
0429:                    m_removeShutdownHookMethod = Runtime.class.getMethod(
0430:                            "removeShutdownHook", new Class[] { Thread.class });
0431:                } catch (NoSuchMethodException e) {
0432:                    if (m_debug) {
0433:                        m_out
0434:                                .println("Wrapper Manager: Shutdown hooks not supported by current JVM.");
0435:                    }
0436:                    m_addShutdownHookMethod = null;
0437:                    m_removeShutdownHookMethod = null;
0438:                    disableShutdownHook = true;
0439:                }
0440:
0441:                // If the shutdown hook is not disabled, then register it.
0442:                if (!disableShutdownHook) {
0443:                    if (m_debug) {
0444:                        m_out
0445:                                .println("Wrapper Manager: Registering shutdown hook");
0446:                    }
0447:                    m_hook = new Thread("Wrapper-Shutdown-Hook") {
0448:                        /**
0449:                         * Run the shutdown hook. (Triggered by the JVM when it is about to shutdown)
0450:                         */
0451:                        public void run() {
0452:                            // Stop the Wrapper cleanly.
0453:                            m_hookTriggered = true;
0454:
0455:                            if (m_debug) {
0456:                                m_out
0457:                                        .println("Wrapper Manager: ShutdownHook started");
0458:                            }
0459:
0460:                            // Let the startup thread die since the shutdown hook is running.
0461:                            m_startupRunner = null;
0462:
0463:                            // If we are not already stopping, then do so.
0464:                            WrapperManager.stop(0);
0465:
0466:                            if (m_debug) {
0467:                                m_out
0468:                                        .println("Wrapper Manager: ShutdownHook complete");
0469:                            }
0470:                        }
0471:                    };
0472:
0473:                    // Actually register the shutdown hook using reflection.
0474:                    try {
0475:                        m_addShutdownHookMethod.invoke(Runtime.getRuntime(),
0476:                                new Object[] { m_hook });
0477:                    } catch (IllegalAccessException e) {
0478:                        m_out
0479:                                .println("Wrapper Manager: Unable to register shutdown hook: "
0480:                                        + e);
0481:                    } catch (InvocationTargetException e) {
0482:                        Throwable t = e.getTargetException();
0483:                        if (t == null) {
0484:                            t = e;
0485:                        }
0486:
0487:                        m_out
0488:                                .println("Wrapper Manager: Unable to register shutdown hook: "
0489:                                        + t);
0490:                    }
0491:                }
0492:
0493:                // A key is required for the wrapper to work correctly.  If it is not
0494:                //  present, then assume that we are not being controlled by the native
0495:                //  wrapper.
0496:                if ((m_key = System.getProperty("wrapper.key")) == null) {
0497:                    if (m_debug) {
0498:                        m_out
0499:                                .println("Wrapper Manager: Not using wrapper.  (key not specified)");
0500:                    }
0501:
0502:                    // The wrapper will not be used, so other values will not be used.
0503:                    m_port = 0;
0504:                    m_jvmPort = 0;
0505:                    m_jvmPortMin = 0;
0506:                    m_jvmPortMax = 0;
0507:                    m_service = false;
0508:                    m_cpuTimeout = 31557600000L; // One Year.  Effectively never.
0509:                } else {
0510:                    if (m_debug) {
0511:                        m_out.println("Wrapper Manager: Using wrapper");
0512:                    }
0513:
0514:                    // A port must have been specified.
0515:                    String sPort;
0516:                    if ((sPort = System.getProperty("wrapper.port")) == null) {
0517:                        String msg = m_res.format("MISSING_PORT");
0518:                        m_out.println(msg);
0519:                        throw new ExceptionInInitializerError(msg);
0520:                    }
0521:                    try {
0522:                        m_port = Integer.parseInt(sPort);
0523:                    } catch (NumberFormatException e) {
0524:                        String msg = m_res.format("BAD_PORT", sPort);
0525:                        m_out.println(msg);
0526:                        throw new ExceptionInInitializerError(msg);
0527:                    }
0528:
0529:                    m_jvmPort = WrapperSystemPropertyUtil.getIntProperty(
0530:                            "wrapper.jvm.port", 0);
0531:                    m_jvmPortMin = WrapperSystemPropertyUtil.getIntProperty(
0532:                            "wrapper.jvm.port.min", 31000);
0533:                    m_jvmPortMax = WrapperSystemPropertyUtil.getIntProperty(
0534:                            "wrapper.jvm.port.max", 31999);
0535:
0536:                    // Check for the ignore signals flag
0537:                    m_ignoreSignals = WrapperSystemPropertyUtil
0538:                            .getBooleanProperty("wrapper.ignore_signals", false);
0539:
0540:                    // If this is being run as a headless server, then a flag would have been set
0541:                    m_service = WrapperSystemPropertyUtil.getBooleanProperty(
0542:                            "wrapper.service", false);
0543:
0544:                    // Get the cpuTimeout
0545:                    String sCPUTimeout = System
0546:                            .getProperty("wrapper.cpu.timeout");
0547:                    if (sCPUTimeout == null) {
0548:                        m_cpuTimeout = DEFAULT_CPU_TIMEOUT;
0549:                    } else {
0550:                        try {
0551:                            m_cpuTimeout = Integer.parseInt(sCPUTimeout) * 1000L;
0552:                        } catch (NumberFormatException e) {
0553:                            String msg = m_res.format("BAD_CPU_TIMEOUT",
0554:                                    sCPUTimeout);
0555:                            m_out.println(msg);
0556:                            throw new ExceptionInInitializerError(msg);
0557:                        }
0558:                    }
0559:                }
0560:
0561:                // Make sure that the version of the Wrapper is correct.
0562:                verifyWrapperVersion();
0563:
0564:                // Register the MBeans if configured to do so.
0565:                if (WrapperSystemPropertyUtil.getBooleanProperty(
0566:                        WrapperManager.class.getName() + ".mbean", true)) {
0567:                    registerMBean(
0568:                            new org.tanukisoftware.wrapper.jmx.WrapperManager(),
0569:                            "org.tanukisoftware.wrapper:type=WrapperManager");
0570:                }
0571:                if (WrapperSystemPropertyUtil.getBooleanProperty(
0572:                        WrapperManager.class.getName() + ".mbean.testing",
0573:                        false)) {
0574:                    registerMBean(
0575:                            new org.tanukisoftware.wrapper.jmx.WrapperManagerTesting(),
0576:                            "org.tanukisoftware.wrapper:type=WrapperManagerTesting");
0577:                }
0578:
0579:                // Initialize the native code to trap system signals
0580:                initializeNativeLibrary();
0581:
0582:                if (m_libraryOK) {
0583:                    // Make sure that the native library's version is correct.
0584:                    verifyNativeLibraryVersion();
0585:
0586:                    // Get the PID of the current JVM from the native library.  Be careful as the method
0587:                    //  will not exist if the library is old.
0588:                    try {
0589:                        System.setProperty("wrapper.java.pid", Integer
0590:                                .toString(nativeGetJavaPID()));
0591:                    } catch (Throwable e) {
0592:                        if (m_debug) {
0593:                            m_out.println("Call to nativeGetJavaPID() failed: "
0594:                                    + e);
0595:                        }
0596:                    }
0597:                }
0598:
0599:                // Start a thread which looks for control events sent to the
0600:                //  process.  The thread is also used to keep track of whether
0601:                //  the VM has been getting CPU to avoid invalid timeouts and
0602:                //  to maintain the number of ticks since the JVM was launched.
0603:                m_eventRunnerTicks = getTicks();
0604:                m_eventRunner = new Thread("Wrapper-Control-Event-Monitor") {
0605:                    public void run() {
0606:                        if (m_debug) {
0607:                            m_out
0608:                                    .println("Control event monitor thread started.");
0609:                        }
0610:
0611:                        try {
0612:                            WrapperTickEventImpl tickEvent = new WrapperTickEventImpl();
0613:                            int lastTickOffset = 0;
0614:                            boolean first = true;
0615:
0616:                            while (!m_shuttingDown) {
0617:                                int offsetDiff;
0618:                                if (!m_useSystemTime) {
0619:                                    // Get the tick count based on the system time.
0620:                                    int sysTicks = getSystemTicks();
0621:
0622:                                    // Increment the tick counter by 1. This loop takes just slightly
0623:                                    //  more than the length of a "tick" but it is a good enough
0624:                                    //  approximation for our purposes.  The accuracy of the tick length
0625:                                    //  falls sharply when the system is under heavly load, but this
0626:                                    //  has the desired effect as the Wrapper is also much less likely
0627:                                    //  to encounter false timeouts due to the heavy load.
0628:                                    // The ticks field is volatile and a single integer, so it is not
0629:                                    //  necessary to synchronize this.
0630:                                    // When the ticks count reaches the upper limit of the int range,
0631:                                    //  it is ok to just let it overflow and wrap.
0632:                                    m_ticks++;
0633:
0634:                                    // Calculate the offset between the two tick counts.
0635:                                    //  This will always work due to overflow.
0636:                                    int tickOffset = sysTicks - m_ticks;
0637:
0638:                                    // The number we really want is the difference between this tickOffset
0639:                                    //  and the previous one.
0640:                                    offsetDiff = tickOffset - lastTickOffset;
0641:
0642:                                    if (first) {
0643:                                        first = false;
0644:                                    } else {
0645:                                        if (offsetDiff > m_timerSlowThreshold) {
0646:                                            m_out
0647:                                                    .println("The timer fell behind the system clock by "
0648:                                                            + (offsetDiff * TICK_MS)
0649:                                                            + "ms.");
0650:                                        } else if (offsetDiff < -m_timerFastThreshold) {
0651:                                            m_out
0652:                                                    .println("The system clock fell behind the timer by "
0653:                                                            + (-1 * offsetDiff * TICK_MS)
0654:                                                            + "ms.");
0655:                                        }
0656:                                    }
0657:
0658:                                    // Store this tick offset for the net time through the loop.
0659:                                    lastTickOffset = tickOffset;
0660:                                } else {
0661:                                    offsetDiff = 0;
0662:                                }
0663:
0664:                                //m_out.println( "  UNIX Time: " + Long.toHexString( System.currentTimeMillis() )
0665:                                //  + ", ticks=" + Integer.toHexString( getTicks() ) + ", sysTicks="
0666:                                //  + Integer.toHexString( getSystemTicks() ) );
0667:
0668:                                // Attempt to detect whether or not we are being starved of CPU.
0669:                                //  This will only have any effect if the m_useSystemTime flag is
0670:                                //  set.
0671:                                int nowTicks = getTicks();
0672:                                long age = getTickAge(m_eventRunnerTicks,
0673:                                        nowTicks);
0674:                                if ((m_cpuTimeout > 0) && (age > m_cpuTimeout)) {
0675:                                    m_out
0676:                                            .println("JVM Process has not received any CPU time for "
0677:                                                    + (age / 1000)
0678:                                                    + " seconds.  Extending timeouts.");
0679:
0680:                                    // Make sure that we don't get any ping timeouts in this event
0681:                                    m_lastPingTicks = nowTicks;
0682:                                }
0683:                                m_eventRunnerTicks = nowTicks;
0684:
0685:                                // If there are any listeners interrested in core events then fire
0686:                                //  off a tick event.
0687:                                if (m_produceCoreEvents) {
0688:                                    tickEvent.m_ticks = nowTicks;
0689:                                    tickEvent.m_tickOffset = offsetDiff;
0690:                                    fireWrapperEvent(tickEvent);
0691:                                }
0692:
0693:                                if (m_libraryOK) {
0694:                                    // Look for a control event in the wrapper library
0695:                                    int event = WrapperManager
0696:                                            .nativeGetControlEvent();
0697:                                    if (event != 0) {
0698:                                        WrapperManager.controlEvent(event);
0699:                                    }
0700:                                }
0701:
0702:                                // Wait before checking for another control event.
0703:                                try {
0704:                                    Thread.sleep(TICK_MS);
0705:                                } catch (InterruptedException e) {
0706:                                }
0707:                            }
0708:                        } finally {
0709:                            if (m_debug) {
0710:                                m_out
0711:                                        .println("Control event monitor thread stopped.");
0712:                            }
0713:                        }
0714:                    }
0715:                };
0716:                m_eventRunner.setDaemon(true);
0717:                m_eventRunner.start();
0718:
0719:                // Resolve the system thread count based on the Java Version
0720:                String fullVersion = System.getProperty("java.fullversion");
0721:                String vendor = System.getProperty("java.vm.vendor", "");
0722:                String os = System.getProperty("os.name", "").toLowerCase();
0723:                if (fullVersion == null) {
0724:                    fullVersion = System.getProperty("java.runtime.version")
0725:                            + " " + System.getProperty("java.vm.name");
0726:                }
0727:
0728:                if (m_debug) {
0729:                    // Display more JVM infor right after the call initialization of the library.
0730:                    m_out.println("Java Version   : " + fullVersion);
0731:                    m_out.println("Java VM Vendor : " + vendor);
0732:                    m_out.println();
0733:                }
0734:
0735:                // This thread will most likely be thread which launches the JVM.
0736:                //  Once this method returns however, the main thread will likely
0737:                //  quit.  There will be a slight delay before the Wrapper binary
0738:                //  has a change to send a command to start the application.
0739:                //  During this lag, the JVM may not have any non-daemon threads
0740:                //  running and would exit.   To keep it from doing so, start a
0741:                //  simple non-daemon thread which will run until the
0742:                //  WrapperListener.start() method returns or the Wrapper's
0743:                //  shutdown thread has started.
0744:                m_startupRunner = new Thread("Wrapper-Startup-Runner") {
0745:                    public void run() {
0746:                        if (m_debug) {
0747:                            m_out.println("Startup runner thread started.");
0748:                        }
0749:
0750:                        try {
0751:                            while (m_startupRunner != null) {
0752:                                try {
0753:                                    Thread.sleep(100);
0754:                                } catch (InterruptedException e) {
0755:                                    // Ignore.
0756:                                }
0757:                            }
0758:                        } finally {
0759:                            if (m_debug) {
0760:                                m_out.println("Startup runner thread stopped.");
0761:                            }
0762:                        }
0763:                    }
0764:                };
0765:                // This thread must not be a daemon thread.
0766:                m_startupRunner.setDaemon(false);
0767:                m_startupRunner.start();
0768:
0769:                // Create the singleton
0770:                m_instance = new WrapperManager();
0771:            }
0772:
0773:            /*---------------------------------------------------------------
0774:             * Native Methods
0775:             *-------------------------------------------------------------*/
0776:            private static native void nativeInit(boolean debug);
0777:
0778:            private static native String nativeGetLibraryVersion();
0779:
0780:            private static native int nativeGetJavaPID();
0781:
0782:            private static native int nativeGetControlEvent();
0783:
0784:            private static native void nativeRequestThreadDump();
0785:
0786:            private static native void accessViolationInner();
0787:
0788:            private static native void nativeSetConsoleTitle(byte[] titleBytes);
0789:
0790:            private static native WrapperUser nativeGetUser(boolean groups);
0791:
0792:            private static native WrapperUser nativeGetInteractiveUser(
0793:                    boolean groups);
0794:
0795:            private static native WrapperWin32Service[] nativeListServices();
0796:
0797:            private static native WrapperWin32Service nativeSendServiceControlCode(
0798:                    byte[] serviceName, int controlCode);
0799:
0800:            /*---------------------------------------------------------------
0801:             * Methods
0802:             *-------------------------------------------------------------*/
0803:            /**
0804:             * Returns a tick count calculated from the system clock.
0805:             */
0806:            private static int getSystemTicks() {
0807:                // Calculate a tick count using the current system time.  The
0808:                //  conversion from a long in ms, to an int in TICK_MS increments
0809:                //  will result in data loss, but the loss of bits and resulting
0810:                //  overflow is expected and Ok.
0811:                return (int) (System.currentTimeMillis() / TICK_MS);
0812:            }
0813:
0814:            /**
0815:             * Returns the number of ticks since the JVM was launched.  This
0816:             *  count is not good enough to be used where accuracy is required but
0817:             *  it allows us to implement timeouts in environments where the system
0818:             *  time is modified while the JVM is running.
0819:             * <p>
0820:             * An int is used rather than a long so the counter can be implemented
0821:             *  without requiring any synchronization.  At the tick resolution, the
0822:             *  tick counter will overflow and wrap (every 6.8 years for 100ms ticks).
0823:             *  This behavior is expected.  The getTickAge method should be used
0824:             *  in cases where the difference between two ticks is required.
0825:             *
0826:             * Returns the tick count.
0827:             */
0828:            private static int getTicks() {
0829:                if (m_useSystemTime) {
0830:                    return getSystemTicks();
0831:                } else {
0832:                    return m_ticks;
0833:                }
0834:            }
0835:
0836:            /**
0837:             * Returns the number of milliseconds that have elapsed between the
0838:             *  start and end counters.  This method assumes that both tick counts
0839:             *  were obtained by calling getTicks().  This method will correctly
0840:             *  handle cases where the tick counter has overflowed and reset.
0841:             *
0842:             * @param start A base tick count.
0843:             * @param end An end tick count.
0844:             *
0845:             * @return The number of milliseconds that are represented by the
0846:             *         difference between the two specified tick counts.
0847:             */
0848:            private static long getTickAge(int start, int end) {
0849:                // Important to cast the first value so that negative values are correctly
0850:                //  cast to negative long values.
0851:                return (long) (end - start) * TICK_MS;
0852:            }
0853:
0854:            /**
0855:             * Attempts to load the a native library file.
0856:             *
0857:             * @param name Name of the library to load.
0858:             * @param file Name of the actual library file.
0859:             *
0860:             * @return null if the library was successfully loaded, an error message
0861:             *         otherwise.
0862:             */
0863:            private static String loadNativeLibrary(String name, String file) {
0864:                try {
0865:                    System.loadLibrary(name);
0866:
0867:                    if (m_debug) {
0868:                        m_out.println("Loaded native library: " + file);
0869:                    }
0870:
0871:                    return null;
0872:                } catch (UnsatisfiedLinkError e) {
0873:                    if (m_debug) {
0874:                        m_out.println("Loading native library failed: " + file
0875:                                + "  Cause: " + e);
0876:                    }
0877:                    String error = e.getMessage();
0878:                    if (error == null) {
0879:                        error = e.toString();
0880:                    }
0881:                    return error;
0882:                } catch (Throwable e) {
0883:                    if (m_debug) {
0884:                        m_out.println("Loading native library failed: " + file
0885:                                + "  Cause: " + e);
0886:                    }
0887:                    String error = e.toString();
0888:                    return error;
0889:                }
0890:            }
0891:
0892:            /**
0893:             * Java 1.5 and above supports the ability to register the WrapperManager
0894:             *  MBean internally.
0895:             */
0896:            private static void registerMBean(Object mbean, String name) {
0897:                Class classManagementFactory;
0898:                try {
0899:                    classManagementFactory = Class
0900:                            .forName("java.lang.management.ManagementFactory");
0901:                } catch (ClassNotFoundException e) {
0902:                    if (m_debug) {
0903:                        m_out
0904:                                .println("Registering MBeans not supported by current JVM: "
0905:                                        + name);
0906:                    }
0907:                    return;
0908:                }
0909:
0910:                try {
0911:                    // This code uses reflection so it combiles on older JVMs.
0912:                    // The original code is as follows:
0913:                    // javax.management.MBeanServer mbs =
0914:                    //     java.lang.management.ManagementFactory.getPlatformMBeanServer();
0915:                    // javax.management.ObjectName oName = new javax.management.ObjectName( name );
0916:                    // mbs.registerMBean( mbean, oName );
0917:
0918:                    // The version of the above code using reflection follows.
0919:                    Class classMBeanServer = Class
0920:                            .forName("javax.management.MBeanServer");
0921:                    Class classObjectName = Class
0922:                            .forName("javax.management.ObjectName");
0923:                    Method methodGetPlatformMBeanServer = classManagementFactory
0924:                            .getMethod("getPlatformMBeanServer", null);
0925:                    Constructor constructorObjectName = classObjectName
0926:                            .getConstructor(new Class[] { String.class });
0927:                    Method methodRegisterMBean = classMBeanServer.getMethod(
0928:                            "registerMBean", new Class[] { Object.class,
0929:                                    classObjectName });
0930:                    Object mbs = methodGetPlatformMBeanServer
0931:                            .invoke(null, null);
0932:                    Object oName = constructorObjectName
0933:                            .newInstance(new Object[] { name });
0934:                    methodRegisterMBean.invoke(mbs,
0935:                            new Object[] { mbean, oName });
0936:
0937:                    if (m_debug) {
0938:                        m_out
0939:                                .println("Registered MBean with Platform MBean Server: "
0940:                                        + name);
0941:                    }
0942:                } catch (Throwable t) {
0943:                    m_err.println("Unable to register the " + name + " MBean.");
0944:                    t.printStackTrace();
0945:                }
0946:            }
0947:
0948:            /**
0949:             * Searches for a file on a path.
0950:             *
0951:             * @param file File to look for.
0952:             * @param path Path to be searched.
0953:             *
0954:             * @return Reference to thr file object if found, otherwise null.
0955:             */
0956:            private static File locateFileOnPath(String file, String path) {
0957:                // A library path exists but the library was not found on it.
0958:                String pathSep = System.getProperty("path.separator");
0959:
0960:                // Search for the file on the library path to verify that it does not
0961:                //  exist, it could be some other problem
0962:                StringTokenizer st = new StringTokenizer(path, pathSep);
0963:                while (st.hasMoreTokens()) {
0964:                    File libFile = new File(new File(st.nextToken()), file);
0965:                    if (libFile.exists()) {
0966:                        return libFile;
0967:                    }
0968:                }
0969:
0970:                return null;
0971:            }
0972:
0973:            /**
0974:             * Generates a detailed native library base name which is made up of the
0975:             *  base name, the os name, architecture, and the bits of the current JVM,
0976:             *  not the platform.
0977:             *
0978:             * @return A detailed native library base name.
0979:             */
0980:            private static String generateDetailedNativeLibraryBaseName(
0981:                    String baseName, int jvmBits, boolean universal) {
0982:                // Generate an os name.  Most names are used as is, but some are modified.
0983:                String os = System.getProperty("os.name", "").toLowerCase();
0984:                if (os.startsWith("windows")) {
0985:                    os = "windows";
0986:                } else if (os.equals("sunos")) {
0987:                    os = "solaris";
0988:                } else if (os.equals("hp-ux") || os.equals("hp-ux64")) {
0989:                    os = "hpux";
0990:                } else if (os.equals("mac os x")) {
0991:                    os = "macosx";
0992:                } else if (os.equals("unix_sv")) {
0993:                    os = "unixware";
0994:                }
0995:
0996:                // Generate an architecture name.
0997:                String arch = System.getProperty("os.arch", "").toLowerCase();
0998:                if (universal) {
0999:                    arch = "universal";
1000:                } else {
1001:                    if (arch.equals("amd64") || arch.equals("athlon")
1002:                            || arch.equals("ia32") || arch.equals("ia64")
1003:                            || arch.equals("x86_64") || arch.equals("i686")
1004:                            || arch.equals("i586") || arch.equals("i486")
1005:                            || arch.equals("i386")) {
1006:                        arch = "x86";
1007:                    } else if (arch.startsWith("sparc")) {
1008:                        arch = "sparc";
1009:                    } else if (arch.equals("power") || arch.equals("powerpc")
1010:                            || arch.equals("ppc64")) {
1011:                        arch = "ppc";
1012:                    } else if (arch.equals("pa_risc") || arch.equals("pa-risc")) {
1013:                        arch = "parisc";
1014:                    }
1015:                }
1016:
1017:                return baseName + "-" + os + "-" + arch + "-" + jvmBits;
1018:            }
1019:
1020:            /**
1021:             * Searches for and then loads the native library.  This method will attempt
1022:             *  locate the wrapper library using one of the following 3 naming 
1023:             */
1024:            private static void initializeNativeLibrary() {
1025:                // Resolve the osname and osarch for the currect system.
1026:                String osName = System.getProperty("os.name").toLowerCase();
1027:
1028:                // Look for the base name of the library.
1029:                String baseName = System.getProperty("wrapper.native_library");
1030:                if (baseName == null) {
1031:                    // This should only happen if an old version of the Wrapper binary is being used.
1032:                    m_out
1033:                            .println("WARNING - The wrapper.native_library system property was not");
1034:                    m_out
1035:                            .println("          set. Using the default value, 'wrapper'.");
1036:                    baseName = "wrapper";
1037:                }
1038:                String[] detailedNames = new String[4];
1039:                if (m_jvmBits > 0) {
1040:                    detailedNames[0] = generateDetailedNativeLibraryBaseName(
1041:                            baseName, m_jvmBits, false);
1042:                    if (osName.startsWith("mac")) {
1043:                        detailedNames[1] = generateDetailedNativeLibraryBaseName(
1044:                                baseName, m_jvmBits, true);
1045:                    }
1046:                } else {
1047:                    detailedNames[0] = generateDetailedNativeLibraryBaseName(
1048:                            baseName, 32, false);
1049:                    detailedNames[1] = generateDetailedNativeLibraryBaseName(
1050:                            baseName, 64, false);
1051:                    if (osName.startsWith("mac")) {
1052:                        detailedNames[2] = generateDetailedNativeLibraryBaseName(
1053:                                baseName, 32, true);
1054:                        detailedNames[3] = generateDetailedNativeLibraryBaseName(
1055:                                baseName, 64, true);
1056:                    }
1057:                }
1058:
1059:                // Construct brief and detailed native library file names.
1060:                String file = System.mapLibraryName(baseName);
1061:                String[] detailedFiles = new String[detailedNames.length];
1062:                for (int i = 0; i < detailedNames.length; i++) {
1063:                    if (detailedNames[i] != null) {
1064:                        detailedFiles[i] = System
1065:                                .mapLibraryName(detailedNames[i]);
1066:                    }
1067:                }
1068:
1069:                String[] detailedErrors = new String[detailedNames.length];
1070:                String baseError = null;
1071:
1072:                // Try loading the native library using the detailed name first.  If that fails, use
1073:                //  the brief name.
1074:                if (m_debug) {
1075:                    m_out
1076:                            .println("Load native library.  One or more attempts may fail if platform "
1077:                                    + "specific libraries do not exist.");
1078:                }
1079:                m_libraryOK = false;
1080:                for (int i = 0; i < detailedNames.length; i++) {
1081:                    if (detailedNames[i] != null) {
1082:                        detailedErrors[i] = loadNativeLibrary(detailedNames[i],
1083:                                detailedFiles[i]);
1084:                        if (detailedErrors[i] == null) {
1085:                            m_libraryOK = true;
1086:                            break;
1087:                        }
1088:                    }
1089:                }
1090:                if ((!m_libraryOK)
1091:                        && ((baseError = loadNativeLibrary(baseName, file)) == null)) {
1092:                    m_libraryOK = true;
1093:                }
1094:                if (m_libraryOK) {
1095:                    // The library was loaded correctly, so initialize it.
1096:                    if (m_debug) {
1097:                        m_out.println("Calling native initialization method.");
1098:                    }
1099:                    nativeInit(m_debug);
1100:                } else {
1101:                    // The library could not be loaded, so we want to give the user a useful
1102:                    //  clue as to why not.
1103:                    String libPath = System.getProperty("java.library.path");
1104:                    m_out.println();
1105:                    if (libPath.equals("")) {
1106:                        // No library path
1107:                        m_out
1108:                                .println("WARNING - Unable to load the Wrapper's native library because the");
1109:                        m_out
1110:                                .println("          java.library.path was set to ''.  Please see the");
1111:                        m_out
1112:                                .println("          documentation for the wrapper.java.library.path ");
1113:                        m_out.println("          configuration property.");
1114:                    } else {
1115:                        // Attempt to locate the actual files on the path.
1116:                        String error = null;
1117:                        File libFile = null;
1118:                        for (int i = 0; i < detailedNames.length; i++) {
1119:                            if (detailedFiles[i] != null) {
1120:                                libFile = locateFileOnPath(detailedFiles[i],
1121:                                        libPath);
1122:                                if (libFile != null) {
1123:                                    error = detailedErrors[i];
1124:                                    break;
1125:                                }
1126:                            }
1127:                        }
1128:                        if (libFile == null) {
1129:                            libFile = locateFileOnPath(file, libPath);
1130:                            if (libFile != null) {
1131:                                error = baseError;
1132:                            }
1133:                        }
1134:                        if (libFile == null) {
1135:                            // The library could not be located on the library path.
1136:                            m_out
1137:                                    .println("WARNING - Unable to load the Wrapper's native library because none of the");
1138:                            m_out.println("          following files:");
1139:                            for (int i = 0; i < detailedNames.length; i++) {
1140:                                if (detailedFiles[i] != null) {
1141:                                    m_out.println("            "
1142:                                            + detailedFiles[i]);
1143:                                }
1144:                            }
1145:                            m_out.println("            " + file);
1146:                            m_out
1147:                                    .println("          could be located on the following java.library.path:");
1148:
1149:                            String pathSep = System
1150:                                    .getProperty("path.separator");
1151:                            StringTokenizer st = new StringTokenizer(libPath,
1152:                                    pathSep);
1153:                            while (st.hasMoreTokens()) {
1154:                                File pathElement = new File(st.nextToken());
1155:                                m_out.println("            "
1156:                                        + pathElement.getAbsolutePath());
1157:                            }
1158:                            m_out
1159:                                    .println("          Please see the documentation for the "
1160:                                            + "wrapper.java.library.path");
1161:                            m_out.println("          configuration property.");
1162:                        } else {
1163:                            // The library file was found but could not be loaded for some reason.
1164:                            m_out
1165:                                    .println("WARNING - Unable to load the Wrapper's native library '"
1166:                                            + libFile.getName() + "'.");
1167:                            m_out
1168:                                    .println("          The file is located on the path at the following location but");
1169:                            m_out.println("          could not be loaded:");
1170:                            m_out.println("            "
1171:                                    + libFile.getAbsolutePath());
1172:                            m_out
1173:                                    .println("          Please verify that the file is readable by the current user");
1174:                            m_out
1175:                                    .println("          and that the file has not been corrupted in any way.");
1176:                            m_out
1177:                                    .println("          One common cause of this problem is running a 32-bit version");
1178:                            m_out
1179:                                    .println("          of the Wrapper with a 64-bit version of Java, or vica versa.");
1180:                            if (m_jvmBits > 0) {
1181:                                m_out.println("          This is a "
1182:                                        + m_jvmBits + "-bit JVM.");
1183:                            } else {
1184:                                m_out
1185:                                        .println("          The bit depth of this JVM could not be determined.");
1186:                            }
1187:                            m_out.println("          Reported cause:");
1188:                            m_out.println("            " + error);
1189:                        }
1190:                    }
1191:                    m_out
1192:                            .println("          System signals will not be handled correctly.");
1193:                    m_out.println();
1194:                }
1195:            }
1196:
1197:            /**
1198:             * Compares the version of the wrapper which launched this JVM with that of
1199:             *  the jar.  If they differ then a Warning message will be displayed.  The
1200:             *  Wrapper application will still be allowed to start.
1201:             */
1202:            private static void verifyWrapperVersion() {
1203:                // If we are not being controlled by the wrapper then return.
1204:                if (!WrapperManager.isControlledByNativeWrapper()) {
1205:                    return;
1206:                }
1207:
1208:                // Lookup the version from the wrapper.  It should have been set as a property
1209:                //  when the JVM was launched.
1210:                String wrapperVersion = System.getProperty("wrapper.version");
1211:                if (wrapperVersion == null) {
1212:                    wrapperVersion = "unknown";
1213:                }
1214:
1215:                if (!WrapperInfo.getVersion().equals(wrapperVersion)) {
1216:                    m_out
1217:                            .println("WARNING - The Wrapper jar file currently in use is version \""
1218:                                    + WrapperInfo.getVersion() + "\"");
1219:                    m_out
1220:                            .println("          while the version of the Wrapper which launched this JVM is ");
1221:                    m_out.println("          \"" + wrapperVersion + "\".");
1222:                    m_out
1223:                            .println("          The Wrapper may appear to work correctly but some features may");
1224:                    m_out
1225:                            .println("          not function correctly.  This configuration has not been tested");
1226:                    m_out.println("          and is not supported.");
1227:                    m_out.println();
1228:                }
1229:            }
1230:
1231:            /**
1232:             * Compares the version of the native library with that of this jar.  If
1233:             *  they differ then a Warning message will be displayed.  The Wrapper
1234:             *  application will still be allowed to start.
1235:             */
1236:            private static void verifyNativeLibraryVersion() {
1237:                // Request the version from the native library.  Be careful as the method
1238:                //  will not exist if the library is old.
1239:                String jniVersion;
1240:                try {
1241:                    jniVersion = nativeGetLibraryVersion();
1242:                } catch (Throwable e) {
1243:                    if (m_debug) {
1244:                        m_out
1245:                                .println("Call to nativeGetLibraryVersion() failed: "
1246:                                        + e);
1247:                    }
1248:                    jniVersion = "unknown";
1249:                }
1250:
1251:                if (!WrapperInfo.getVersion().equals(jniVersion)) {
1252:                    m_out
1253:                            .println("WARNING - The Wrapper jar file currently in use is version \""
1254:                                    + WrapperInfo.getVersion() + "\"");
1255:                    m_out
1256:                            .println("          while the version of the native library is \""
1257:                                    + jniVersion + "\".");
1258:                    m_out
1259:                            .println("          The Wrapper may appear to work correctly but some features may");
1260:                    m_out
1261:                            .println("          not function correctly.  This configuration has not been tested");
1262:                    m_out.println("          and is not supported.");
1263:                    m_out.println();
1264:                }
1265:            }
1266:
1267:            /**
1268:             * Obtain the current version of Wrapper.
1269:             *
1270:             * @return The version of the Wrapper.
1271:             */
1272:            public static String getVersion() {
1273:                return WrapperInfo.getVersion();
1274:            }
1275:
1276:            /**
1277:             * Obtain the build time of Wrapper.
1278:             *
1279:             * @return The time that the Wrapper was built.
1280:             */
1281:            public static String getBuildTime() {
1282:                return WrapperInfo.getBuildTime();
1283:            }
1284:
1285:            /**
1286:             * Returns the Id of the current JVM.  JVM Ids increment from 1 each time
1287:             *  the wrapper restarts a new one.
1288:             *
1289:             * @return The Id of the current JVM.
1290:             */
1291:            public static int getJVMId() {
1292:                return m_jvmId;
1293:            }
1294:
1295:            /**
1296:             * Sets the title of the console in which the Wrapper is running.  This
1297:             *  is currently only supported on Windows platforms.
1298:             * <p>
1299:             * As an alternative, it is also possible to set the console title from
1300:             *  within the wrapper.conf file using the wrapper.console.title property.
1301:             *
1302:             * @param title The new title.  The specified string will be encoded
1303:             *              to a byte array using the default encoding for the
1304:             *              current platform.
1305:             */
1306:            public static void setConsoleTitle(String title) {
1307:                SecurityManager sm = System.getSecurityManager();
1308:                if (sm != null) {
1309:                    sm
1310:                            .checkPermission(new WrapperPermission(
1311:                                    "setConsoleTitle"));
1312:                }
1313:
1314:                if (m_libraryOK) {
1315:                    // Convert the unicode string to a string of bytes using the default
1316:                    //  platform encoding.
1317:                    byte[] titleBytes = title.getBytes();
1318:
1319:                    // We need a null terminated string.
1320:                    byte[] nullTermBytes = new byte[titleBytes.length + 1];
1321:                    System.arraycopy(titleBytes, 0, nullTermBytes, 0,
1322:                            titleBytes.length);
1323:                    nullTermBytes[titleBytes.length] = 0;
1324:
1325:                    nativeSetConsoleTitle(nullTermBytes);
1326:                }
1327:            }
1328:
1329:            /**
1330:             * Returns a WrapperUser object which describes the user under which the
1331:             *  Wrapper is currently running.  Additional platform specific information
1332:             *  can be obtained by casting the object to a platform specific subclass.
1333:             *  WrapperWin32User, for example.
1334:             *
1335:             * @param groups True if the user's groups should be returned as well.
1336:             *               Requesting the groups that a user belongs to increases
1337:             *               the CPU load required to complete the call.
1338:             *
1339:             * @return An object describing the current user.
1340:             */
1341:            public static WrapperUser getUser(boolean groups) {
1342:                SecurityManager sm = System.getSecurityManager();
1343:                if (sm != null) {
1344:                    sm.checkPermission(new WrapperPermission("getUser"));
1345:                }
1346:
1347:                WrapperUser user = null;
1348:                if (m_libraryOK) {
1349:                    user = nativeGetUser(groups);
1350:                }
1351:                return user;
1352:            }
1353:
1354:            /**
1355:             * Returns a WrapperUser object which describes the interactive user whose
1356:             *  desktop is being interacted with.  When a service running on a Windows
1357:             *  platform has its interactive flag set, this method will return the user
1358:             *  who is currently logged in.  Additional platform specific information
1359:             *  can be obtained by casting the object to a platform specific subclass.
1360:             *  WrapperWin32User, for example.
1361:             * <p>
1362:             * If a user is not currently logged on then this method will return null.
1363:             *  User code can repeatedly call this method to detect when a user has
1364:             *  logged in.  To detect when a user has logged out, there are two options.
1365:             *  1) The user code can continue to call this method until it returns null.
1366:             *  2) Or if the WrapperListener method is being implemented, the
1367:             *     WrapperListener.controlEvent method will receive a WRAPPER_CTRL_LOGOFF_EVENT
1368:             *     event when the user logs out.
1369:             * <p>
1370:             * On XP systems, it is possible to switch to another account rather than
1371:             *  actually logging out.  In such a case, the interactive user will be
1372:             *  the first user that logged in.  This will also be the only user with
1373:             *  which the service will interact.  If other users are logged in when the
1374:             *  interactive user logs out, the service will not automatically switch to
1375:             *  another logged in user.  Rather, the next user to log in will become
1376:             *  the new user which the service will interact with.
1377:             * <p>
1378:             * This method will always return NULL on versions of NT prior to Windows
1379:             *  2000.  This can not be helped as some required functions were not added
1380:             *  to the windows API until NT version 5.0, also known as Windows 2000.
1381:             *
1382:             * @param groups True if the user's groups should be returned as well.
1383:             *               Requesting the groups that a user belongs to increases
1384:             *               the CPU load required to complete the call.
1385:             *
1386:             * @return The current interactive user, or null.
1387:             */
1388:            public static WrapperUser getInteractiveUser(boolean groups) {
1389:                SecurityManager sm = System.getSecurityManager();
1390:                if (sm != null) {
1391:                    sm.checkPermission(new WrapperPermission(
1392:                            "getInteractiveUser"));
1393:                }
1394:
1395:                WrapperUser user = null;
1396:                if (m_libraryOK) {
1397:                    user = nativeGetInteractiveUser(groups);
1398:                }
1399:                return user;
1400:            }
1401:
1402:            /**
1403:             * Returns a Properties object containing expanded the contents of the
1404:             *  configuration file used to launch the Wrapper.
1405:             *
1406:             * All properties are included so it is possible to define properties
1407:             *  not used by the Wrapper in the configuration file and have then
1408:             *  be available in this Properties object.
1409:             *
1410:             * @return The contents of the Wrapper configuration file.
1411:             */
1412:            public static Properties getProperties() {
1413:                SecurityManager sm = System.getSecurityManager();
1414:                if (sm != null) {
1415:                    sm.checkPermission(new WrapperPermission("getProperties"));
1416:                }
1417:
1418:                return m_properties;
1419:            }
1420:
1421:            /**
1422:             * Returns the PID of the Wrapper process.
1423:             *
1424:             * A PID of 0 will be returned if the JVM was launched standalone.
1425:             *
1426:             * This value can also be obtained using the 'wrapper.pid' system property.
1427:             *
1428:             * @return The PID of the Wrpper process.
1429:             */
1430:            public static int getWrapperPID() {
1431:                SecurityManager sm = System.getSecurityManager();
1432:                if (sm != null) {
1433:                    sm.checkPermission(new WrapperPermission("getWrapperPID"));
1434:                }
1435:
1436:                return WrapperSystemPropertyUtil.getIntProperty("wrapper.pid",
1437:                        0);
1438:            }
1439:
1440:            /**
1441:             * Returns the PID of the Java process.
1442:             *
1443:             * A PID of 0 will be returned if the native library has not been initialized.
1444:             *
1445:             * This value can also be obtained using the 'wrapper.java.pid' system property.
1446:             *
1447:             * @return The PID of the Java process.
1448:             */
1449:            public static int getJavaPID() {
1450:                SecurityManager sm = System.getSecurityManager();
1451:                if (sm != null) {
1452:                    sm.checkPermission(new WrapperPermission("getJavaPID"));
1453:                }
1454:
1455:                return WrapperSystemPropertyUtil.getIntProperty(
1456:                        "wrapper.java.pid", 0);
1457:            }
1458:
1459:            /**
1460:             * Requests that the current JVM process request a thread dump.  This is
1461:             *  the same as pressing CTRL-BREAK (under Windows) or CTRL-\ (under Unix)
1462:             *  in the the console in which Java is running.  This method does nothing
1463:             *  if the native library is not loaded.
1464:             */
1465:            public static void requestThreadDump() {
1466:                SecurityManager sm = System.getSecurityManager();
1467:                if (sm != null) {
1468:                    sm.checkPermission(new WrapperPermission(
1469:                            "requestThreadDump"));
1470:                }
1471:
1472:                if (m_libraryOK) {
1473:                    nativeRequestThreadDump();
1474:                } else {
1475:                    m_out.println("  wrapper library not loaded.");
1476:                }
1477:            }
1478:
1479:            /**
1480:             * (Testing Method) Causes the WrapperManager to go into a state which makes the JVM appear
1481:             *  to be hung when viewed from the native Wrapper code.  Does not have any effect when the
1482:             *  JVM is not being controlled from the native Wrapper. Useful for testing the Wrapper 
1483:             *  functions.
1484:             */
1485:            public static void appearHung() {
1486:                SecurityManager sm = System.getSecurityManager();
1487:                if (sm != null) {
1488:                    sm
1489:                            .checkPermission(new WrapperPermission(
1490:                                    "test.appearHung"));
1491:                }
1492:
1493:                m_out.println("WARNING: Making JVM appear to be hung...");
1494:                m_appearHung = true;
1495:            }
1496:
1497:            /**
1498:             * (Testing Method) Cause an access violation within the Java code.  Useful
1499:             *  for testing the Wrapper functions.  This currently only crashes Sun
1500:             *  JVMs and takes advantage of Bug #4369043 which does not exist in newer
1501:             *  JVMs.  Use of the accessViolationNative() method is preferred.
1502:             */
1503:            public static void accessViolation() {
1504:                SecurityManager sm = System.getSecurityManager();
1505:                if (sm != null) {
1506:                    sm.checkPermission(new WrapperPermission(
1507:                            "test.accessViolation"));
1508:                }
1509:
1510:                m_out
1511:                        .println("WARNING: Attempting to cause an access violation...");
1512:
1513:                try {
1514:                    Class c = Class.forName("java.lang.String");
1515:                    java.lang.reflect.Method m = c
1516:                            .getDeclaredMethod(null, null);
1517:                } catch (NoSuchMethodException ex) {
1518:                    // Correctly did not find method.  access_violation attempt failed.  Not Sun JVM?
1519:                } catch (Exception ex) {
1520:                    if (ex instanceof  NoSuchFieldException) {
1521:                        // Can't catch this in a catch because the compiler doesn't think it is being
1522:                        //  thrown.  But it is thrown on IBM jvms at least
1523:                        // Correctly did not find method.  access_violation attempt failed.  Not Sun JVM?
1524:                    } else {
1525:                        // Shouldn't get here.
1526:                        ex.printStackTrace();
1527:                    }
1528:                }
1529:
1530:                m_out
1531:                        .println("  Attempt to cause access violation failed.  JVM is still alive.");
1532:            }
1533:
1534:            /**
1535:             * (Testing Method) Cause an access violation within native JNI code.  Useful for testing the
1536:             *  Wrapper functions. This currently causes the access violation by attempting to write to 
1537:             *  a null pointer.
1538:             */
1539:            public static void accessViolationNative() {
1540:                SecurityManager sm = System.getSecurityManager();
1541:                if (sm != null) {
1542:                    sm.checkPermission(new WrapperPermission(
1543:                            "test.accessViolationNative"));
1544:                }
1545:
1546:                m_out
1547:                        .println("WARNING: Attempting to cause an access violation...");
1548:                if (m_libraryOK) {
1549:                    accessViolationInner();
1550:
1551:                    m_out
1552:                            .println("  Attempt to cause access violation failed.  "
1553:                                    + "JVM is still alive.");
1554:                } else {
1555:                    m_out.println("  wrapper library not loaded.");
1556:                }
1557:            }
1558:
1559:            /**
1560:             * Returns true if the JVM was launched by the Wrapper application.  False
1561:             *  if the JVM was launched manually without the Wrapper controlling it.
1562:             *
1563:             * @return True if the current JVM was launched by the Wrapper.
1564:             */
1565:            public static boolean isControlledByNativeWrapper() {
1566:                return m_key != null;
1567:            }
1568:
1569:            /**
1570:             * Returns true if the Wrapper was launched as an NT service on Windows or
1571:             *  as a daemon process on UNIX platforms.  False if launched as a console.
1572:             *  This can be useful if you wish to display a user interface when in
1573:             *  Console mode.  On UNIX platforms, this is not as useful because an
1574:             *  X display may not be visible even if launched in a console.
1575:             *
1576:             * @return True if the Wrapper is running as an NT service or daemon
1577:             *         process.
1578:             */
1579:            public static boolean isLaunchedAsService() {
1580:                return m_service;
1581:            }
1582:
1583:            /**
1584:             * Returns true if the wrapper.debug property, or any of the logging
1585:             *  channels are set to DEBUG in the wrapper configuration file.  Useful
1586:             *  for deciding whether or not to output certain information to the
1587:             *  console.
1588:             *
1589:             * @return True if the Wrapper is logging any Debug level output.
1590:             */
1591:            public static boolean isDebugEnabled() {
1592:                return m_debug;
1593:            }
1594:
1595:            /**
1596:             * Start the Java side of the Wrapper code running.  This will make it
1597:             *  possible for the native side of the Wrapper to detect that the Java
1598:             *  Wrapper is up and running.
1599:             * <p>
1600:             * This method must be called on startup and then can only be called once
1601:             *  so there is no reason for any security permission checks on this call.
1602:             *
1603:             * @param listener The WrapperListener instance which represents the
1604:             *                 application being started.
1605:             * @param args The argument list passed to the JVM when it was launched.
1606:             */
1607:            public static synchronized void start(
1608:                    final WrapperListener listener, final String[] args) {
1609:                // As was done in the static initializer, we need to execute the following
1610:                //  code in a privileged action so it is not necessary for the calling code
1611:                //  to have the same privileges as the wrapper jar.
1612:                // This is safe because this method can only be called once and that one call
1613:                //  will presumably be made on JVM startup.
1614:                AccessController.doPrivileged(new PrivilegedAction() {
1615:                    public Object run() {
1616:                        privilegedStart(listener, args);
1617:                        return null;
1618:                    }
1619:                });
1620:            }
1621:
1622:            /**
1623:             * Called by the start method within a PrivilegedAction.
1624:             *
1625:             * @param WrapperListener The WrapperListener instance which represents
1626:             *                        the application being started.
1627:             * @param args The argument list passed to the JVM when it was launched.
1628:             */
1629:            private static void privilegedStart(WrapperListener listener,
1630:                    String[] args) {
1631:                // Check the SecurityManager here as it is possible that it was set before this call.
1632:                checkSecurityManager();
1633:
1634:                // Just in case the user failed to provide an argument list, recover by creating one
1635:                //  here.  This will avoid possible problems down stream.
1636:                if (args == null) {
1637:                    args = new String[0];
1638:                }
1639:
1640:                if (m_debug) {
1641:                    StringBuffer sb = new StringBuffer();
1642:                    sb.append("args[");
1643:                    for (int i = 0; i < args.length; i++) {
1644:                        if (i > 0) {
1645:                            sb.append(", ");
1646:                        }
1647:                        sb.append("\"");
1648:                        sb.append(args[i]);
1649:                        sb.append("\"");
1650:                    }
1651:                    sb.append("]");
1652:
1653:                    m_out.println("WrapperManager.start(" + listener + ", "
1654:                            + sb.toString() + ") " + "called by thread: "
1655:                            + Thread.currentThread().getName());
1656:                }
1657:
1658:                // Make sure that the class has not already been disposed.
1659:                if (m_disposed) {
1660:                    throw new IllegalStateException(
1661:                            "WrapperManager has already been disposed.");
1662:                }
1663:
1664:                if (m_listener != null) {
1665:                    throw new IllegalStateException(
1666:                            "WrapperManager has already been started with a WrapperListener.");
1667:                }
1668:                if (listener == null) {
1669:                    throw new IllegalStateException(
1670:                            "A WrapperListener must be specified.");
1671:                }
1672:                m_listener = listener;
1673:
1674:                m_args = args;
1675:
1676:                startRunner();
1677:
1678:                // If this JVM is being controlled by a native wrapper, then we want to
1679:                //  wait for the command to start.  However, if this is a standalone
1680:                //  JVM, then we want to start now.
1681:                if (!isControlledByNativeWrapper()) {
1682:                    startInner();
1683:                }
1684:            }
1685:
1686:            /**
1687:             * Tells the native wrapper that the JVM wants to restart, then informs
1688:             *	all listeners that the JVM is about to shutdown before killing the JVM.
1689:             * <p>
1690:             * This method will not return.
1691:             *
1692:             * @throws SecurityException If a SecurityManager is present and the
1693:             *                           calling thread does not have the
1694:             *                           WrapperPermission("restart") permission.
1695:             *
1696:             * @see WrapperPermission
1697:             */
1698:            public static void restart() throws SecurityException {
1699:                SecurityManager sm = System.getSecurityManager();
1700:                if (sm != null) {
1701:                    sm.checkPermission(new WrapperPermission("restart"));
1702:                }
1703:
1704:                if (m_debug) {
1705:                    m_out.println("WrapperManager.restart() called by thread: "
1706:                            + Thread.currentThread().getName());
1707:                }
1708:
1709:                restartInner();
1710:            }
1711:
1712:            /**
1713:             * Tells the native wrapper that the JVM wants to restart, then informs
1714:             *	all listeners that the JVM is about to shutdown before killing the JVM.
1715:             * <p>
1716:             * This method requests that the JVM be restarted but then returns.  This
1717:             *  allows components to initiate a JVM exit and then continue, allowing
1718:             *  a normal shutdown initiated by the JVM via shutdown hooks.  In
1719:             *  applications which are designed to be shutdown when the user presses
1720:             *  CTRL-C, this may result in a cleaner shutdown.
1721:             *
1722:             * @throws SecurityException If a SecurityManager is present and the
1723:             *                           calling thread does not have the
1724:             *                           WrapperPermission("restart") permission.
1725:             *
1726:             * @see WrapperPermission
1727:             */
1728:            public static void restartAndReturn() throws SecurityException {
1729:                SecurityManager sm = System.getSecurityManager();
1730:                if (sm != null) {
1731:                    sm.checkPermission(new WrapperPermission("restart"));
1732:                }
1733:
1734:                synchronized (WrapperManager.class) {
1735:                    if (m_stopping) {
1736:                        if (m_debug) {
1737:                            m_out
1738:                                    .println("WrapperManager.restartAndReturn() called by thread: "
1739:                                            + Thread.currentThread().getName()
1740:                                            + " already stopping.");
1741:                        }
1742:                        return;
1743:                    } else {
1744:                        if (m_debug) {
1745:                            m_out
1746:                                    .println("WrapperManager.restartAndReturn() called by thread: "
1747:                                            + Thread.currentThread().getName());
1748:                        }
1749:                    }
1750:                }
1751:
1752:                // To make this possible, we have to create a new thread to actually do the shutdown.
1753:                Thread restarter = new Thread("Wrapper-Restarter") {
1754:                    public void run() {
1755:                        restartInner();
1756:                    }
1757:                };
1758:                restarter.setDaemon(false);
1759:                restarter.start();
1760:            }
1761:
1762:            /**
1763:             * Common code used to restart the JVM.  It is assumed that the calling
1764:             *  thread has has passed security checks before this is called.
1765:             */
1766:            private static void restartInner() {
1767:                boolean stopping;
1768:                synchronized (WrapperManager.class) {
1769:                    stopping = m_stopping;
1770:                    if (!stopping) {
1771:                        m_stopping = true;
1772:                    }
1773:                }
1774:
1775:                if (!stopping) {
1776:                    if (!m_commRunnerStarted) {
1777:                        startRunner();
1778:                    }
1779:
1780:                    // Always send the stop command
1781:                    sendCommand(WRAPPER_MSG_RESTART, "restart");
1782:                }
1783:
1784:                // Give the Wrapper a chance to register the stop command before stopping.
1785:                // This avoids any errors thrown by the Wrapper because the JVM died before
1786:                //  it was expected to.
1787:                try {
1788:                    Thread.sleep(1000);
1789:                } catch (InterruptedException e) {
1790:                }
1791:
1792:                // This is safe because we are already checking for the privilege to restart the JVM
1793:                //  above.  If we get this far then we want the Wrapper to be able to do everything
1794:                //  necessary to stop the JVM.
1795:                AccessController.doPrivileged(new PrivilegedAction() {
1796:                    public Object run() {
1797:                        privilegedStopInner(0);
1798:                        return null;
1799:                    }
1800:                });
1801:            }
1802:
1803:            /**
1804:             * Tells the native wrapper that the JVM wants to shut down, then informs
1805:             *	all listeners that the JVM is about to shutdown before killing the JVM.
1806:             * <p>
1807:             * This method will not return.
1808:             *
1809:             * @param exitCode The exit code that the Wrapper will return when it exits.
1810:             *
1811:             * @throws SecurityException If a SecurityManager is present and the
1812:             *                           calling thread does not have the
1813:             *                           WrapperPermission("stop") permission.
1814:             *
1815:             * @see WrapperPermission
1816:             */
1817:            public static void stop(final int exitCode) {
1818:                SecurityManager sm = System.getSecurityManager();
1819:                if (sm != null) {
1820:                    sm.checkPermission(new WrapperPermission("stop"));
1821:                }
1822:
1823:                if (m_debug) {
1824:                    m_out.println("WrapperManager.stop(" + exitCode
1825:                            + ") called by thread: "
1826:                            + Thread.currentThread().getName());
1827:                }
1828:
1829:                stopCommon(exitCode, 1000);
1830:
1831:                // This is safe because we are already checking for the privilege to stop the JVM
1832:                //  above.  If we get this far then we want the Wrapper to be able to do everything
1833:                //  necessary to stop the JVM.
1834:                AccessController.doPrivileged(new PrivilegedAction() {
1835:                    public Object run() {
1836:                        privilegedStopInner(exitCode);
1837:                        return null;
1838:                    }
1839:                });
1840:            }
1841:
1842:            /**
1843:             * Tells the native wrapper that the JVM wants to shut down, then informs
1844:             *	all listeners that the JVM is about to shutdown before killing the JVM.
1845:             * <p>
1846:             * This method requests that the JVM be shutdown but then returns.  This
1847:             *  allows components to initiate a JVM exit and then continue, allowing
1848:             *  a normal shutdown initiated by the JVM via shutdown hooks.  In
1849:             *  applications which are designed to be shutdown when the user presses
1850:             *  CTRL-C, this may result in a cleaner shutdown.
1851:             *
1852:             * @param exitCode The exit code that the Wrapper will return when it exits.
1853:             *
1854:             * @throws SecurityException If a SecurityManager is present and the
1855:             *                           calling thread does not have the
1856:             *                           WrapperPermission("stop") permission.
1857:             *
1858:             * @see WrapperPermission
1859:             */
1860:            public static void stopAndReturn(final int exitCode) {
1861:                SecurityManager sm = System.getSecurityManager();
1862:                if (sm != null) {
1863:                    sm.checkPermission(new WrapperPermission("stop"));
1864:                }
1865:
1866:                synchronized (WrapperManager.class) {
1867:                    if (m_stopping) {
1868:                        if (m_debug) {
1869:                            m_out.println("WrapperManager.stopAndReturn("
1870:                                    + exitCode + ") called by thread: "
1871:                                    + Thread.currentThread().getName()
1872:                                    + " already stopping.");
1873:                        }
1874:                        return;
1875:                    } else {
1876:                        if (m_debug) {
1877:                            m_out.println("WrapperManager.stopAndReturn("
1878:                                    + exitCode + ") called by thread: "
1879:                                    + Thread.currentThread().getName());
1880:                        }
1881:                    }
1882:                }
1883:
1884:                // To make this possible, we have to create a new thread to actually do the shutdown.
1885:                Thread stopper = new Thread("Wrapper-Stopper") {
1886:                    public void run() {
1887:                        stopCommon(exitCode, 1000);
1888:
1889:                        // This is safe because we are already checking for the privilege to stop the JVM
1890:                        //  above.  If we get this far then we want the Wrapper to be able to do everything
1891:                        //  necessary to stop the JVM.
1892:                        AccessController.doPrivileged(new PrivilegedAction() {
1893:                            public Object run() {
1894:                                privilegedStopInner(exitCode);
1895:                                return null;
1896:                            }
1897:                        });
1898:                    }
1899:                };
1900:                stopper.setDaemon(false);
1901:                stopper.start();
1902:            }
1903:
1904:            /**
1905:             * Tells the native wrapper that the JVM wants to shut down and then
1906:             *  promptly halts.  Be careful when using this method as an application
1907:             *  will not be given a chance to shutdown cleanly.
1908:             *
1909:             * @param exitCode The exit code that the Wrapper will return when it exits.
1910:             *
1911:             * @throws SecurityException If a SecurityManager is present and the
1912:             *                           calling thread does not have the
1913:             *                           WrapperPermission("stopImmediate") permission.
1914:             *
1915:             * @see WrapperPermission
1916:             */
1917:            public static void stopImmediate(final int exitCode) {
1918:                SecurityManager sm = System.getSecurityManager();
1919:                if (sm != null) {
1920:                    sm.checkPermission(new WrapperPermission("stopImmediate"));
1921:                }
1922:
1923:                if (m_debug) {
1924:                    m_out.println("WrapperManager.stopImmediate(" + exitCode
1925:                            + ") called by thread: "
1926:                            + Thread.currentThread().getName());
1927:                }
1928:
1929:                stopCommon(exitCode, 250);
1930:
1931:                signalStopped(exitCode);
1932:
1933:                // Execute runtime.halt(0) using reflection so this class will
1934:                //  compile on 1.2.x versions of Java.
1935:                Method haltMethod;
1936:                try {
1937:                    haltMethod = Runtime.class.getMethod("halt",
1938:                            new Class[] { Integer.TYPE });
1939:                } catch (NoSuchMethodException e) {
1940:                    m_out.println("halt not supported by current JVM.");
1941:                    haltMethod = null;
1942:                }
1943:
1944:                if (haltMethod != null) {
1945:                    Runtime runtime = Runtime.getRuntime();
1946:                    try {
1947:                        haltMethod.invoke(runtime, new Object[] { new Integer(
1948:                                exitCode) });
1949:                    } catch (IllegalAccessException e) {
1950:                        m_out.println("Unable to call runtime.halt: " + e);
1951:                    } catch (InvocationTargetException e) {
1952:                        Throwable t = e.getTargetException();
1953:                        if (t == null) {
1954:                            t = e;
1955:                        }
1956:
1957:                        m_out.println("Unable to call runtime.halt: " + t);
1958:                    }
1959:                } else {
1960:                    // Shutdown normally
1961:
1962:                    // This is safe because we are already checking for the privilege to stop the JVM
1963:                    //  above.  If we get this far then we want the Wrapper to be able to do everything
1964:                    //  necessary to stop the JVM.
1965:                    AccessController.doPrivileged(new PrivilegedAction() {
1966:                        public Object run() {
1967:                            privilegedStopInner(exitCode);
1968:                            return null;
1969:                        }
1970:                    });
1971:                }
1972:            }
1973:
1974:            /**
1975:             * Signal the native wrapper that the startup is progressing but that more
1976:             *  time is needed.  The Wrapper will extend the startup timeout by the
1977:             *  specified time.
1978:             *
1979:             * @param waitHint Additional time in milliseconds.
1980:             *
1981:             * @throws SecurityException If a SecurityManager is present and the
1982:             *                           calling thread does not have the
1983:             *                           WrapperPermission("signalStarting") permission.
1984:             *
1985:             * @see WrapperPermission
1986:             */
1987:            public static void signalStarting(int waitHint) {
1988:                SecurityManager sm = System.getSecurityManager();
1989:                if (sm != null) {
1990:                    sm.checkPermission(new WrapperPermission("signalStarting"));
1991:                }
1992:
1993:                sendCommand(WRAPPER_MSG_START_PENDING, Integer
1994:                        .toString(waitHint));
1995:            }
1996:
1997:            /**
1998:             * Signal the native wrapper that the shutdown is progressing but that more
1999:             *  time is needed.  The Wrapper will extend the stop timeout by the
2000:             *  specified time.
2001:             *
2002:             * @param waitHint Additional time in milliseconds.
2003:             *
2004:             * @throws SecurityException If a SecurityManager is present and the
2005:             *                           calling thread does not have the
2006:             *                           WrapperPermission("signalStopping") permission.
2007:             *
2008:             * @see WrapperPermission
2009:             */
2010:            public static void signalStopping(int waitHint) {
2011:                SecurityManager sm = System.getSecurityManager();
2012:                if (sm != null) {
2013:                    sm.checkPermission(new WrapperPermission("signalStopping"));
2014:                }
2015:
2016:                m_stopping = true;
2017:                sendCommand(WRAPPER_MSG_STOP_PENDING, Integer
2018:                        .toString(waitHint));
2019:            }
2020:
2021:            /**
2022:             * This method should not normally be called by user code as it is called
2023:             *  from within the stop and restart methods.  However certain applications
2024:             *  which stop the JVM may need to call this method to let the wrapper code
2025:             *  know that the shutdown was intentional.
2026:             *
2027:             * @throws SecurityException If a SecurityManager is present and the
2028:             *                           calling thread does not have the
2029:             *                           WrapperPermission("signalStopped") permission.
2030:             *
2031:             * @see WrapperPermission
2032:             */
2033:            public static void signalStopped(int exitCode) {
2034:                SecurityManager sm = System.getSecurityManager();
2035:                if (sm != null) {
2036:                    sm.checkPermission(new WrapperPermission("signalStopped"));
2037:                }
2038:
2039:                m_stopping = true;
2040:                sendCommand(WRAPPER_MSG_STOPPED, Integer.toString(exitCode));
2041:
2042:                // Give the socket time to actuall send the packet to the Wrapper
2043:                //  as this call is often immediately followed by a halt command.
2044:                try {
2045:                    Thread.sleep(250);
2046:                } catch (InterruptedException e) {
2047:                    // Ignore.
2048:                }
2049:            }
2050:
2051:            /**
2052:             * Returns true if the ShutdownHook for the JVM has already been triggered.
2053:             *  Some code needs to know whether or not the system is shutting down.
2054:             *
2055:             * @return True if the ShutdownHook for the JVM has already been triggered.
2056:             */
2057:            public static boolean hasShutdownHookBeenTriggered() {
2058:                return m_hookTriggered;
2059:            }
2060:
2061:            /**
2062:             * Requests that the Wrapper log a message at the specified log level.
2063:             *  If the JVM is not being managed by the Wrapper then calls to this
2064:             *  method will be ignored.  This method has been optimized to ignore
2065:             *  messages at a log level which will not be logged given the current
2066:             *  log levels of the Wrapper.
2067:             * <p>
2068:             * Log messages will currently by trimmed by the Wrapper at 4k (4096 bytes).
2069:             * <p>
2070:             * Because of differences in the way console output is collected and
2071:             *  messages logged via this method, it is expected that interspersed
2072:             *  console and log messages will not be in the correct order in the
2073:             *  resulting log file.
2074:             * <p>
2075:             * This method was added to allow simple logging to the wrapper.log
2076:             *  file.  This is not meant to be a full featured log file and should
2077:             *  not be used as such.  Please look into a logging package for most
2078:             *  application logging.
2079:             *
2080:             * @param logLevel The level to log the message at can be one of
2081:             *                 WRAPPER_LOG_LEVEL_DEBUG, WRAPPER_LOG_LEVEL_INFO,
2082:             *                 WRAPPER_LOG_LEVEL_STATUS, WRAPPER_LOG_LEVEL_WARN,
2083:             *                 WRAPPER_LOG_LEVEL_ERROR, or WRAPPER_LOG_LEVEL_FATAL.
2084:             * @param message The message to be logged.
2085:             *
2086:             * @throws SecurityException If a SecurityManager is present and the
2087:             *                           calling thread does not have the
2088:             *                           WrapperPermission("log") permission.
2089:             *
2090:             * @see WrapperPermission
2091:             */
2092:            public static void log(int logLevel, String message) {
2093:                SecurityManager sm = System.getSecurityManager();
2094:                if (sm != null) {
2095:                    sm.checkPermission(new WrapperPermission("log"));
2096:                }
2097:
2098:                // Make sure that the logLevel is valid to avoid problems with the
2099:                //  command sent to the server.
2100:
2101:                if ((logLevel < WRAPPER_LOG_LEVEL_DEBUG)
2102:                        || (logLevel > WRAPPER_LOG_LEVEL_ADVICE)) {
2103:                    throw new IllegalArgumentException(
2104:                            "The specified logLevel is not valid.");
2105:                }
2106:                if (message == null) {
2107:                    throw new IllegalArgumentException(
2108:                            "The message parameter can not be null.");
2109:                }
2110:
2111:                if (m_lowLogLevel <= logLevel) {
2112:                    sendCommand((byte) (WRAPPER_MSG_LOG + logLevel), message);
2113:                }
2114:            }
2115:
2116:            /**
2117:             * Returns an array of all registered services.  This method is only
2118:             *  supported on Windows platforms which support services.  Calling this
2119:             *  method on other platforms will result in null being returned.
2120:             *
2121:             * @return An array of services.
2122:             *
2123:             * @throws SecurityException If a SecurityManager has not been set in the
2124:             *                           JVM or if the calling code has not been
2125:             *                           granted the WrapperPermission "listServices"
2126:             *                           permission.  A SecurityManager is required
2127:             *                           for this operation because this method makes
2128:             *                           it possible to learn a great deal about the
2129:             *                           state of the system.
2130:             */
2131:            public static WrapperWin32Service[] listServices()
2132:                    throws SecurityException {
2133:                SecurityManager sm = System.getSecurityManager();
2134:                if (sm == null) {
2135:                    throw new SecurityException(
2136:                            "A SecurityManager has not yet been set.");
2137:                } else {
2138:                    sm.checkPermission(new WrapperPermission("listServices"));
2139:                }
2140:
2141:                if (m_libraryOK) {
2142:                    return nativeListServices();
2143:                } else {
2144:                    return null;
2145:                }
2146:            }
2147:
2148:            /**
2149:             * Sends a service control code to the specified service.  The state of the
2150:             *  service should be tested on return.  If the service was not currently
2151:             *  running then the control code will not be sent.
2152:             * <p>
2153:             * The control code sent can be one of the system control codes:
2154:             *  WrapperManager.SERVICE_CONTROL_CODE_START,
2155:             *  WrapperManager.SERVICE_CONTROL_CODE_STOP,
2156:             *  WrapperManager.SERVICE_CONTROL_CODE_PAUSE,
2157:             *  WrapperManager.SERVICE_CONTROL_CODE_CONTINUE, or
2158:             *  WrapperManager.SERVICE_CONTROL_CODE_INTERROGATE.  In addition, user
2159:             *  defined codes in the range 128-255 can also be sent.
2160:             *
2161:             * @param serviceName Name of the Windows service which will receive the
2162:             *                    control code.
2163:             * @param controlCode The actual control code to be sent.  User defined
2164:             *                    control codes should be in the range 128-255.
2165:             *
2166:             * @return A WrapperWin32Service containing the last known status of the
2167:             *         service after sending the control code.  This will be null if
2168:             *         the currently platform is not a version of Windows which
2169:             *         supports services.
2170:             *
2171:             * @throws WrapperServiceException If there are any problems accessing the
2172:             *                                 specified service.
2173:             * @throws SecurityException If a SecurityManager has not been set in the
2174:             *                           JVM or if the calling code has not been
2175:             *                           granted the WrapperServicePermission
2176:             *                           permission for the specified service and
2177:             *                           control code.  A SecurityManager is required
2178:             *                           for this operation because this method makes
2179:             *                           it possible to control any service on the
2180:             *                           system, which is of course rather dangerous.
2181:             */
2182:            public static WrapperWin32Service sendServiceControlCode(
2183:                    String serviceName, int controlCode)
2184:                    throws WrapperServiceException, SecurityException {
2185:                SecurityManager sm = System.getSecurityManager();
2186:                if (sm == null) {
2187:                    throw new SecurityException(
2188:                            "A SecurityManager has not yet been set.");
2189:                } else {
2190:                    String action;
2191:                    switch (controlCode) {
2192:                    case SERVICE_CONTROL_CODE_START:
2193:                        action = WrapperServicePermission.ACTION_START;
2194:                        break;
2195:
2196:                    case SERVICE_CONTROL_CODE_STOP:
2197:                        action = WrapperServicePermission.ACTION_STOP;
2198:                        break;
2199:
2200:                    case SERVICE_CONTROL_CODE_PAUSE:
2201:                        action = WrapperServicePermission.ACTION_PAUSE;
2202:                        break;
2203:
2204:                    case SERVICE_CONTROL_CODE_CONTINUE:
2205:                        action = WrapperServicePermission.ACTION_CONTINUE;
2206:                        break;
2207:
2208:                    case SERVICE_CONTROL_CODE_INTERROGATE:
2209:                        action = WrapperServicePermission.ACTION_INTERROGATE;
2210:                        break;
2211:
2212:                    default:
2213:                        action = WrapperServicePermission.ACTION_USER_CODE;
2214:                        break;
2215:                    }
2216:
2217:                    sm.checkPermission(new WrapperServicePermission(
2218:                            serviceName, action));
2219:                }
2220:
2221:                WrapperWin32Service service = null;
2222:                if (m_libraryOK) {
2223:                    service = nativeSendServiceControlCode(serviceName
2224:                            .getBytes(), controlCode);
2225:                }
2226:                return service;
2227:            }
2228:
2229:            /**
2230:             * Adds a WrapperEventListener which will receive WrapperEvents.  The
2231:             *  specific events can be controlled using the mask parameter.  This API
2232:             *  was chosen to allow for additional events in the future.
2233:             *
2234:             * To avoid future compatibility problems, WrapperEventListeners should
2235:             *  always test the class of an event before making use of it.  This will
2236:             *  avoid problems caused by new event classes added in future versions
2237:             *  of the Wrapper.
2238:             *
2239:             * This method should only be called once for a given WrapperEventListener.
2240:             *  Build up a single mask to receive events of multiple types.
2241:             *
2242:             * @param listener WrapperEventListener to be start receiving events.
2243:             * @param mask A mask specifying the event types that the listener is
2244:             *             interrested in receiving.  See the WrapperEventListener
2245:             *             class for a full list of flags.  A mask is created by
2246:             *             combining multiple flags using the binary '|' OR operator.
2247:             */
2248:            public static void addWrapperEventListener(
2249:                    WrapperEventListener listener, long mask) {
2250:                SecurityManager sm = System.getSecurityManager();
2251:                if (sm != null) {
2252:                    StringBuffer sb = new StringBuffer();
2253:                    boolean first = true;
2254:                    if ((mask & WrapperEventListener.EVENT_FLAG_SERVICE) != 0) {
2255:                        first = false;
2256:                        sb.append(WrapperEventPermission.EVENT_TYPE_SERVICE);
2257:                    }
2258:                    if ((mask & WrapperEventListener.EVENT_FLAG_CONTROL) != 0) {
2259:                        if (first) {
2260:                            first = false;
2261:                        } else {
2262:                            sb.append(",");
2263:                        }
2264:                        sb.append(WrapperEventPermission.EVENT_TYPE_CONTROL);
2265:                    }
2266:                    if ((mask & WrapperEventListener.EVENT_FLAG_CORE) != 0) {
2267:                        if (first) {
2268:                            first = false;
2269:                        } else {
2270:                            sb.append(",");
2271:                        }
2272:                        sb.append(WrapperEventPermission.EVENT_TYPE_CORE);
2273:                    }
2274:                    sm
2275:                            .checkPermission(new WrapperEventPermission(sb
2276:                                    .toString()));
2277:                }
2278:
2279:                synchronized (WrapperManager.class) {
2280:                    WrapperEventListenerMask listenerMask = new WrapperEventListenerMask();
2281:                    listenerMask.m_listener = listener;
2282:                    listenerMask.m_mask = mask;
2283:
2284:                    m_wrapperEventListenerMaskList.add(listenerMask);
2285:                    m_wrapperEventListenerMasks = null;
2286:                }
2287:
2288:                updateWrapperEventListenerFlags();
2289:            }
2290:
2291:            /**
2292:             * Removes a WrapperEventListener so it will not longer receive WrapperEvents.
2293:             *
2294:             * @param listener WrapperEventListener to be stop receiving events.
2295:             */
2296:            public static void removeWrapperEventListener(
2297:                    WrapperEventListener listener) {
2298:                SecurityManager sm = System.getSecurityManager();
2299:                if (sm != null) {
2300:                    sm.checkPermission(new WrapperPermission(
2301:                            "removeWrapperEventListener"));
2302:                }
2303:
2304:                synchronized (WrapperManager.class) {
2305:                    // Look for the first instance of a given listener in the list.
2306:                    for (Iterator iter = m_wrapperEventListenerMaskList
2307:                            .iterator(); iter.hasNext();) {
2308:                        WrapperEventListenerMask listenerMask = (WrapperEventListenerMask) iter
2309:                                .next();
2310:                        if (listenerMask.m_listener == listener) {
2311:                            iter.remove();
2312:                            m_wrapperEventListenerMasks = null;
2313:                            break;
2314:                        }
2315:                    }
2316:                }
2317:
2318:                updateWrapperEventListenerFlags();
2319:            }
2320:
2321:            /*---------------------------------------------------------------
2322:             * Constructors
2323:             *-------------------------------------------------------------*/
2324:            /** 
2325:             * This class can not be instantiated.
2326:             */
2327:            private WrapperManager() {
2328:            }
2329:
2330:            /*---------------------------------------------------------------
2331:             * Private methods
2332:             *-------------------------------------------------------------*/
2333:            /**
2334:             * Checks for the existence of a SecurityManager and then makes sure that
2335:             *  the Wrapper jar has been granted AllPermissions.  If not then a warning
2336:             *  will be displayed as this will most likely result in the Wrapper
2337:             *  failing to function correctly.
2338:             *
2339:             * This method is called at various points in the startup as it is possible
2340:             *  and in fact likely that any SecurityManager will be set by user code
2341:             *  during or shortly after initialization.  Once a SecurityManager has
2342:             *  been located and tested then this method will become a noop.
2343:             */
2344:            private static void checkSecurityManager() {
2345:                if (m_securityManagerChecked) {
2346:                    return;
2347:                }
2348:
2349:                SecurityManager securityManager = System.getSecurityManager();
2350:                if (securityManager != null) {
2351:                    if (m_debug) {
2352:                        m_out.println("Detected a SecurityManager: "
2353:                                + securityManager.getClass().getName());
2354:                    }
2355:
2356:                    try {
2357:                        securityManager
2358:                                .checkPermission(new java.security.AllPermission());
2359:                    } catch (SecurityException e) {
2360:                        m_out.println();
2361:                        m_out
2362:                                .println("WARNING - Detected that a SecurityManager has been installed but the ");
2363:                        m_out
2364:                                .println("          wrapper.jar has not been granted the java.security.AllPermission");
2365:                        m_out
2366:                                .println("          permission.  This will most likely result in SecurityExceptions");
2367:                        m_out.println("          being thrown by the Wrapper.");
2368:                        m_out.println();
2369:                    }
2370:
2371:                    // Always set the flag.
2372:                    m_securityManagerChecked = true;
2373:                }
2374:            }
2375:
2376:            /**
2377:             * Returns an array of WrapperEventListenerMask instances which can
2378:             *  be safely used outside of synchronization.
2379:             *
2380:             * @return An array of WrapperEventListenerMask instances.
2381:             */
2382:            private static WrapperEventListenerMask[] getWrapperEventListenerMasks() {
2383:                WrapperEventListenerMask[] listenerMasks = m_wrapperEventListenerMasks;
2384:                if (listenerMasks == null) {
2385:                    synchronized (WrapperManager.class) {
2386:                        if (listenerMasks == null) {
2387:                            listenerMasks = new WrapperEventListenerMask[m_wrapperEventListenerMaskList
2388:                                    .size()];
2389:                            m_wrapperEventListenerMaskList
2390:                                    .toArray(listenerMasks);
2391:                            m_wrapperEventListenerMasks = listenerMasks;
2392:                        }
2393:                    }
2394:                }
2395:
2396:                return listenerMasks;
2397:            }
2398:
2399:            /**
2400:             * Updates the internal flags based on the WrapperEventListeners currently
2401:             *  registered.
2402:             */
2403:            private static void updateWrapperEventListenerFlags() {
2404:                boolean core = false;
2405:
2406:                WrapperEventListenerMask[] listenerMasks = getWrapperEventListenerMasks();
2407:                for (int i = 0; i < listenerMasks.length; i++) {
2408:                    long mask = listenerMasks[i].m_mask;
2409:
2410:                    // See whether particular event types are required.
2411:                    core = core
2412:                            | ((mask & WrapperEventListener.EVENT_FLAG_CORE) != 0);
2413:                }
2414:
2415:                m_produceCoreEvents = core;
2416:            }
2417:
2418:            /**
2419:             * Notifies registered listeners that an event has been fired.
2420:             *
2421:             * @param event Event to notify the listeners of.
2422:             */
2423:            private static void fireWrapperEvent(WrapperEvent event) {
2424:                long eventMask = event.getFlags();
2425:
2426:                WrapperEventListenerMask[] listenerMasks = getWrapperEventListenerMasks();
2427:                for (int i = 0; i < listenerMasks.length; i++) {
2428:                    long listenerMask = listenerMasks[i].m_mask;
2429:
2430:                    // See if the event should be passed to this listner.
2431:                    if ((listenerMask & eventMask) != 0) {
2432:                        // The listener wants the event.
2433:                        WrapperEventListener listener = listenerMasks[i].m_listener;
2434:                        try {
2435:                            listener.fired(event);
2436:                        } catch (Throwable t) {
2437:                            m_out
2438:                                    .println("Encountered an uncaught exception while notifying "
2439:                                            + "WrapperEventListener of an event:");
2440:                            t.printStackTrace(m_out);
2441:                        }
2442:                    }
2443:                }
2444:            }
2445:
2446:            /**
2447:             * Executed code common to the stop and stopImmediate methods.
2448:             */
2449:            private static void stopCommon(int exitCode, int delay) {
2450:                boolean stopping;
2451:                synchronized (WrapperManager.class) {
2452:                    stopping = m_stopping;
2453:                    if (!stopping) {
2454:                        m_stopping = true;
2455:                    }
2456:                }
2457:
2458:                if (!stopping) {
2459:                    if (!m_commRunnerStarted) {
2460:                        startRunner();
2461:                    }
2462:
2463:                    // Always send the stop command
2464:                    sendCommand(WRAPPER_MSG_STOP, Integer.toString(exitCode));
2465:
2466:                    // Give the Wrapper a chance to register the stop command before stopping.
2467:                    // This avoids any errors thrown by the Wrapper because the JVM died before
2468:                    //  it was expected to.
2469:                    try {
2470:                        Thread.sleep(delay);
2471:                    } catch (InterruptedException e) {
2472:                    }
2473:                }
2474:            }
2475:
2476:            /**
2477:             * Dispose of all resources used by the WrapperManager.  Closes the server
2478:             *	socket which is used to listen for events from the 
2479:             */
2480:            private static void dispose() {
2481:                synchronized (WrapperManager.class) {
2482:                    m_disposed = true;
2483:
2484:                    // Close the open socket if it exists.
2485:                    closeSocket();
2486:
2487:                    // Give the Connection Thread a chance to stop itself.
2488:                    try {
2489:                        Thread.sleep(500);
2490:                    } catch (InterruptedException e) {
2491:                    }
2492:                }
2493:            }
2494:
2495:            /**
2496:             * Informs the listener that it should start.
2497:             */
2498:            private static void startInner() {
2499:                // Set the thread priority back to normal so that any spawned threads
2500:                //	will use the normal priority
2501:                int oldPriority = Thread.currentThread().getPriority();
2502:                Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
2503:
2504:                // This method can be called from the connection thread which must be a
2505:                //  daemon thread by design.  We need to call the WrapperListener.start method
2506:                //  from a non-daemon thread.  This means that if the current thread is a
2507:                //  daemon we need to launch a new thread while we wait for the start method
2508:                //  to return.
2509:                if (m_listener == null) {
2510:                    if (m_debug) {
2511:                        m_out
2512:                                .println("No WrapperListener has been set.  Nothing to start.");
2513:                    }
2514:                } else {
2515:                    if (m_debug) {
2516:                        m_out.println("calling WrapperListener.start()");
2517:                    }
2518:
2519:                    // These arrays aren't pretty, but we need final variables for the inline
2520:                    //  class and this makes it possible to get the values back.
2521:                    final Integer[] resultF = new Integer[1];
2522:                    final Throwable[] tF = new Throwable[1];
2523:
2524:                    if (Thread.currentThread().isDaemon()) {
2525:                        // Start in a dedicated thread.
2526:                        Thread startRunner = new Thread(
2527:                                "WrapperListener_start_runner") {
2528:                            public void run() {
2529:                                if (m_debug) {
2530:                                    m_out
2531:                                            .println("WrapperListener.start runner thread started.");
2532:                                }
2533:
2534:                                try {
2535:                                    // This is user code, so don't trust it.
2536:                                    try {
2537:                                        resultF[0] = m_listener.start(m_args);
2538:                                    } catch (Throwable t) {
2539:                                        tF[0] = t;
2540:                                    }
2541:                                } finally {
2542:                                    if (m_debug) {
2543:                                        m_out
2544:                                                .println("WrapperListener.start runner thread stopped.");
2545:                                    }
2546:                                }
2547:                            }
2548:                        };
2549:                        startRunner.setDaemon(false);
2550:                        startRunner.start();
2551:
2552:                        // Wait for the start runner to complete.
2553:                        if (m_debug) {
2554:                            m_out
2555:                                    .println("Waiting for WrapperListener.start runner thread to complete.");
2556:                        }
2557:                        while ((startRunner != null) && (startRunner.isAlive())) {
2558:                            try {
2559:                                startRunner.join();
2560:                                startRunner = null;
2561:                            } catch (InterruptedException e) {
2562:                                // Ignore and keep waiting.
2563:                            }
2564:                        }
2565:                    } else {
2566:                        // Start in line.
2567:                        // This is user code, so don't trust it.
2568:                        try {
2569:                            resultF[0] = m_listener.start(m_args);
2570:                        } catch (Throwable t) {
2571:                            tF[0] = t;
2572:                        }
2573:                    }
2574:
2575:                    // Now that we are back in the main thread, handle the results.
2576:                    if (tF[0] != null) {
2577:                        m_out
2578:                                .println("Error in WrapperListener.start callback.  "
2579:                                        + tF[0]);
2580:                        tF[0].printStackTrace();
2581:                        // Kill the JVM, but don't tell the wrapper that we want to stop.
2582:                        //  This may be a problem with this instantiation only.
2583:                        privilegedStopInner(1);
2584:                        // Won't make it here.
2585:                        return;
2586:                    }
2587:
2588:                    if (m_debug) {
2589:                        m_out.println("returned from WrapperListener.start()");
2590:                    }
2591:                    if (resultF[0] != null) {
2592:                        int exitCode = resultF[0].intValue();
2593:                        if (m_debug) {
2594:                            m_out
2595:                                    .println("WrapperListener.start() returned an exit code of "
2596:                                            + exitCode + ".");
2597:                        }
2598:
2599:                        // Signal the native code.
2600:                        stop(exitCode);
2601:                        // Won't make it here.
2602:                        return;
2603:                    }
2604:                }
2605:                m_startedTicks = getTicks();
2606:
2607:                // Let the startup thread die since the application has been started.
2608:                m_startupRunner = null;
2609:
2610:                // Check the SecurityManager here as it is possible that it was set in the
2611:                //  listener's start method.
2612:                checkSecurityManager();
2613:
2614:                // Crank the priority back up.
2615:                Thread.currentThread().setPriority(oldPriority);
2616:
2617:                // Signal that the application has started.
2618:                signalStarted();
2619:            }
2620:
2621:            private static void shutdownJVM(int exitCode) {
2622:                if (m_debug) {
2623:                    m_out.println("shutdownJVM(" + exitCode + ") Thread:"
2624:                            + Thread.currentThread().getName());
2625:                }
2626:
2627:                // Do not call System.exit if this is the ShutdownHook
2628:                if (Thread.currentThread() == m_hook) {
2629:                    // Signal that the application has stopped and the JVM is about to shutdown.
2630:                    signalStopped(exitCode);
2631:
2632:                    // Dispose the wrapper.  (If the hook runs, it will do this.)
2633:                    dispose();
2634:
2635:                    // This is the shutdown hook, so fall through because things are
2636:                    //  already shutting down.
2637:
2638:                    m_shutdownJVMComplete = true;
2639:                } else {
2640:                    // We do not want the ShutdownHook to execute, so unregister it before calling exit.
2641:                    //  It can't be unregistered if it has already fired however.  The only way that this
2642:                    //  could happen is if user code calls System.exit from within the listener stop
2643:                    //  method.
2644:                    if ((!m_hookTriggered) && (m_hook != null)) {
2645:                        // Remove the shutdown hook using reflection.
2646:                        try {
2647:                            m_removeShutdownHookMethod.invoke(Runtime
2648:                                    .getRuntime(), new Object[] { m_hook });
2649:                        } catch (IllegalAccessException e) {
2650:                            m_out
2651:                                    .println("Wrapper Manager: Unable to unregister shutdown hook: "
2652:                                            + e);
2653:                        } catch (InvocationTargetException e) {
2654:                            Throwable t = e.getTargetException();
2655:                            if (t == null) {
2656:                                t = e;
2657:                            }
2658:
2659:                            m_out
2660:                                    .println("Wrapper Manager: Unable to unregister shutdown hook: "
2661:                                            + t);
2662:                        }
2663:                    }
2664:                    // Signal that the application has stopped and the JVM is about to shutdown.
2665:                    signalStopped(exitCode);
2666:
2667:                    // Dispose the wrapper.  (If the hook runs, it will do this.)
2668:                    dispose();
2669:
2670:                    if (m_debug) {
2671:                        m_out.println("calling System.exit(" + exitCode + ")");
2672:                    }
2673:                    m_shutdownJVMComplete = true;
2674:                    safeSystemExit(exitCode);
2675:                }
2676:            }
2677:
2678:            /**
2679:             * A user ran into a JVM bug where a call to System exit was causing an
2680:             *  IllegalThreadStateException to be thrown.  Not sure how widespread
2681:             *  this problem is.  But it is easy to avoid it causing serious problems
2682:             *  for the wrapper.
2683:             */
2684:            private static void safeSystemExit(int exitCode) {
2685:                try {
2686:                    System.exit(exitCode);
2687:                } catch (IllegalThreadStateException e) {
2688:                    m_out.println("Wrapper Manager: Attempted System.exit("
2689:                            + exitCode + ") call failed: " + e.toString());
2690:                    m_out.println("                 Trying Runtime.halt("
2691:                            + exitCode + ")");
2692:                    Runtime.getRuntime().halt(exitCode);
2693:                }
2694:            }
2695:
2696:            /**
2697:             * Informs the listener that the JVM will be shut down.
2698:             *
2699:             * This should only be called from within a PrivilegedAction or in a
2700:             *  context that came from a PrivilegedAction.
2701:             */
2702:            private static void privilegedStopInner(int exitCode) {
2703:                boolean block;
2704:                synchronized (WrapperManager.class) {
2705:                    // Always set the stopping flag.
2706:                    m_stopping = true;
2707:
2708:                    // Only one thread can be allowed to continue.
2709:                    if (m_stoppingThread == null) {
2710:                        m_stoppingThread = Thread.currentThread();
2711:                        block = false;
2712:                    } else {
2713:                        if (Thread.currentThread() == m_stoppingThread) {
2714:                            throw new IllegalStateException(
2715:                                    "WrapperManager.stop() can not be called recursively.");
2716:                        }
2717:
2718:                        block = true;
2719:                    }
2720:                }
2721:
2722:                if (block) {
2723:                    if (m_debug) {
2724:                        m_out.println("Thread, "
2725:                                + Thread.currentThread().getName()
2726:                                + ", waiting for the JVM to exit.");
2727:
2728:                        if (Thread.currentThread() == m_hook) {
2729:                            m_out
2730:                                    .println("System.exit appears to have been called from within the");
2731:                            m_out
2732:                                    .println("  WrapperListener.stop() method.  If possible the application");
2733:                            m_out
2734:                                    .println("  should be modified to avoid this behavior.");
2735:                            m_out
2736:                                    .println("  To avoid a deadlock, this thread will only wait 5 seconds");
2737:                            m_out
2738:                                    .println("  for the application to shutdown.  This may result in the");
2739:                            m_out
2740:                                    .println("  application failing to shutdown completely before the JVM");
2741:                            m_out
2742:                                    .println("  exists.  Removing the offending System.exit call will");
2743:                            m_out.println("  resolve this.");
2744:                        }
2745:                    }
2746:
2747:                    // This thread needs to be put into an infinite loop until the JVM exits.
2748:                    //  This thread can not be allowed to return to the caller, but another
2749:                    //  thread is already responsible for shutting down the JVM, so this
2750:                    //  one can do nothing but wait.
2751:                    int loops = 0;
2752:                    int wait = 50;
2753:                    while (true) {
2754:                        try {
2755:                            Thread.sleep(wait);
2756:                        } catch (InterruptedException e) {
2757:                        }
2758:
2759:                        // If this is the wrapper's shutdown hook then we only want to loop until
2760:                        //  the shutdownJVM method has completed.  We will only get into this state
2761:                        //  if user code calls System.exit from within the WrapperListener.stop
2762:                        //  method.  Failing to return here will cause the shutdown process to hang.
2763:                        // If the user code calls System.exit directly in the stop method then the
2764:                        //  m_shutdownJVMComplete flag will never be set.   Always time out after
2765:                        //  5 seconds so the JVM will not hang in such cases.
2766:                        if (Thread.currentThread() == m_hook) {
2767:                            if (m_shutdownJVMComplete || (loops > 5000 / wait)) {
2768:                                if (!m_shutdownJVMComplete) {
2769:                                    if (m_debug) {
2770:                                        m_out
2771:                                                .println("Thread, "
2772:                                                        + Thread
2773:                                                                .currentThread()
2774:                                                                .getName()
2775:                                                        + ", continuing after 5 seconds.");
2776:                                    }
2777:                                }
2778:
2779:                                // To keep the wrapper from showing a JVM exited unexpectedly message
2780:                                //  on shutdown, tell the wrapper that we are ready to stop.
2781:                                // If the WrapperListener.stop method is taking a long time, we will
2782:                                //  also get here.  In that case, the Wrapper will still wait for
2783:                                //  the configured exit timeout before killing the JVM process.
2784:                                // In theory, the shutdown process of an application will only call
2785:                                //  System.exit after the shutdown is complete so this should be Ok.
2786:                                // Use the exit code from the thread which initiated the call rather
2787:                                //  than this call as that one is the one we really want.
2788:                                signalStopped(m_exitCode);
2789:
2790:                                return;
2791:                            }
2792:                        }
2793:
2794:                        loops++;
2795:                    }
2796:                }
2797:
2798:                if (m_debug) {
2799:                    m_out.println("Thread, " + Thread.currentThread().getName()
2800:                            + ", handling the shutdown process.");
2801:                }
2802:                m_exitCode = exitCode;
2803:
2804:                // Only stop the listener if the app has been started.
2805:                int code = exitCode;
2806:                if (m_started) {
2807:                    // Set the thread priority back to normal so that any spawned threads
2808:                    //	will use the normal priority
2809:                    int oldPriority = Thread.currentThread().getPriority();
2810:                    Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
2811:
2812:                    // This method can be called from the connection thread which must be a
2813:                    //  daemon thread by design.  We need to call the WrapperListener.stop method
2814:                    //  from a non-daemon thread.  This means that if the current thread is a
2815:                    //  daemon we need to launch a new thread while we wait for the stop method
2816:                    //  to return.
2817:                    if (m_listener == null) {
2818:                        if (m_debug) {
2819:                            m_out
2820:                                    .println("No WrapperListener has been set.  Nothing to stop.");
2821:                        }
2822:                    } else {
2823:                        if (m_debug) {
2824:                            m_out.println("calling listener.stop()");
2825:                        }
2826:
2827:                        if (Thread.currentThread().isDaemon()) {
2828:                            // This array isn't pretty, but we need final variables for the inline
2829:                            //  class and this makes it possible to get the values back.
2830:                            final Integer[] codeF = new Integer[] { new Integer(
2831:                                    code) };
2832:
2833:                            // Start in a dedicated thread.
2834:                            Thread stopRunner = new Thread(
2835:                                    "WrapperListener_stop_runner") {
2836:                                public void run() {
2837:                                    if (m_debug) {
2838:                                        m_out
2839:                                                .println("WrapperListener.stop runner thread started.");
2840:                                    }
2841:
2842:                                    try {
2843:                                        // This is user code, so don't trust it.
2844:                                        try {
2845:                                            codeF[0] = new Integer(m_listener
2846:                                                    .stop(codeF[0].intValue()));
2847:                                        } catch (Throwable t) {
2848:                                            m_out
2849:                                                    .println("Error in WrapperListener.stop callback.  "
2850:                                                            + t);
2851:                                            t.printStackTrace();
2852:                                        }
2853:                                    } finally {
2854:                                        if (m_debug) {
2855:                                            m_out
2856:                                                    .println("WrapperListener.stop runner thread stopped.");
2857:                                        }
2858:                                    }
2859:                                }
2860:                            };
2861:                            stopRunner.setDaemon(false);
2862:                            stopRunner.start();
2863:
2864:                            // Wait for the start runner to complete.
2865:                            if (m_debug) {
2866:                                m_out
2867:                                        .println("Waiting for WrapperListener.stop runner thread to complete.");
2868:                            }
2869:                            while ((stopRunner != null)
2870:                                    && (stopRunner.isAlive())) {
2871:                                try {
2872:                                    stopRunner.join();
2873:                                    stopRunner = null;
2874:                                } catch (InterruptedException e) {
2875:                                    // Ignore and keep waiting.
2876:                                }
2877:                            }
2878:
2879:                            // Get the exit code back from the array.
2880:                            code = codeF[0].intValue();
2881:                        } else {
2882:                            // This is user code, so don't trust it.
2883:                            try {
2884:                                code = m_listener.stop(code);
2885:                            } catch (Throwable t) {
2886:                                m_out
2887:                                        .println("Error in WrapperListener.stop callback.  "
2888:                                                + t);
2889:                                t.printStackTrace();
2890:                            }
2891:                        }
2892:                        if (m_debug) {
2893:                            m_out.println("returned from listener.stop() -> "
2894:                                    + code);
2895:                        }
2896:                    }
2897:
2898:                    // Crank the priority back up.
2899:                    Thread.currentThread().setPriority(oldPriority);
2900:                }
2901:
2902:                shutdownJVM(code);
2903:            }
2904:
2905:            private static void signalStarted() {
2906:                sendCommand(WRAPPER_MSG_STARTED, "");
2907:                m_started = true;
2908:            }
2909:
2910:            /**
2911:             * Called by the native code when a control event is trapped by native code.
2912:             * Can have the values: WRAPPER_CTRL_C_EVENT, WRAPPER_CTRL_CLOSE_EVENT, 
2913:             *    WRAPPER_CTRL_LOGOFF_EVENT, WRAPPER_CTRL_SHUTDOWN_EVENT,
2914:             *    WRAPPER_CTRL_TERM_EVENT, or WRAPPER_CTRL_HUP_EVENT.
2915:             */
2916:            private static void controlEvent(int event) {
2917:                String eventName;
2918:                boolean ignore;
2919:                switch (event) {
2920:                case WRAPPER_CTRL_C_EVENT:
2921:                    eventName = "WRAPPER_CTRL_C_EVENT";
2922:                    ignore = m_ignoreSignals;
2923:                    break;
2924:                case WRAPPER_CTRL_CLOSE_EVENT:
2925:                    eventName = "WRAPPER_CTRL_CLOSE_EVENT";
2926:                    ignore = m_ignoreSignals;
2927:                    break;
2928:                case WRAPPER_CTRL_LOGOFF_EVENT:
2929:                    eventName = "WRAPPER_CTRL_LOGOFF_EVENT";
2930:                    ignore = false;
2931:                    break;
2932:                case WRAPPER_CTRL_SHUTDOWN_EVENT:
2933:                    eventName = "WRAPPER_CTRL_SHUTDOWN_EVENT";
2934:                    ignore = false;
2935:                    break;
2936:                case WRAPPER_CTRL_TERM_EVENT:
2937:                    eventName = "WRAPPER_CTRL_TERM_EVENT";
2938:                    ignore = m_ignoreSignals;
2939:                    break;
2940:                case WRAPPER_CTRL_HUP_EVENT:
2941:                    eventName = "WRAPPER_CTRL_HUP_EVENT";
2942:                    ignore = m_ignoreSignals;
2943:                    break;
2944:                default:
2945:                    eventName = "Unexpected event: " + event;
2946:                    ignore = false;
2947:                    break;
2948:                }
2949:
2950:                WrapperControlEvent controlEvent = new WrapperControlEvent(
2951:                        event, eventName);
2952:                if (ignore) {
2953:                    // Preconsume the event if it is set to be ignored, but go ahead and fire it so
2954:                    //  user can can still have the oportunity to recognize it.
2955:                    controlEvent.consume();
2956:                }
2957:                fireWrapperEvent(controlEvent);
2958:
2959:                if (!controlEvent.isConsumed()) {
2960:                    if (ignore) {
2961:                        if (m_debug) {
2962:                            m_out.println("Ignoring control event(" + eventName
2963:                                    + ")");
2964:                        }
2965:                    } else {
2966:                        if (m_debug) {
2967:                            m_out.println("Processing control event("
2968:                                    + eventName + ")");
2969:                        }
2970:
2971:                        // This is user code, so don't trust it.
2972:                        if (m_listener != null) {
2973:                            try {
2974:                                m_listener.controlEvent(event);
2975:                            } catch (Throwable t) {
2976:                                m_out
2977:                                        .println("Error in WrapperListener.controlEvent callback.  "
2978:                                                + t);
2979:                                t.printStackTrace();
2980:                            }
2981:                        } else {
2982:                            // A listener was never registered.  Always respond by exiting.
2983:                            //  This can happen if the user does not initialize things correctly.
2984:                            stop(0);
2985:                        }
2986:                    }
2987:                }
2988:            }
2989:
2990:            /**
2991:             * Parses a long tab separated string of properties into an internal
2992:             *  properties object.  Actual tabs are escaped by real tabs.
2993:             */
2994:            private static char PROPERTY_SEPARATOR = '\t';
2995:
2996:            private static void readProperties(String rawProps) {
2997:                WrapperProperties properties = new WrapperProperties();
2998:
2999:                int len = rawProps.length();
3000:                int first = 0;
3001:                while (first < len) {
3002:                    StringBuffer sb = new StringBuffer();
3003:                    boolean foundEnd = false;
3004:                    do {
3005:                        int pos = rawProps.indexOf(PROPERTY_SEPARATOR, first);
3006:                        if (pos >= 0) {
3007:                            if (pos > 0) {
3008:                                sb.append(rawProps.substring(first, pos));
3009:                            }
3010:                            if (pos < len - 1) {
3011:                                if (rawProps.charAt(pos + 1) == PROPERTY_SEPARATOR) {
3012:                                    // Two separators in a row, it was escaped.
3013:                                    sb.append(PROPERTY_SEPARATOR);
3014:                                    first = pos + 2;
3015:                                } else {
3016:                                    foundEnd = true;
3017:                                    first = pos + 1;
3018:                                }
3019:                            } else {
3020:                                foundEnd = true;
3021:                                first = pos + 1;
3022:                            }
3023:                        } else {
3024:                            // No more separators.  The rest is the last property.
3025:                            sb.append(rawProps.substring(first));
3026:                            foundEnd = true;
3027:                            first = len;
3028:                        }
3029:                    } while (!foundEnd);
3030:
3031:                    String property = sb.toString();
3032:
3033:                    // Parse the property.
3034:                    int pos = property.indexOf('=');
3035:                    if (pos > 0) {
3036:                        String key = property.substring(0, pos);
3037:                        String value;
3038:                        if (pos < property.length() - 1) {
3039:                            value = property.substring(pos + 1);
3040:                        } else {
3041:                            value = "";
3042:                        }
3043:
3044:                        properties.setProperty(key, value);
3045:                    }
3046:                }
3047:
3048:                // Lock the properties object and store it.
3049:                properties.lock();
3050:
3051:                m_properties = properties;
3052:            }
3053:
3054:            private static synchronized Socket openSocket() {
3055:                if (m_debug) {
3056:                    m_out.println("Open socket to wrapper..."
3057:                            + Thread.currentThread().getName());
3058:                }
3059:
3060:                InetAddress iNetAddress;
3061:                try {
3062:                    iNetAddress = InetAddress.getByName("127.0.0.1");
3063:                } catch (UnknownHostException e) {
3064:                    // This is pretty fatal.
3065:                    m_out.println(e);
3066:                    stop(1);
3067:                    return null; //please the compiler
3068:                }
3069:
3070:                // If the user has specified a specific port to use then we want to try that first.
3071:                boolean connected = false;
3072:                int tryPort;
3073:                boolean fixedPort;
3074:                if (m_jvmPort > 0) {
3075:                    tryPort = m_jvmPort;
3076:                    fixedPort = true;
3077:                } else {
3078:                    tryPort = m_jvmPortMin;
3079:                    fixedPort = false;
3080:                }
3081:
3082:                // Loop until we find a port we can connect using.
3083:                do {
3084:                    try {
3085:                        m_socket = new Socket(iNetAddress, m_port, iNetAddress,
3086:                                tryPort);
3087:                        if (m_debug) {
3088:                            m_out.println("Opened Socket from " + tryPort
3089:                                    + " to " + m_port);
3090:                        }
3091:                        connected = true;
3092:                        break;
3093:                    } catch (SocketException e) {
3094:                        String eMessage = e.getMessage();
3095:
3096:                        if (e instanceof  ConnectException) {
3097:                            m_out
3098:                                    .println("Failed to connect to the Wrapper at port "
3099:                                            + m_port + ".");
3100:                            m_out.println(e);
3101:                            // This is fatal because there is nobody listening.
3102:                            m_out.println("Exiting JVM...");
3103:                            stopImmediate(1);
3104:                        } else if ((e instanceof  BindException)
3105:                                || ((eMessage != null) && (eMessage
3106:                                        .indexOf("errno: 48") >= 0))) {
3107:                            // Most Java implementations throw a BindException when the port is in use,
3108:                            //  but FreeBSD throws a SocketException with a specific message.
3109:
3110:                            // This happens if the local port is already in use.  In this case, we want
3111:                            //  to loop and try again.
3112:                            if (m_debug) {
3113:                                m_out
3114:                                        .println("Failed attempt to bind using local port "
3115:                                                + tryPort);
3116:                            }
3117:
3118:                            if (fixedPort) {
3119:                                // The last port checked was the fixed port, switch to the dynamic range.
3120:                                tryPort = m_jvmPortMin;
3121:                                fixedPort = false;
3122:                            } else {
3123:                                tryPort++;
3124:                            }
3125:                        } else {
3126:                            // Unexpected exception.
3127:                            m_out.println(e);
3128:                            m_socket = null;
3129:                            return null;
3130:                        }
3131:                    } catch (IOException e) {
3132:                        m_out.println(e);
3133:                        m_socket = null;
3134:                        return null;
3135:                    }
3136:                } while (tryPort <= m_jvmPortMax);
3137:
3138:                if (connected) {
3139:                    if ((m_jvmPort > 0) && (m_jvmPort != tryPort)) {
3140:                        m_out.println("Port " + m_jvmPort
3141:                                + " already in use, using port " + tryPort
3142:                                + " instead.");
3143:                    }
3144:                } else {
3145:                    if (m_jvmPortMax > m_jvmPortMin) {
3146:                        m_out
3147:                                .println("Failed to connect to the Wrapper at port "
3148:                                        + m_port
3149:                                        + " by binding to any "
3150:                                        + "ports in the range "
3151:                                        + m_jvmPortMin
3152:                                        + " to " + m_jvmPortMax + ".");
3153:                    } else {
3154:                        m_out
3155:                                .println("Failed to connect to the Wrapper at port "
3156:                                        + m_port
3157:                                        + " by binding to port "
3158:                                        + m_jvmPortMin + ".");
3159:                    }
3160:                    // This is fatal because there is nobody listening.
3161:                    m_out.println("Exiting JVM...");
3162:                    stopImmediate(1);
3163:                }
3164:
3165:                // Now that we have a connected socket, continue on to configure it.
3166:                try {
3167:                    // Turn on the TCP_NODELAY flag.  This is very important for speed!!
3168:                    m_socket.setTcpNoDelay(true);
3169:
3170:                    // Set the SO_TIMEOUT for the socket (max block time)
3171:                    if (m_soTimeout > 0) {
3172:                        m_socket.setSoTimeout(m_soTimeout);
3173:                    }
3174:                } catch (IOException e) {
3175:                    m_out.println(e);
3176:                }
3177:
3178:                // Send the key back to the wrapper so that the wrapper can feel safe
3179:                //  that it is talking to the correct JVM
3180:                sendCommand(WRAPPER_MSG_KEY, m_key);
3181:
3182:                return m_socket;
3183:            }
3184:
3185:            private static synchronized void closeSocket() {
3186:                if (m_socket != null) {
3187:                    if (m_debug) {
3188:                        m_out.println("Closing socket.");
3189:                    }
3190:
3191:                    try {
3192:                        m_socket.close();
3193:                    } catch (IOException e) {
3194:                    } finally {
3195:                        m_socket = null;
3196:                    }
3197:                }
3198:            }
3199:
3200:            private static String getPacketCodeName(byte code) {
3201:                String name;
3202:
3203:                switch (code) {
3204:                case WRAPPER_MSG_START:
3205:                    name = "START";
3206:                    break;
3207:
3208:                case WRAPPER_MSG_STOP:
3209:                    name = "STOP";
3210:                    break;
3211:
3212:                case WRAPPER_MSG_RESTART:
3213:                    name = "RESTART";
3214:                    break;
3215:
3216:                case WRAPPER_MSG_PING:
3217:                    name = "PING";
3218:                    break;
3219:
3220:                case WRAPPER_MSG_STOP_PENDING:
3221:                    name = "STOP_PENDING";
3222:                    break;
3223:
3224:                case WRAPPER_MSG_START_PENDING:
3225:                    name = "START_PENDING";
3226:                    break;
3227:
3228:                case WRAPPER_MSG_STARTED:
3229:                    name = "STARTED";
3230:                    break;
3231:
3232:                case WRAPPER_MSG_STOPPED:
3233:                    name = "STOPPED";
3234:                    break;
3235:
3236:                case WRAPPER_MSG_KEY:
3237:                    name = "KEY";
3238:                    break;
3239:
3240:                case WRAPPER_MSG_BADKEY:
3241:                    name = "BADKEY";
3242:                    break;
3243:
3244:                case WRAPPER_MSG_LOW_LOG_LEVEL:
3245:                    name = "LOW_LOG_LEVEL";
3246:                    break;
3247:
3248:                case WRAPPER_MSG_PING_TIMEOUT:
3249:                    name = "PING_TIMEOUT";
3250:                    break;
3251:
3252:                case WRAPPER_MSG_SERVICE_CONTROL_CODE:
3253:                    name = "SERVICE_CONTROL_CODE";
3254:                    break;
3255:
3256:                case WRAPPER_MSG_PROPERTIES:
3257:                    name = "PROPERTIES";
3258:                    break;
3259:
3260:                case WRAPPER_MSG_LOG + WRAPPER_LOG_LEVEL_DEBUG:
3261:                    name = "LOG(DEBUG)";
3262:                    break;
3263:
3264:                case WRAPPER_MSG_LOG + WRAPPER_LOG_LEVEL_INFO:
3265:                    name = "LOG(INFO)";
3266:                    break;
3267:
3268:                case WRAPPER_MSG_LOG + WRAPPER_LOG_LEVEL_STATUS:
3269:                    name = "LOG(STATUS)";
3270:                    break;
3271:
3272:                case WRAPPER_MSG_LOG + WRAPPER_LOG_LEVEL_WARN:
3273:                    name = "LOG(WARN)";
3274:                    break;
3275:
3276:                case WRAPPER_MSG_LOG + WRAPPER_LOG_LEVEL_ERROR:
3277:                    name = "LOG(ERROR)";
3278:                    break;
3279:
3280:                case WRAPPER_MSG_LOG + WRAPPER_LOG_LEVEL_FATAL:
3281:                    name = "LOG(FATAL)";
3282:                    break;
3283:
3284:                case WRAPPER_MSG_LOG + WRAPPER_LOG_LEVEL_ADVICE:
3285:                    name = "LOG(ADVICE)";
3286:                    break;
3287:
3288:                default:
3289:                    name = "UNKNOWN(" + code + ")";
3290:                    break;
3291:                }
3292:                return name;
3293:            }
3294:
3295:            private static synchronized void sendCommand(byte code,
3296:                    String message) {
3297:                if (m_debug) {
3298:                    m_out.println("Send a packet " + getPacketCodeName(code)
3299:                            + " : " + message);
3300:                }
3301:                if (m_appearHung) {
3302:                    // The WrapperManager is attempting to make the JVM appear hung, so do nothing
3303:                } else {
3304:                    // Make a copy of the reference to make this more thread safe.
3305:                    Socket socket = m_socket;
3306:                    if (socket == null && isControlledByNativeWrapper()
3307:                            && (!m_stopping)) {
3308:                        // The socket is not currently open, try opening it.
3309:                        socket = openSocket();
3310:                    }
3311:
3312:                    if ((code == WRAPPER_MSG_START_PENDING)
3313:                            || (code == WRAPPER_MSG_STARTED)) {
3314:                        // Set the last ping time so that the startup process does not time out
3315:                        //  thinking that the JVM has not received a Ping for too long.
3316:                        m_lastPingTicks = getTicks();
3317:                    }
3318:
3319:                    // If the socket is open, then send the command, otherwise just throw it away.
3320:                    if (socket != null) {
3321:                        try {
3322:                            // It is possible that a logged message is quite large.  Expand the size
3323:                            // of the command buffer if necessary so that it can be included.  This
3324:                            //  means that the command buffer will be the size of the largest message.
3325:                            byte[] messageBytes = message.getBytes();
3326:                            if (m_commandBuffer.length < messageBytes.length + 2) {
3327:                                m_commandBuffer = new byte[messageBytes.length + 2];
3328:                            }
3329:
3330:                            // Writing the bytes one by one was sometimes causing the first byte to be lost.
3331:                            // Try to work around this problem by creating a buffer and sending the whole lot
3332:                            // at once.
3333:                            m_commandBuffer[0] = code;
3334:                            System.arraycopy(messageBytes, 0, m_commandBuffer,
3335:                                    1, messageBytes.length);
3336:                            int len = messageBytes.length + 2;
3337:                            m_commandBuffer[len - 1] = 0;
3338:
3339:                            OutputStream os = socket.getOutputStream();
3340:                            os.write(m_commandBuffer, 0, len);
3341:                            os.flush();
3342:                        } catch (IOException e) {
3343:                            m_out.println(e);
3344:                            e.printStackTrace();
3345:                            closeSocket();
3346:                        }
3347:                    }
3348:                }
3349:            }
3350:
3351:            /**
3352:             * Loop reading packets from the native side of the Wrapper until the 
3353:             *  connection is closed or the WrapperManager class is disposed.
3354:             *  Each packet consists of a packet code followed by a null terminated
3355:             *  string up to 256 characters in length.  If the entire packet has not
3356:             *  yet been received, then it must not be read until the complete packet
3357:             *  has arived.
3358:             */
3359:            private static byte[] m_socketReadBuffer = new byte[256];
3360:
3361:            private static void handleSocket() {
3362:                WrapperPingEvent pingEvent = new WrapperPingEvent();
3363:                try {
3364:                    if (m_debug) {
3365:                        m_out.println("handleSocket(" + m_socket + ")");
3366:                    }
3367:                    DataInputStream is = new DataInputStream(m_socket
3368:                            .getInputStream());
3369:                    while (!m_disposed) {
3370:                        try {
3371:                            // A Packet code must exist.
3372:                            byte code = is.readByte();
3373:
3374:                            // Always read from the buffer until a null '\0' is encountered.
3375:                            byte b;
3376:                            int i = 0;
3377:                            do {
3378:                                b = is.readByte();
3379:                                if (b != 0) {
3380:                                    if (i >= m_socketReadBuffer.length) {
3381:                                        byte[] tmp = m_socketReadBuffer;
3382:                                        m_socketReadBuffer = new byte[tmp.length + 256];
3383:                                        System.arraycopy(tmp, 0,
3384:                                                m_socketReadBuffer, 0,
3385:                                                tmp.length);
3386:                                    }
3387:                                    m_socketReadBuffer[i] = b;
3388:                                    i++;
3389:                                }
3390:                            } while (b != 0);
3391:
3392:                            String msg = new String(m_socketReadBuffer, 0, i);
3393:
3394:                            if (m_appearHung) {
3395:                                // The WrapperManager is attempting to make the JVM appear hung,
3396:                                //   so ignore all incoming requests
3397:                            } else {
3398:                                if (m_debug) {
3399:                                    String logMsg;
3400:                                    if (code == WRAPPER_MSG_PROPERTIES) {
3401:                                        // The property values are very large and distracting in the log.
3402:                                        //  Plus if any triggers are defined, then logging them will fire
3403:                                        //  the trigger.
3404:                                        logMsg = "(Property Values)";
3405:                                    } else {
3406:                                        logMsg = msg;
3407:                                    }
3408:                                    m_out.println("Received a packet "
3409:                                            + getPacketCodeName(code) + " : "
3410:                                            + logMsg);
3411:                                }
3412:
3413:                                // Ok, we got a packet.  Do something with it.
3414:                                switch (code) {
3415:                                case WRAPPER_MSG_START:
3416:                                    startInner();
3417:                                    break;
3418:
3419:                                case WRAPPER_MSG_STOP:
3420:                                    // Don't do anything if we are already stopping
3421:                                    if (!m_stopping) {
3422:                                        privilegedStopInner(0);
3423:                                        // Should never get back here.
3424:                                    }
3425:                                    break;
3426:
3427:                                case WRAPPER_MSG_PING:
3428:                                    m_lastPingTicks = getTicks();
3429:                                    sendCommand(WRAPPER_MSG_PING, "ok");
3430:
3431:                                    if (m_produceCoreEvents) {
3432:                                        fireWrapperEvent(pingEvent);
3433:                                    }
3434:
3435:                                    break;
3436:
3437:                                case WRAPPER_MSG_BADKEY:
3438:                                    // The key sent to the wrapper was incorrect.  We need to shutdown.
3439:                                    m_out
3440:                                            .println("Authorization key rejected by Wrapper.  Exiting JVM.");
3441:                                    closeSocket();
3442:                                    privilegedStopInner(1);
3443:                                    break;
3444:
3445:                                case WRAPPER_MSG_LOW_LOG_LEVEL:
3446:                                    try {
3447:                                        m_lowLogLevel = Integer.parseInt(msg);
3448:                                        m_debug = (m_lowLogLevel <= WRAPPER_LOG_LEVEL_DEBUG);
3449:                                        if (m_debug) {
3450:                                            m_out
3451:                                                    .println("Wrapper Manager: LowLogLevel from Wrapper "
3452:                                                            + "is "
3453:                                                            + m_lowLogLevel);
3454:                                        }
3455:                                    } catch (NumberFormatException e) {
3456:                                        m_out
3457:                                                .println("Encountered an Illegal LowLogLevel from the "
3458:                                                        + "Wrapper: " + msg);
3459:                                    }
3460:                                    break;
3461:
3462:                                case WRAPPER_MSG_PING_TIMEOUT:
3463:                                    try {
3464:                                        m_pingTimeout = Integer.parseInt(msg) * 1000;
3465:                                        if (m_debug) {
3466:                                            m_out
3467:                                                    .println("PingTimeout from Wrapper is "
3468:                                                            + m_pingTimeout);
3469:                                        }
3470:                                    } catch (NumberFormatException e) {
3471:                                        m_out
3472:                                                .println("Encountered an Illegal PingTimeout from the "
3473:                                                        + "Wrapper: " + msg);
3474:                                    }
3475:
3476:                                    // Make sure that the so timeout is longer than the ping timeout
3477:                                    if (m_pingTimeout <= 0) {
3478:                                        m_socket.setSoTimeout(0);
3479:                                    } else if (m_soTimeout < m_pingTimeout) {
3480:                                        m_socket.setSoTimeout(m_pingTimeout);
3481:                                    }
3482:
3483:                                    break;
3484:
3485:                                case WRAPPER_MSG_SERVICE_CONTROL_CODE:
3486:                                    try {
3487:                                        int serviceControlCode = Integer
3488:                                                .parseInt(msg);
3489:                                        if (m_debug) {
3490:                                            m_out
3491:                                                    .println("ServiceControlCode from Wrapper with code "
3492:                                                            + serviceControlCode);
3493:                                        }
3494:                                        WrapperServiceControlEvent event = new WrapperServiceControlEvent(
3495:                                                serviceControlCode);
3496:                                        fireWrapperEvent(event);
3497:                                    } catch (NumberFormatException e) {
3498:                                        m_out
3499:                                                .println("Encountered an Illegal ServiceControlCode from "
3500:                                                        + "the Wrapper: " + msg);
3501:                                    }
3502:                                    break;
3503:
3504:                                case WRAPPER_MSG_PROPERTIES:
3505:                                    readProperties(msg);
3506:                                    break;
3507:
3508:                                default:
3509:                                    // Ignore unknown messages
3510:                                    m_out
3511:                                            .println("Wrapper code received an unknown packet type: "
3512:                                                    + code);
3513:                                    break;
3514:                                }
3515:                            }
3516:                        } catch (InterruptedIOException e) {
3517:                            int nowTicks = getTicks();
3518:
3519:                            // Unless the JVM is shutting dowm we want to show warning messages and maybe exit.
3520:                            if ((m_started) && (!m_stopping)) {
3521:                                if (m_debug) {
3522:                                    m_out
3523:                                            .println("Read Timed out. (Last Ping was "
3524:                                                    + getTickAge(
3525:                                                            m_lastPingTicks,
3526:                                                            nowTicks)
3527:                                                    + " milliseconds ago)");
3528:                                }
3529:
3530:                                if (!m_appearHung) {
3531:                                    long lastPingAge = getTickAge(
3532:                                            m_lastPingTicks, nowTicks);
3533:                                    long eventRunnerAge = getTickAge(
3534:                                            m_eventRunnerTicks, nowTicks);
3535:
3536:                                    // We may have timed out because the system was extremely busy or
3537:                                    //  suspended.  Only restart due to a lack of ping events if the
3538:                                    //  event thread has been running.
3539:                                    if (eventRunnerAge < 10000) {
3540:                                        // Only perform ping timeout checks if ping timeouts are enabled.
3541:                                        if (m_pingTimeout > 0) {
3542:                                            // How long has it been since we received the last ping
3543:                                            //  from the Wrapper?
3544:                                            if (lastPingAge > m_pingTimeout + 90000) {
3545:                                                // It has been more than the ping timeout + 90 seconds,
3546:                                                //  so just give up and kill the JVM
3547:                                                m_out
3548:                                                        .println("Wrapper Manager: JVM did not exit.  Give up.");
3549:                                                safeSystemExit(1);
3550:                                            } else if (lastPingAge > m_pingTimeout) {
3551:                                                // It has been more than the ping timeout since the
3552:                                                //  JVM was last pinged.  Ask to be stopped (and restarted).
3553:                                                m_out
3554:                                                        .println("Wrapper Manager: The Wrapper code did not ping the "
3555:                                                                + "JVM for "
3556:                                                                + (lastPingAge / 1000)
3557:                                                                + " seconds.  "
3558:                                                                + "Quit and let the Wrapper resynch.");
3559:
3560:                                                // Don't do anything if we are already stopping
3561:                                                if (!m_stopping) {
3562:                                                    // Always send the stop command
3563:                                                    sendCommand(
3564:                                                            WRAPPER_MSG_RESTART,
3565:                                                            "restart");
3566:
3567:                                                    // Give the Wrapper a chance to register the stop
3568:                                                    //  command before stopping.
3569:                                                    // This avoids any errors thrown by the Wrapper because
3570:                                                    //  the JVM died before it was expected to.
3571:                                                    try {
3572:                                                        Thread.sleep(1000);
3573:                                                    } catch (InterruptedException e2) {
3574:                                                    }
3575:
3576:                                                    privilegedStopInner(1);
3577:                                                }
3578:                                            }
3579:                                        }
3580:                                    }
3581:                                }
3582:                            }
3583:                        }
3584:                    }
3585:                    return;
3586:
3587:                } catch (SocketException e) {
3588:                    if (m_debug) {
3589:                        if (m_socket == null) {
3590:                            // This error happens if the socket is closed while reading:
3591:                            // java.net.SocketException: Descriptor not a socket: JVM_recv in socket
3592:                            //                           input stream read
3593:                        } else {
3594:                            m_out.println("Closed socket: " + e);
3595:                        }
3596:                    }
3597:                    return;
3598:                } catch (IOException e) {
3599:                    // This means that the connection was closed.  Allow this to return.
3600:                    //m_out.println( e );
3601:                    //e.printStackTrace();
3602:                    return;
3603:                }
3604:            }
3605:
3606:            private static void startRunner() {
3607:                if (isControlledByNativeWrapper()) {
3608:                    if (m_commRunner == null) {
3609:                        // Create and launch a new thread to manage this connection
3610:                        m_commRunner = new Thread(m_instance,
3611:                                WRAPPER_CONNECTION_THREAD_NAME);
3612:                        m_commRunner.setDaemon(true);
3613:                        m_commRunner.start();
3614:                    }
3615:
3616:                    // Wait to give the runner a chance to connect.
3617:                    synchronized (WrapperManager.class) {
3618:                        while (!m_commRunnerStarted) {
3619:                            try {
3620:                                WrapperManager.class.wait(100);
3621:                            } catch (InterruptedException e) {
3622:                            }
3623:                        }
3624:                    }
3625:                } else {
3626:                    // Immediately mark the runner as started as it will never be used.
3627:                    synchronized (WrapperManager.class) {
3628:                        m_commRunnerStarted = true;
3629:                        WrapperManager.class.notifyAll();
3630:                    }
3631:                }
3632:            }
3633:
3634:            /*---------------------------------------------------------------
3635:             * Runnable Methods
3636:             *-------------------------------------------------------------*/
3637:            public void run() {
3638:                // Make sure that no other threads call this method.
3639:                if (Thread.currentThread() != m_commRunner) {
3640:                    throw new IllegalStateException(
3641:                            "Only the comm runner thread is allowed to call this method.");
3642:                }
3643:
3644:                if (m_debug) {
3645:                    m_out.println("Communications runner thread started.");
3646:                }
3647:
3648:                // This thread needs to have a very high priority so that it never
3649:                //	gets put behind other threads.
3650:                Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
3651:
3652:                // Initialize the last ping tick count.
3653:                m_lastPingTicks = getTicks();
3654:
3655:                boolean gotPortOnce = false;
3656:                while (!m_disposed) {
3657:                    try {
3658:                        try {
3659:                            openSocket();
3660:
3661:                            // After the socket has been opened the first time, mark the thread as
3662:                            //  started.  This must be done here to make sure that exits work correctly
3663:                            //  when called on startup.
3664:                            if (!m_commRunnerStarted) {
3665:                                synchronized (WrapperManager.class) {
3666:                                    m_commRunnerStarted = true;
3667:                                    WrapperManager.class.notifyAll();
3668:                                }
3669:                            }
3670:
3671:                            if (m_socket != null) {
3672:                                handleSocket();
3673:                            } else {
3674:                                // Failed, so wait for just a moment
3675:                                try {
3676:                                    Thread.sleep(100);
3677:                                } catch (InterruptedException e) {
3678:                                }
3679:                            }
3680:                        } finally {
3681:                            // Always close the socket here.
3682:                            closeSocket();
3683:                        }
3684:                    } catch (ThreadDeath td) {
3685:                        m_out.println(m_warning.format("SERVER_DAEMON_KILLED"));
3686:                    } catch (Throwable t) {
3687:                        if (!m_shuttingDown) {
3688:                            // Show a stack trace here because this is fairly critical
3689:                            m_out.println(m_error.format("SERVER_DAEMON_DIED"));
3690:                            t.printStackTrace();
3691:                        }
3692:                    }
3693:                }
3694:
3695:                // Make sure that noone is ever left waiting for this thread to start.
3696:                synchronized (WrapperManager.class) {
3697:                    if (!m_commRunnerStarted) {
3698:                        m_commRunnerStarted = true;
3699:                        WrapperManager.class.notifyAll();
3700:                    }
3701:                }
3702:
3703:                if (m_debug) {
3704:                    m_out.println(m_info.format("SERVER_DAEMON_SHUT_DOWN"));
3705:                }
3706:            }
3707:
3708:            /*---------------------------------------------------------------
3709:             * Inner Classes
3710:             *-------------------------------------------------------------*/
3711:            /**
3712:             * Mapping between WrapperEventListeners and their registered masks.
3713:             *  This is necessary to support the case where the same listener is
3714:             *  registered more than once.   It also makes it possible to reference
3715:             *  an array of these mappings without synchronization.
3716:             */
3717:            private static class WrapperEventListenerMask {
3718:                private WrapperEventListener m_listener;
3719:                private long m_mask;
3720:            }
3721:
3722:            private static class WrapperTickEventImpl extends WrapperTickEvent {
3723:                private int m_ticks;
3724:                private int m_tickOffset;
3725:
3726:                /**
3727:                 * Returns the tick count at the point the event is fired.
3728:                 *
3729:                 * @return The tick count at the point the event is fired.
3730:                 */
3731:                public int getTicks() {
3732:                    return m_ticks;
3733:                }
3734:
3735:                /**
3736:                 * Returns the offset between the tick count used by the Wrapper for time
3737:                 *  keeping and the tick count generated directly from the system time.
3738:                 *
3739:                 * This will be 0 in most cases.  But will be a positive value if the
3740:                 *  system time is ever set back for any reason.  It will be a negative
3741:                 *  value if the system time is set forward or if the system is under
3742:                 *  heavy load.  If the wrapper.use_system_time property is set to TRUE
3743:                 *  then the Wrapper will be using the system tick count for internal
3744:                 *  timing and this value will always be 0.
3745:                 *
3746:                 * @return The tick count offset.
3747:                 */
3748:                public int getTickOffset() {
3749:                    return m_tickOffset;
3750:                }
3751:            }
3752:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.