0001: /*
0002: * JBoss, Home of Professional Open Source.
0003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
0004: * as indicated by the @author tags. See the copyright.txt file in the
0005: * distribution for a full listing of individual contributors.
0006: *
0007: * This is free software; you can redistribute it and/or modify it
0008: * under the terms of the GNU Lesser General Public License as
0009: * published by the Free Software Foundation; either version 2.1 of
0010: * the License, or (at your option) any later version.
0011: *
0012: * This software is distributed in the hope that it will be useful,
0013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0015: * Lesser General Public License for more details.
0016: *
0017: * You should have received a copy of the GNU Lesser General Public
0018: * License along with this software; if not, write to the Free
0019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
0020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
0021: */
0022: package org.jboss.system.server;
0023:
0024: import java.io.File;
0025: import java.lang.reflect.Method;
0026: import java.net.URL;
0027: import java.util.ArrayList;
0028: import java.util.Date;
0029: import java.util.Iterator;
0030: import java.util.List;
0031: import java.util.Properties;
0032: import java.util.logging.LogManager;
0033:
0034: import javax.management.Attribute;
0035: import javax.management.ListenerNotFoundException;
0036: import javax.management.MBeanNotificationInfo;
0037: import javax.management.MBeanServer;
0038: import javax.management.MBeanServerFactory;
0039: import javax.management.Notification;
0040: import javax.management.NotificationEmitter;
0041: import javax.management.NotificationFilter;
0042: import javax.management.NotificationListener;
0043: import javax.management.ObjectInstance;
0044: import javax.management.ObjectName;
0045:
0046: import org.jboss.Version;
0047: import org.jboss.deployment.IncompleteDeploymentException;
0048: import org.jboss.deployment.MainDeployerMBean;
0049: import org.jboss.logging.JBossJDKLogManager;
0050: import org.jboss.logging.Logger;
0051: import org.jboss.mx.loading.RepositoryClassLoader;
0052: import org.jboss.mx.server.ServerConstants;
0053: import org.jboss.mx.util.JBossNotificationBroadcasterSupport;
0054: import org.jboss.mx.util.JMXExceptionDecoder;
0055: import org.jboss.mx.util.MBeanProxyExt;
0056: import org.jboss.mx.util.MBeanServerLocator;
0057: import org.jboss.mx.util.ObjectNameFactory;
0058: import org.jboss.net.protocol.URLStreamHandlerFactory;
0059: import org.jboss.system.ServiceControllerMBean;
0060: import org.jboss.system.server.jmx.LazyMBeanServer;
0061: import org.jboss.util.StopWatch;
0062: import org.jboss.util.file.FileSuffixFilter;
0063: import org.jboss.util.file.Files;
0064:
0065: /**
0066: * The main container component of a JBoss server instance.
0067: *
0068: * <h3>Concurrency</h3>
0069: * This class is <b>not</b> thread-safe.
0070: *
0071: * @jmx:mbean name="jboss.system:type=Server"
0072: *
0073: * @author <a href="mailto:marc.fleury@jboss.org">Marc Fleury</a>
0074: * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
0075: * @author <a href="mailto:scott.stark@jboss.org">Scott Stark</a>
0076: * @author <a href="mailto:dimitris@jboss.org">Dimitris Andreadis</a>
0077: * @version $Revision: 59334 $
0078: */
0079: public class ServerImpl implements Server, ServerImplMBean,
0080: NotificationEmitter {
0081: private final static ObjectName DEFAULT_LOADER_NAME = ObjectNameFactory
0082: .create(ServerConstants.DEFAULT_LOADER_NAME);
0083:
0084: /** Instance logger. */
0085: private Logger log;
0086:
0087: /** Container for version information. */
0088: private final Version version = Version.getInstance();
0089:
0090: /** Package information for org.jboss */
0091: private final Package jbossPackage = Package
0092: .getPackage("org.jboss");
0093:
0094: /** The basic configuration for the server. */
0095: private ServerConfigImpl config;
0096:
0097: /** The JMX MBeanServer which will serve as our communication bus. */
0098: private MBeanServer server;
0099:
0100: /** When the server was started. */
0101: private Date startDate;
0102:
0103: /** Flag to indicate if we are started. */
0104: private boolean started;
0105:
0106: /** The JVM shutdown hook */
0107: private ShutdownHook shutdownHook;
0108:
0109: /** The JBoss Life Thread */
0110: private LifeThread lifeThread;
0111:
0112: /** The NotificationBroadcaster implementation delegate */
0113: private JBossNotificationBroadcasterSupport broadcasterSupport;
0114:
0115: /** The bootstrap UCL class loader ObjectName */
0116: private ObjectName bootstrapUCLName;
0117: /** A flag indicating if shutdown has been called */
0118: private boolean isInShutdown;
0119:
0120: /**
0121: * No-arg constructor for {@link ServerLoader}.
0122: */
0123: public ServerImpl() {
0124: }
0125:
0126: /**
0127: * Initialize the Server instance.
0128: *
0129: * @param props The configuration properties for the server.
0130: *
0131: * @throws IllegalStateException Already initialized.
0132: * @throws Exception Failed to initialize.
0133: */
0134: public void init(final Properties props)
0135: throws IllegalStateException, Exception {
0136: if (props == null)
0137: throw new IllegalArgumentException("props is null");
0138: if (config != null)
0139: throw new IllegalStateException("already initialized");
0140:
0141: ClassLoader oldCL = Thread.currentThread()
0142: .getContextClassLoader();
0143:
0144: try {
0145: Thread.currentThread().setContextClassLoader(
0146: getClass().getClassLoader());
0147: doInit(props);
0148: } finally {
0149: Thread.currentThread().setContextClassLoader(oldCL);
0150: }
0151: }
0152:
0153: /** Actually does the init'ing... */
0154: private void doInit(final Properties props) throws Exception {
0155: // Create a new config object from the give properties
0156: this .config = new ServerConfigImpl(props);
0157:
0158: /* Initialize the logging layer using the Server.class. The server log
0159: directory is initialized prior to this to ensure the jboss.server.log.dir
0160: system property is set in case its used by the logging configs.
0161: */
0162: config.getServerLogDir();
0163: log = Logger.getLogger(Server.class);
0164:
0165: // Create the NotificationBroadcaster delegate
0166: broadcasterSupport = new JBossNotificationBroadcasterSupport();
0167:
0168: // Set the VM temp directory to the server tmp dir
0169: boolean overrideTmpDir = Boolean
0170: .getBoolean("jboss.server.temp.dir.overrideJavaTmpDir");
0171: if (overrideTmpDir) {
0172: File serverTmpDir = config.getServerTempDir();
0173: System.setProperty("java.io.tmpdir", serverTmpDir
0174: .getCanonicalPath());
0175: }
0176:
0177: // Setup URL handlers - do this before initializing the ServerConfig
0178: initURLHandlers();
0179: config.initURLs();
0180:
0181: log.info("Starting JBoss (MX MicroKernel)...");
0182:
0183: if (jbossPackage != null) {
0184: // Show what release this is...
0185: log.info("Release ID: "
0186: + jbossPackage.getImplementationTitle() + " "
0187: + jbossPackage.getImplementationVersion());
0188: } else {
0189: log
0190: .warn("could not get package info to display release, either the "
0191: + "jar manifest in jboss-system.jar has been mangled or you're "
0192: + "running unit tests from ant outside of JBoss itself.");
0193: }
0194:
0195: log.debug("Using config: " + config);
0196:
0197: // make sure our impl type is exposed
0198: log.debug("Server type: " + getClass());
0199:
0200: // log the boot classloader
0201: ClassLoader cl = getClass().getClassLoader();
0202: log.debug("Server loaded through: " + cl.getClass().getName());
0203:
0204: // log the boot URLs
0205: if (cl instanceof NoAnnotationURLClassLoader) {
0206: NoAnnotationURLClassLoader nacl = (NoAnnotationURLClassLoader) cl;
0207: URL[] bootURLs = nacl.getAllURLs();
0208: log.debug("Boot URLs:");
0209: for (int i = 0; i < bootURLs.length; i++) {
0210: log.debug(" " + bootURLs[i]);
0211: }
0212: }
0213:
0214: // Log the basic configuration elements
0215: log.info("Home Dir: " + config.getHomeDir());
0216: log.info("Home URL: " + config.getHomeURL());
0217: log.debug("Library URL: " + config.getLibraryURL());
0218: log.info("Patch URL: " + config.getPatchURL());
0219: log.info("Server Name: " + config.getServerName());
0220: log.info("Server Home Dir: " + config.getServerHomeDir());
0221: log.info("Server Home URL: " + config.getServerHomeURL());
0222: log.info("Server Log Dir: " + config.getServerLogDir());
0223: log.debug("Server Data Dir: " + config.getServerDataDir());
0224: log.info("Server Temp Dir: " + config.getServerTempDir());
0225: log.debug("Server Config URL: " + config.getServerConfigURL());
0226: log
0227: .debug("Server Library URL: "
0228: + config.getServerLibraryURL());
0229: log.info("Root Deployment Filename: "
0230: + config.getRootDeploymentFilename());
0231: }
0232:
0233: /**
0234: * The <code>initURLHandlers</code> method calls
0235: * internalInitURLHandlers. if requireJBossURLStreamHandlers is
0236: * false, any exceptions are logged and ignored.
0237: *
0238: */
0239: private void initURLHandlers() {
0240: if (config.getRequireJBossURLStreamHandlerFactory()) {
0241: internalInitURLHandlers();
0242: } // end of if ()
0243: else {
0244: try {
0245: internalInitURLHandlers();
0246: } catch (SecurityException e) {
0247: log
0248: .warn(
0249: "You do not have permissions to set URLStreamHandlerFactory",
0250: e);
0251: } // end of try-catch
0252: catch (Error e) {
0253: log.warn("URLStreamHandlerFactory already set", e);
0254: } // end of catch
0255: } // end of else
0256: }
0257:
0258: /**
0259: * Set up our only URLStreamHandlerFactory.
0260: * This is needed to ensure Sun's version is not used (as it leaves files
0261: * locked on Win2K/WinXP platforms.
0262: */
0263: private void internalInitURLHandlers() {
0264: try {
0265: // Install a URLStreamHandlerFactory that uses the TCL
0266: URL
0267: .setURLStreamHandlerFactory(new URLStreamHandlerFactory());
0268:
0269: // Preload JBoss URL handlers
0270: URLStreamHandlerFactory.preload();
0271: } catch (Error error) { //very naughty but we HAVE to do this or
0272: //we'll fail if we ever try to do this again
0273: log
0274: .warn("Caught Throwable Error, this probably means "
0275: + "we've already set the URLStreamHAndlerFactory before");
0276: //Sys.out because we don't have logging yet
0277: }
0278:
0279: // Include the default JBoss protocol handler package
0280: String handlerPkgs = System
0281: .getProperty("java.protocol.handler.pkgs");
0282: if (handlerPkgs != null) {
0283: handlerPkgs += "|org.jboss.net.protocol";
0284: } else {
0285: handlerPkgs = "org.jboss.net.protocol";
0286: }
0287: System.setProperty("java.protocol.handler.pkgs", handlerPkgs);
0288: }
0289:
0290: /**
0291: * Get the typed server configuration object which the
0292: * server has been initalized to use.
0293: *
0294: * @return Typed server configuration object.
0295: *
0296: * @throws IllegalStateException Not initialized.
0297: */
0298: public ServerConfig getConfig() throws IllegalStateException {
0299: if (config == null)
0300: throw new IllegalStateException("not initialized");
0301:
0302: return config;
0303: }
0304:
0305: /**
0306: * Check if the server is started.
0307: *
0308: * @return True if the server is started, else false.
0309: * @jmx:managed-attribute
0310: */
0311: public boolean isStarted() {
0312: return started;
0313: }
0314:
0315: /**
0316: Check if the shutdown operation has been called/is in progress.
0317:
0318: @return true if shutdown has been called, false otherwise
0319: */
0320: public boolean isInShutdown() {
0321: return isInShutdown;
0322: }
0323:
0324: /**
0325: * Start the Server instance.
0326: *
0327: * @throws IllegalStateException Already started or not initialized.
0328: * @throws Exception Failed to start.
0329: */
0330: public void start() throws IllegalStateException, Exception {
0331: // make sure we are initialized
0332: getConfig();
0333:
0334: // make sure we aren't started yet
0335: if (started)
0336: throw new IllegalStateException("already started");
0337:
0338: ClassLoader oldCL = Thread.currentThread()
0339: .getContextClassLoader();
0340:
0341: try {
0342: Thread.currentThread().setContextClassLoader(
0343: getClass().getClassLoader());
0344:
0345: // Deal with those pesky JMX throwables
0346: try {
0347: doStart();
0348: } catch (Exception e) {
0349: JMXExceptionDecoder.rethrow(e);
0350: }
0351: } catch (Throwable t) {
0352: log.debug("Failed to start", t);
0353:
0354: if (t instanceof Exception)
0355: throw (Exception) t;
0356: if (t instanceof Error)
0357: throw (Error) t;
0358:
0359: throw new org.jboss.util.UnexpectedThrowable(t);
0360: } finally {
0361: Thread.currentThread().setContextClassLoader(oldCL);
0362: }
0363: }
0364:
0365: /** Actually does the starting... */
0366: private void doStart() throws Exception {
0367: // See how long it takes us to start up
0368: StopWatch watch = new StopWatch(true);
0369:
0370: // remeber when we we started
0371: startDate = new Date();
0372:
0373: log.debug("Starting General Purpose Architecture (GPA)...");
0374:
0375: // Create the MBeanServer
0376: String builder = System.getProperty(
0377: ServerConstants.MBEAN_SERVER_BUILDER_CLASS_PROPERTY,
0378: ServerConstants.DEFAULT_MBEAN_SERVER_BUILDER_CLASS);
0379: System.setProperty(
0380: ServerConstants.MBEAN_SERVER_BUILDER_CLASS_PROPERTY,
0381: builder);
0382:
0383: // Check if we'll use the platform MBeanServer or instantiate our own
0384: if (config.getPlatformMBeanServer() == true) {
0385: // jdk1.5+
0386: ClassLoader cl = Thread.currentThread()
0387: .getContextClassLoader();
0388: Class clazz = cl
0389: .loadClass("java.lang.management.ManagementFactory");
0390: Method method = clazz.getMethod("getPlatformMBeanServer",
0391: null);
0392: server = (MBeanServer) method.invoke(null, null);
0393: // Tell the MBeanServerLocator to point to this server
0394: MBeanServerLocator.setJBoss(server);
0395: /* If the LazyMBeanServer was used, we need to reset to the jboss
0396: MBeanServer to use our implementation for the jboss services.
0397: */
0398: server = LazyMBeanServer.resetToJBossServer(server);
0399: } else {
0400: // Create our own MBeanServer
0401: server = MBeanServerFactory.createMBeanServer("jboss");
0402: }
0403: log.debug("Created MBeanServer: " + server);
0404:
0405: // Register server components
0406: server.registerMBean(this , ServerImplMBean.OBJECT_NAME);
0407: server.registerMBean(config, ServerConfigImplMBean.OBJECT_NAME);
0408:
0409: // Initialize spine boot libraries
0410: RepositoryClassLoader ucl = initBootLibraries();
0411: bootstrapUCLName = ucl.getObjectName();
0412: server.registerMBean(ucl, bootstrapUCLName);
0413:
0414: // Set ServiceClassLoader as classloader for the construction of
0415: // the basic system
0416: Thread.currentThread().setContextClassLoader(ucl);
0417:
0418: // General Purpose Architecture information
0419: createMBean("org.jboss.system.server.ServerInfo",
0420: "jboss.system:type=ServerInfo");
0421:
0422: // Service Controller
0423: ObjectName controller = createMBean(
0424: "org.jboss.system.ServiceController",
0425: "jboss.system:service=ServiceController");
0426:
0427: // Main Deployer
0428: ObjectName mainDeployer = startBootService(controller,
0429: "org.jboss.deployment.MainDeployer",
0430: "jboss.system:service=MainDeployer");
0431: server.setAttribute(mainDeployer, new Attribute(
0432: "ServiceController", controller));
0433:
0434: // Install the shutdown hook
0435: shutdownHook = new ShutdownHook(controller, mainDeployer);
0436: shutdownHook.setDaemon(true);
0437:
0438: try {
0439: Runtime.getRuntime().addShutdownHook(shutdownHook);
0440: log.debug("Shutdown hook added");
0441: } catch (Exception e) {
0442: log.warn("Failed to add shutdown hook; ignoring", e);
0443: }
0444:
0445: // JARDeployer, required to process <classpath>
0446: startBootService(controller,
0447: "org.jboss.deployment.JARDeployer",
0448: "jboss.system:service=JARDeployer");
0449:
0450: // SARDeployer, required to process *-service.xml
0451: startBootService(controller,
0452: "org.jboss.deployment.SARDeployer",
0453: "jboss.system:service=ServiceDeployer");
0454:
0455: log.info("Core system initialized");
0456:
0457: // Ok, now deploy the root deployable to finish the job
0458:
0459: MainDeployerMBean md = (MainDeployerMBean) MBeanProxyExt
0460: .create(MainDeployerMBean.class, mainDeployer, server);
0461:
0462: try {
0463: md.deploy(config.getServerConfigURL()
0464: + config.getRootDeploymentFilename());
0465: } catch (IncompleteDeploymentException e) {
0466: log
0467: .error(
0468: "Root deployment has missing dependencies; continuing",
0469: e);
0470: }
0471:
0472: lifeThread = new LifeThread();
0473: lifeThread.start();
0474:
0475: started = true;
0476:
0477: // Send a notification that the startup is complete
0478: Notification msg = new Notification(START_NOTIFICATION_TYPE,
0479: this , 1);
0480: msg.setUserData(new Long(watch.getLapTime()));
0481: sendNotification(msg);
0482:
0483: watch.stop();
0484:
0485: if (jbossPackage != null) {
0486: // Tell the world how fast it was =)
0487: log.info("JBoss (MX MicroKernel) ["
0488: + jbossPackage.getImplementationVersion()
0489: + "] Started in " + watch);
0490: } else {
0491: log
0492: .warn("could not get package info to display release, either the "
0493: + "jar manifest in jboss-boot.jar has been mangled or you're "
0494: + "running unit tests from ant outside of JBoss itself.");
0495: }
0496: }
0497:
0498: /**
0499: * Instantiate and register a service for the given classname into the MBean server.
0500: */
0501: private ObjectName createMBean(final String classname, String name)
0502: throws Exception {
0503: ObjectName mbeanName = null;
0504: if (name != null)
0505: mbeanName = new ObjectName(name);
0506: try {
0507: // See if there is an xmbean descriptor for the bootstrap mbean
0508: URL xmbeanDD = new URL("resource:xmdesc/" + classname
0509: + "-xmbean.xml");
0510: Object resource = server.instantiate(classname);
0511: // Create the XMBean
0512: Object[] args = { resource, xmbeanDD };
0513: String[] sig = { Object.class.getName(),
0514: URL.class.getName() };
0515: ObjectInstance instance = server.createMBean(
0516: "org.jboss.mx.modelmbean.XMBean", mbeanName,
0517: bootstrapUCLName, args, sig);
0518: mbeanName = instance.getObjectName();
0519: log.debug("Created system XMBean: " + mbeanName);
0520: } catch (Exception e) {
0521: log.debug("Failed to create xmbean for: " + classname);
0522: mbeanName = server.createMBean(classname, mbeanName)
0523: .getObjectName();
0524: log.debug("Created system MBean: " + mbeanName);
0525: }
0526:
0527: return mbeanName;
0528: }
0529:
0530: /**
0531: * Instantiate/register, create and start a service for the given classname.
0532: */
0533: private ObjectName startBootService(
0534: final ObjectName controllerName, final String classname,
0535: final String name) throws Exception {
0536: ObjectName mbeanName = createMBean(classname, name);
0537:
0538: // now go through the create/start sequence on the new service
0539:
0540: Object[] args = { mbeanName };
0541: String[] sig = { ObjectName.class.getName() };
0542:
0543: server.invoke(controllerName, "create", args, sig);
0544: server.invoke(controllerName, "start", args, sig);
0545:
0546: return mbeanName;
0547: }
0548:
0549: /**
0550: * Initialize the boot libraries.
0551: */
0552: private RepositoryClassLoader initBootLibraries() throws Exception {
0553: // Build the list of URL for the spine to boot
0554: List list = new ArrayList();
0555:
0556: // Add the patch URL. If the url protocol is file, then
0557: // add the contents of the directory it points to
0558: URL patchURL = config.getPatchURL();
0559: if (patchURL != null) {
0560: if (patchURL.getProtocol().equals("file")) {
0561: File dir = new File(patchURL.getFile());
0562: if (dir.exists()) {
0563: // Add the local file patch directory
0564: list.add(dir.toURL());
0565:
0566: // Add the contents of the directory too
0567: File[] jars = dir.listFiles(new FileSuffixFilter(
0568: new String[] { ".jar", ".zip" }, true));
0569:
0570: for (int j = 0; jars != null && j < jars.length; j++) {
0571: list.add(jars[j].getCanonicalFile().toURL());
0572: }
0573: }
0574: } else {
0575: list.add(patchURL);
0576: }
0577: }
0578:
0579: // Add the server configuration directory to be able to load config files as resources
0580: list.add(config.getServerConfigURL());
0581:
0582: // Not needed, ServerImpl will have the basics on its classpath from ServerLoader
0583: // may want to bring this back at some point if we want to have reloadable core
0584: // components...
0585:
0586: // URL libraryURL = config.getLibraryURL();
0587: // list.add(new URL(libraryURL, "jboss-spine.jar"));
0588:
0589: log.debug("Boot url list: " + list);
0590:
0591: // Create loaders for each URL
0592: RepositoryClassLoader loader = null;
0593: for (Iterator iter = list.iterator(); iter.hasNext();) {
0594: URL url = (URL) iter.next();
0595: log.debug("Creating loader for URL: " + url);
0596:
0597: // This is a boot URL, so key it on itself.
0598: Object[] args = { url, Boolean.TRUE };
0599: String[] sig = { "java.net.URL", "boolean" };
0600: loader = (RepositoryClassLoader) server.invoke(
0601: DEFAULT_LOADER_NAME, "newClassLoader", args, sig);
0602: }
0603: return loader;
0604: }
0605:
0606: /**
0607: * Shutdown the Server instance and run shutdown hooks.
0608: *
0609: * <p>If the exit on shutdown flag is true, then {@link #exit}
0610: * is called, else only the shutdown hook is run.
0611: *
0612: * @jmx:managed-operation
0613: *
0614: * @throws IllegalStateException No started.
0615: */
0616: public void shutdown() throws IllegalStateException {
0617: if (log.isTraceEnabled())
0618: log.trace("Shutdown caller:", new Throwable("Here"));
0619:
0620: if (!started)
0621: throw new IllegalStateException("Server not started");
0622:
0623: isInShutdown = true;
0624: boolean exitOnShutdown = config.getExitOnShutdown();
0625: boolean blockingShutdown = config.getBlockingShutdown();
0626: log.info("Shutting down the server, blockingShutdown: "
0627: + blockingShutdown);
0628:
0629: if (exitOnShutdown) {
0630: exit(0);
0631: } else {
0632: // signal lifethread to exit; if no non-daemon threads
0633: // remain, the JVM will eventually exit
0634: lifeThread.interrupt();
0635:
0636: if (blockingShutdown) {
0637: shutdownHook.shutdown();
0638: } else {
0639: // start in new thread to give positive
0640: // feedback to requesting client of success.
0641: new Thread() {
0642: public void run() {
0643: // just run the hook, don't call System.exit, as we may
0644: // be embeded in a vm that would not like that very much
0645: shutdownHook.shutdown();
0646: }
0647: }.start();
0648: }
0649: }
0650: }
0651:
0652: /**
0653: * Exit the JVM, run shutdown hooks, shutdown the server.
0654: *
0655: * @jmx:managed-operation
0656: *
0657: * @param exitcode The exit code returned to the operating system.
0658: */
0659: public void exit(final int exitcode) {
0660: // exit() in new thread so that we might have a chance to give positive
0661: // feed back to requesting client of success.
0662: new Thread() {
0663: public void run() {
0664: log.info("Server exit(" + exitcode + ") called");
0665:
0666: // Set exit code in the shutdown hook, in case halt is enabled
0667: shutdownHook.setHaltExitCode(exitcode);
0668:
0669: // Initiate exiting, shutdown hook will be called
0670: Runtime.getRuntime().exit(exitcode);
0671: }
0672: }.start();
0673: }
0674:
0675: /**
0676: * Exit the JVM with code 1, run shutdown hooks, shutdown the server.
0677: *
0678: * @jmx:managed-operation
0679: */
0680: public void exit() {
0681: exit(1);
0682: }
0683:
0684: /**
0685: * Forcibly terminates the currently running Java virtual machine.
0686: *
0687: * @param exitcode The exit code returned to the operating system.
0688: *
0689: * @jmx:managed-operation
0690: */
0691: public void halt(final int exitcode) {
0692: // halt() in new thread so that we might have a chance to give positive
0693: // feed back to requesting client of success.
0694: new Thread() {
0695: public void run() {
0696: System.err.println("Server halt(" + exitcode
0697: + ") called, halting the JVM now!");
0698: Runtime.getRuntime().halt(exitcode);
0699: }
0700: }.start();
0701: }
0702:
0703: /**
0704: * Forcibly terminates the currently running Java virtual machine.
0705: * Halts with code 1.
0706: *
0707: * @jmx:managed-operation
0708: */
0709: public void halt() {
0710: halt(1);
0711: }
0712:
0713: ///////////////////////////////////////////////////////////////////////////
0714: // Runtime Access //
0715: ///////////////////////////////////////////////////////////////////////////
0716:
0717: /** A simple helper used to log the Runtime memory information. */
0718: private void logMemoryUsage(final Runtime rt) {
0719: log.info("Total/free memory: " + rt.totalMemory() + "/"
0720: + rt.freeMemory());
0721: }
0722:
0723: /**
0724: * Hint to the JVM to run the garbage collector.
0725: *
0726: * @jmx:managed-operation
0727: */
0728: public void runGarbageCollector() {
0729: Runtime rt = Runtime.getRuntime();
0730:
0731: logMemoryUsage(rt);
0732: rt.gc();
0733: log.info("Hinted to the JVM to run garbage collection");
0734: logMemoryUsage(rt);
0735: }
0736:
0737: /**
0738: * Hint to the JVM to run any pending object finailizations.
0739: *
0740: * @jmx:managed-operation
0741: */
0742: public void runFinalization() {
0743: Runtime.getRuntime().runFinalization();
0744: log
0745: .info("Hinted to the JVM to run any pending object finalizations");
0746: }
0747:
0748: /**
0749: * Enable or disable tracing method calls at the Runtime level.
0750: *
0751: * @jmx:managed-operation
0752: */
0753: public void traceMethodCalls(final Boolean flag) {
0754: Runtime.getRuntime().traceMethodCalls(flag.booleanValue());
0755: }
0756:
0757: /**
0758: * Enable or disable tracing instructions the Runtime level.
0759: *
0760: * @jmx:managed-operation
0761: */
0762: public void traceInstructions(final Boolean flag) {
0763: Runtime.getRuntime().traceInstructions(flag.booleanValue());
0764: }
0765:
0766: ///////////////////////////////////////////////////////////////////////////
0767: // Server Information //
0768: ///////////////////////////////////////////////////////////////////////////
0769:
0770: /**
0771: * @jmx:managed-attribute
0772: */
0773: public Date getStartDate() {
0774: return startDate;
0775: }
0776:
0777: /**
0778: * @jmx:managed-attribute
0779: */
0780: public String getVersion() {
0781: return version.toString();
0782: }
0783:
0784: /**
0785: * @jmx:managed-attribute
0786: */
0787: public String getVersionName() {
0788: return version.getName();
0789: }
0790:
0791: /**
0792: * @jmx:managed-attribute
0793: */
0794: public String getVersionNumber() {
0795: return version.getVersionNumber();
0796: }
0797:
0798: /**
0799: * @jmx:managed-attribute
0800: */
0801: public String getBuildNumber() {
0802: return version.getBuildNumber();
0803: }
0804:
0805: /**
0806: * @jmx:managed-attribute
0807: */
0808: public String getBuildJVM() {
0809: return version.getBuildJVM();
0810: }
0811:
0812: /**
0813: * @jmx:managed-attribute
0814: */
0815: public String getBuildOS() {
0816: return version.getBuildOS();
0817: }
0818:
0819: /**
0820: * @jmx:managed-attribute
0821: */
0822: public String getBuildID() {
0823: return version.getBuildID();
0824: }
0825:
0826: /**
0827: * @jmx:managed-attribute
0828: */
0829: public String getBuildDate() {
0830: return version.getBuildDate();
0831: }
0832:
0833: ///////////////////////////////////////////////////////////////////////////
0834: // NotificationEmitter //
0835: ///////////////////////////////////////////////////////////////////////////
0836:
0837: public void addNotificationListener(NotificationListener listener,
0838: NotificationFilter filter, Object handback) {
0839: broadcasterSupport.addNotificationListener(listener, filter,
0840: handback);
0841: }
0842:
0843: public void removeNotificationListener(NotificationListener listener)
0844: throws ListenerNotFoundException {
0845: broadcasterSupport.removeNotificationListener(listener);
0846: }
0847:
0848: public void removeNotificationListener(
0849: NotificationListener listener, NotificationFilter filter,
0850: Object handback) throws ListenerNotFoundException {
0851: broadcasterSupport.removeNotificationListener(listener, filter,
0852: handback);
0853: }
0854:
0855: public MBeanNotificationInfo[] getNotificationInfo() {
0856: return broadcasterSupport.getNotificationInfo();
0857: }
0858:
0859: public void sendNotification(Notification notification) {
0860: broadcasterSupport.sendNotification(notification);
0861: }
0862:
0863: ///////////////////////////////////////////////////////////////////////////
0864: // Lifecycle Thread //
0865: ///////////////////////////////////////////////////////////////////////////
0866:
0867: /** A simple thread that keeps the vm alive in the event there are no
0868: * other threads started.
0869: */
0870: private class LifeThread extends Thread {
0871: Object lock = new Object();
0872:
0873: LifeThread() {
0874: super ("JBossLifeThread");
0875: }
0876:
0877: public void run() {
0878: synchronized (lock) {
0879: try {
0880: lock.wait();
0881: } catch (InterruptedException ignore) {
0882: }
0883: }
0884: log.debug("LifeThread.run() exits!");
0885: }
0886: }
0887:
0888: ///////////////////////////////////////////////////////////////////////////
0889: // Shutdown Hook //
0890: ///////////////////////////////////////////////////////////////////////////
0891:
0892: private class ShutdownHook extends Thread {
0893: /** The ServiceController which we will ask to shut things down with. */
0894: private ObjectName controller;
0895:
0896: /** The MainDeployer which we will ask to undeploy everything. */
0897: private ObjectName mainDeployer;
0898:
0899: /** Whether to halt the JMV at the end of the shutdown hook */
0900: private boolean forceHalt = true;
0901:
0902: /** The exit code to use if forceHalt is enabled */
0903: private int haltExitCode;
0904:
0905: /** Mark when shutdown has been performed */
0906: private boolean shutdownCalled;
0907:
0908: public ShutdownHook(final ObjectName controller,
0909: final ObjectName mainDeployer) {
0910: super ("JBoss Shutdown Hook");
0911:
0912: this .controller = controller;
0913: this .mainDeployer = mainDeployer;
0914:
0915: String value = System.getProperty(
0916: "jboss.shutdown.forceHalt", null);
0917: if (value != null) {
0918: forceHalt = new Boolean(value).booleanValue();
0919: }
0920: }
0921:
0922: public void setHaltExitCode(int haltExitCode) {
0923: this .haltExitCode = haltExitCode;
0924: }
0925:
0926: public void run() {
0927: log.info("Runtime shutdown hook called, forceHalt: "
0928: + forceHalt);
0929:
0930: // shutdown the server
0931: shutdown();
0932:
0933: // Execute the jdk JBossJDKLogManager doReset
0934: LogManager lm = LogManager.getLogManager();
0935: if (lm instanceof JBossJDKLogManager) {
0936: JBossJDKLogManager jbosslm = (JBossJDKLogManager) lm;
0937: jbosslm.doReset();
0938: }
0939:
0940: // later bitch - other shutdown hooks may be killed
0941: if (forceHalt) {
0942: System.out.println("Halting VM");
0943: Runtime.getRuntime().halt(haltExitCode);
0944: }
0945: }
0946:
0947: public void shutdown() {
0948: if (log.isTraceEnabled())
0949: log.trace("Shutdown caller:", new Throwable("Here"));
0950:
0951: // avoid entering twice; may happen when called directly
0952: // from ServerImpl.shutdown(), then called again when all
0953: // non-daemon threads have exited and the ShutdownHook runs.
0954: if (shutdownCalled)
0955: return;
0956: else
0957: shutdownCalled = true;
0958:
0959: // Send a notification that server stop is initiated
0960: Notification msg = new Notification(STOP_NOTIFICATION_TYPE,
0961: this , 2);
0962: sendNotification(msg);
0963:
0964: // MainDeployer.shutdown()
0965: log.info("JBoss SHUTDOWN: Undeploying all packages");
0966: shutdownDeployments();
0967:
0968: // ServiceController.shutdown()
0969: log.debug("Shutting down all services");
0970: shutdownServices();
0971:
0972: // Make sure all mbeans are unregistered
0973: removeMBeans();
0974:
0975: // Cleanup tmp/deploy dir
0976: log.debug("Deleting server tmp/deploy directory");
0977: File tmp = config.getServerTempDir();
0978: File tmpDeploy = new File(tmp, "deploy");
0979: Files.delete(tmpDeploy);
0980:
0981: // Done
0982: log.info("Shutdown complete");
0983: System.out.println("Shutdown complete");
0984: }
0985:
0986: protected void shutdownDeployments() {
0987: try {
0988: // get the deployed objects from ServiceController
0989: server.invoke(mainDeployer, "shutdown", new Object[0],
0990: new String[0]);
0991: } catch (Exception e) {
0992: Throwable t = JMXExceptionDecoder.decode(e);
0993: log.error("Failed to shutdown deployer", t);
0994: }
0995: }
0996:
0997: /**
0998: * The <code>shutdownServices</code> method calls the one and only
0999: * ServiceController to shut down all the mbeans registered with it.
1000: */
1001: protected void shutdownServices() {
1002: try {
1003: // get the deployed objects from ServiceController
1004: server.invoke(controller, "shutdown", new Object[0],
1005: new String[0]);
1006: } catch (Exception e) {
1007: Throwable t = JMXExceptionDecoder.decode(e);
1008: log.error("Failed to shutdown services", t);
1009: }
1010: }
1011:
1012: /**
1013: * The <code>removeMBeans</code> method uses the mbean server to unregister
1014: * all the mbeans registered here.
1015: */
1016: protected void removeMBeans() {
1017: try {
1018: server
1019: .unregisterMBean(ServiceControllerMBean.OBJECT_NAME);
1020: server
1021: .unregisterMBean(ServerConfigImplMBean.OBJECT_NAME);
1022: server.unregisterMBean(ServerImplMBean.OBJECT_NAME);
1023: } catch (Exception e) {
1024: Throwable t = JMXExceptionDecoder.decode(e);
1025: log.error("Failed to unregister mbeans", t);
1026: }
1027: try {
1028: MBeanServer registeredServer = server;
1029: if (config.getPlatformMBeanServer() == true)
1030: registeredServer = LazyMBeanServer
1031: .getRegisteredMBeanServer(server);
1032: MBeanServerFactory.releaseMBeanServer(registeredServer);
1033: } catch (Exception e) {
1034: Throwable t = JMXExceptionDecoder.decode(e);
1035: log.error("Failed to release mbean server", t);
1036: }
1037: }
1038: }
1039: }
|