KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > system > server > ServerImpl


1 /*
2  * JBoss, Home of Professional Open Source
3  * Copyright 2005, JBoss Inc., and individual contributors as indicated
4  * by the @authors tag. See the copyright.txt in the distribution for a
5  * full listing of individual contributors.
6  *
7  * This is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU Lesser General Public License as
9  * published by the Free Software Foundation; either version 2.1 of
10  * the License, or (at your option) any later version.
11  *
12  * This software is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this software; if not, write to the Free
19  * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20  * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21  */

22 package org.jboss.system.server;
23
24 import java.io.File JavaDoc;
25 import java.lang.reflect.Method JavaDoc;
26 import java.net.URL JavaDoc;
27 import java.util.ArrayList JavaDoc;
28 import java.util.Date JavaDoc;
29 import java.util.Iterator JavaDoc;
30 import java.util.List JavaDoc;
31 import java.util.Properties JavaDoc;
32 import java.util.logging.LogManager JavaDoc;
33
34 import javax.management.Attribute JavaDoc;
35 import javax.management.ListenerNotFoundException JavaDoc;
36 import javax.management.MBeanNotificationInfo JavaDoc;
37 import javax.management.MBeanServer JavaDoc;
38 import javax.management.MBeanServerFactory JavaDoc;
39 import javax.management.Notification JavaDoc;
40 import javax.management.NotificationEmitter JavaDoc;
41 import javax.management.NotificationFilter JavaDoc;
42 import javax.management.NotificationListener JavaDoc;
43 import javax.management.ObjectInstance JavaDoc;
44 import javax.management.ObjectName JavaDoc;
45
46 import org.jboss.Version;
47 import org.jboss.deployment.IncompleteDeploymentException;
48 import org.jboss.deployment.MainDeployerMBean;
49 import org.jboss.logging.JBossJDKLogManager;
50 import org.jboss.logging.Logger;
51 import org.jboss.mx.loading.RepositoryClassLoader;
52 import org.jboss.mx.server.ServerConstants;
53 import org.jboss.mx.util.JBossNotificationBroadcasterSupport;
54 import org.jboss.mx.util.JMXExceptionDecoder;
55 import org.jboss.mx.util.MBeanProxyExt;
56 import org.jboss.mx.util.MBeanServerLocator;
57 import org.jboss.mx.util.ObjectNameFactory;
58 import org.jboss.net.protocol.URLStreamHandlerFactory;
59 import org.jboss.system.ServiceControllerMBean;
60 import org.jboss.system.server.jmx.LazyMBeanServer;
61 import org.jboss.util.StopWatch;
62 import org.jboss.util.file.FileSuffixFilter;
63 import org.jboss.util.file.Files;
64
65 /**
66  * The main container component of a JBoss server instance.
67  *
68  * <h3>Concurrency</h3>
69  * This class is <b>not</b> thread-safe.
70  *
71  * @jmx:mbean name="jboss.system:type=Server"
72  *
73  * @author <a HREF="mailto:marc.fleury@jboss.org">Marc Fleury</a>
74  * @author <a HREF="mailto:jason@planet57.com">Jason Dillon</a>
75  * @author <a HREF="mailto:scott.stark@jboss.org">Scott Stark</a>
76  * @author <a HREF="mailto:dimitris@jboss.org">Dimitris Andreadis</a>
77  * @version $Revision: 57108 $
78  */

79 public class ServerImpl
80    implements Server, ServerImplMBean, NotificationEmitter JavaDoc
81 {
82    private final static ObjectName JavaDoc DEFAULT_LOADER_NAME =
83       ObjectNameFactory.create(ServerConstants.DEFAULT_LOADER_NAME);
84
85    /** Instance logger. */
86    private Logger log;
87
88    /** Container for version information. */
89    private final Version version = Version.getInstance();
90
91    /** Package information for org.jboss */
92    private final Package JavaDoc jbossPackage = Package.getPackage("org.jboss");
93
94    /** The basic configuration for the server. */
95    private ServerConfigImpl config;
96
97    /** The JMX MBeanServer which will serve as our communication bus. */
98    private MBeanServer JavaDoc server;
99
100    /** When the server was started. */
101    private Date JavaDoc startDate;
102
103    /** Flag to indicate if we are started. */
104    private boolean started;
105
106    /** The JVM shutdown hook */
107    private ShutdownHook shutdownHook;
108
109    /** The JBoss Life Thread */
110    private LifeThread lifeThread;
111
112    /** The NotificationBroadcaster implementation delegate */
113    private JBossNotificationBroadcasterSupport broadcasterSupport;
114    
115    /** The bootstrap UCL class loader ObjectName */
116    private ObjectName JavaDoc bootstrapUCLName;
117    /** A flag indicating if shutdown has been called */
118    private boolean isInShutdown;
119
120    /**
121     * No-arg constructor for {@link ServerLoader}.
122     */

123    public ServerImpl()
124    {
125    }
126
127    /**
128     * Initialize the Server instance.
129     *
130     * @param props The configuration properties for the server.
131     *
132     * @throws IllegalStateException Already initialized.
133     * @throws Exception Failed to initialize.
134     */

135    public void init(final Properties JavaDoc props) throws IllegalStateException JavaDoc, Exception JavaDoc
136    {
137       if (props == null)
138          throw new IllegalArgumentException JavaDoc("props is null");
139       if (config != null)
140          throw new IllegalStateException JavaDoc("already initialized");
141
142       ClassLoader JavaDoc oldCL = Thread.currentThread().getContextClassLoader();
143
144       try
145       {
146          Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
147          doInit(props);
148       }
149       finally
150       {
151          Thread.currentThread().setContextClassLoader(oldCL);
152       }
153    }
154
155    /** Actually does the init'ing... */
156    private void doInit(final Properties JavaDoc props) throws Exception JavaDoc
157    {
158       // Create a new config object from the give properties
159
BaseServerConfig baseConfig = new BaseServerConfig(props);
160       this.config = new ServerConfigImpl(baseConfig);
161
162       /* Initialize the logging layer using the Server.class. The server log
163       directory is initialized prior to this to ensure the jboss.server.log.dir
164       system property is set in case its used by the logging configs.
165       */

166       config.getServerLogDir();
167       log = Logger.getLogger(Server.class);
168
169       // Create the NotificationBroadcaster delegate
170
broadcasterSupport = new JBossNotificationBroadcasterSupport();
171       
172       // Set the VM temp directory to the server tmp dir
173
boolean overrideTmpDir = Boolean.getBoolean("jboss.server.temp.dir.overrideJavaTmpDir");
174       if( overrideTmpDir )
175       {
176          File JavaDoc serverTmpDir = config.getServerTempDir();
177          System.setProperty("java.io.tmpdir", serverTmpDir.getCanonicalPath());
178       }
179
180       // Setup URL handlers - do this before initializing the ServerConfig
181
initURLHandlers();
182       baseConfig.initURLs();
183
184       log.info("Starting JBoss (MX MicroKernel)...");
185
186       if (jbossPackage != null)
187       {
188          // Show what release this is...
189
log.info("Release ID: " +
190                   jbossPackage.getImplementationTitle() + " " +
191                   jbossPackage.getImplementationVersion());
192       }
193       else
194       {
195          log.warn("could not get package info to display release, either the " +
196             "jar manifest in jboss-system.jar has been mangled or you're " +
197             "running unit tests from ant outside of JBoss itself.");
198       }
199
200       log.debug("Using config: " + config);
201
202       // make sure our impl type is exposed
203
log.debug("Server type: " + getClass());
204
205       // log the boot classloader
206
ClassLoader JavaDoc cl = getClass().getClassLoader();
207       log.debug("Server loaded through: " + cl.getClass().getName());
208       
209       // log the boot URLs
210
if (cl instanceof NoAnnotationURLClassLoader)
211       {
212          NoAnnotationURLClassLoader nacl = (NoAnnotationURLClassLoader)cl;
213          URL JavaDoc[] bootURLs = nacl.getAllURLs();
214          log.debug("Boot URLs:");
215          for (int i = 0; i < bootURLs.length; i++)
216          {
217             log.debug(" " + bootURLs[i]);
218          }
219       }
220       
221       // Log the basic configuration elements
222
log.info("Home Dir: " + config.getHomeDir());
223       log.info("Home URL: " + config.getHomeURL());
224       log.debug("Library URL: " + config.getLibraryURL());
225       log.info("Patch URL: " + config.getPatchURL());
226       log.info("Server Name: " + config.getServerName());
227       log.info("Server Home Dir: " + config.getServerHomeDir());
228       log.info("Server Home URL: " + config.getServerHomeURL());
229       log.debug("Server Data Dir: " + config.getServerDataDir());
230       log.info("Server Temp Dir: " + config.getServerTempDir());
231       log.debug("Server Config URL: " + config.getServerConfigURL());
232       log.debug("Server Library URL: " + config.getServerLibraryURL());
233       log.info("Root Deployment Filename: " + config.getRootDeploymentFilename());
234    }
235
236    /**
237     * The <code>initURLHandlers</code> method calls
238     * internalInitURLHandlers. if requireJBossURLStreamHandlers is
239     * false, any exceptions are logged and ignored.
240     *
241     */

242    private void initURLHandlers()
243    {
244       if (config.getRequireJBossURLStreamHandlerFactory())
245       {
246          internalInitURLHandlers();
247       } // end of if ()
248
else
249       {
250          try
251          {
252             internalInitURLHandlers();
253          }
254          catch (SecurityException JavaDoc e)
255          {
256             log.warn("You do not have permissions to set URLStreamHandlerFactory", e);
257          } // end of try-catch
258
catch (Error JavaDoc e)
259          {
260             log.warn("URLStreamHandlerFactory already set", e);
261          } // end of catch
262
} // end of else
263
}
264
265    /**
266     * Set up our only URLStreamHandlerFactory.
267     * This is needed to ensure Sun's version is not used (as it leaves files
268     * locked on Win2K/WinXP platforms.
269     */

270    private void internalInitURLHandlers()
271    {
272       try
273       {
274          // Install a URLStreamHandlerFactory that uses the TCL
275
URL.setURLStreamHandlerFactory(new URLStreamHandlerFactory());
276    
277          // Preload JBoss URL handlers
278
URLStreamHandlerFactory.preload();
279       }
280       catch (Error JavaDoc error)
281       { //very naughty but we HAVE to do this or
282
//we'll fail if we ever try to do this again
283
log.warn("Caught Throwable Error, this probably means " +
284             "we've already set the URLStreamHAndlerFactory before");
285          //Sys.out because we don't have logging yet
286
}
287
288       // Include the default JBoss protocol handler package
289
String JavaDoc handlerPkgs = System.getProperty("java.protocol.handler.pkgs");
290       if (handlerPkgs != null)
291       {
292          handlerPkgs += "|org.jboss.net.protocol";
293       }
294       else
295       {
296          handlerPkgs = "org.jboss.net.protocol";
297       }
298       System.setProperty("java.protocol.handler.pkgs", handlerPkgs);
299    }
300
301    /**
302     * Get the typed server configuration object which the
303     * server has been initalized to use.
304     *
305     * @return Typed server configuration object.
306     *
307     * @throws IllegalStateException Not initialized.
308     */

309    public ServerConfig getConfig() throws IllegalStateException JavaDoc
310    {
311       if (config == null)
312          throw new IllegalStateException JavaDoc("not initialized");
313
314       return config.getConfig();
315    }
316
317    /**
318     * Check if the server is started.
319     *
320     * @return True if the server is started, else false.
321     * @jmx:managed-attribute
322     */

323    public boolean isStarted()
324    {
325       return started;
326    }
327
328    /**
329     Check if the shutdown operation has been called/is in progress.
330
331     @return true if shutdown has been called, false otherwise
332     */

333    public boolean isInShutdown()
334    {
335       return isInShutdown;
336    }
337
338    /**
339     * Start the Server instance.
340     *
341     * @throws IllegalStateException Already started or not initialized.
342     * @throws Exception Failed to start.
343     */

344    public void start() throws IllegalStateException JavaDoc, Exception JavaDoc
345    {
346       // make sure we are initialized
347
getConfig();
348
349       // make sure we aren't started yet
350
if (started)
351          throw new IllegalStateException JavaDoc("already started");
352
353       ClassLoader JavaDoc oldCL = Thread.currentThread().getContextClassLoader();
354
355       try
356       {
357          Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
358
359          // Deal with those pesky JMX throwables
360
try
361          {
362             doStart();
363          }
364          catch (Exception JavaDoc e)
365          {
366             JMXExceptionDecoder.rethrow(e);
367          }
368       }
369       catch (Throwable JavaDoc t)
370       {
371          log.debug("Failed to start", t);
372
373          if (t instanceof Exception JavaDoc)
374             throw (Exception JavaDoc)t;
375          if (t instanceof Error JavaDoc)
376             throw (Error JavaDoc)t;
377
378          throw new org.jboss.util.UnexpectedThrowable(t);
379       }
380       finally
381       {
382          Thread.currentThread().setContextClassLoader(oldCL);
383       }
384    }
385
386    /** Actually does the starting... */
387    private void doStart() throws Exception JavaDoc
388    {
389       // See how long it takes us to start up
390
StopWatch watch = new StopWatch(true);
391
392       // remeber when we we started
393
startDate = new Date JavaDoc();
394
395       log.debug("Starting General Purpose Architecture (GPA)...");
396
397       // Create the MBeanServer
398
String JavaDoc builder = System.getProperty(ServerConstants.MBEAN_SERVER_BUILDER_CLASS_PROPERTY,
399                                           ServerConstants.DEFAULT_MBEAN_SERVER_BUILDER_CLASS);
400       System.setProperty(ServerConstants.MBEAN_SERVER_BUILDER_CLASS_PROPERTY, builder);
401       
402       // Check if we'll use the platform MBeanServer or instantiate our own
403
if (config.getPlatformMBeanServer() == true)
404       {
405          // jdk1.5+
406
ClassLoader JavaDoc cl = Thread.currentThread().getContextClassLoader();
407          Class JavaDoc clazz = cl.loadClass("java.lang.management.ManagementFactory");
408          Method JavaDoc method = clazz.getMethod("getPlatformMBeanServer", null);
409          server = (MBeanServer JavaDoc)method.invoke(null, null);
410          // Tell the MBeanServerLocator to point to this server
411
MBeanServerLocator.setJBoss(server);
412          /* If the LazyMBeanServer was used, we need to reset to the jboss
413          MBeanServer to use our implementation for the jboss services.
414          */

415          server = LazyMBeanServer.resetToJBossServer(server);
416       }
417       else
418       {
419          // Create our own MBeanServer
420
server = MBeanServerFactory.createMBeanServer("jboss");
421       }
422       log.debug("Created MBeanServer: " + server);
423
424       // Register server components
425
server.registerMBean(this, ServerImplMBean.OBJECT_NAME);
426       server.registerMBean(config, ServerConfigImplMBean.OBJECT_NAME);
427
428       // Initialize spine boot libraries
429
RepositoryClassLoader ucl = initBootLibraries();
430       bootstrapUCLName = ucl.getObjectName();
431       server.registerMBean(ucl, bootstrapUCLName);
432
433       // Set ServiceClassLoader as classloader for the construction of
434
// the basic system
435
Thread.currentThread().setContextClassLoader(ucl);
436
437       // General Purpose Architecture information
438
createMBean("org.jboss.system.server.ServerInfo",
439          "jboss.system:type=ServerInfo");
440
441       // Service Controller
442
ObjectName JavaDoc controller = createMBean("org.jboss.system.ServiceController",
443          "jboss.system:service=ServiceController");
444
445       // Main Deployer
446
ObjectName JavaDoc mainDeployer = startBootService(controller,
447          "org.jboss.deployment.MainDeployer", "jboss.system:service=MainDeployer");
448       server.setAttribute(mainDeployer,
449                           new Attribute JavaDoc("ServiceController", controller));
450
451       // Install the shutdown hook
452
shutdownHook = new ShutdownHook(controller, mainDeployer);
453       shutdownHook.setDaemon(true);
454
455       try
456       {
457          Runtime.getRuntime().addShutdownHook(shutdownHook);
458          log.debug("Shutdown hook added");
459       }
460       catch (Exception JavaDoc e)
461       {
462          log.warn("Failed to add shutdown hook; ignoring", e);
463       }
464
465       // JARDeployer, required to process <classpath>
466
startBootService(controller, "org.jboss.deployment.JARDeployer",
467          "jboss.system:service=JARDeployer");
468
469       // SARDeployer, required to process *-service.xml
470
startBootService(controller, "org.jboss.deployment.SARDeployer",
471          "jboss.system:service=ServiceDeployer");
472
473       log.info("Core system initialized");
474
475       // Ok, now deploy the root deployable to finish the job
476

477       MainDeployerMBean md = (MainDeployerMBean)
478          MBeanProxyExt.create(MainDeployerMBean.class, mainDeployer, server);
479
480       try
481       {
482          md.deploy(config.getServerConfigURL() + config.getRootDeploymentFilename());
483       }
484       catch (IncompleteDeploymentException e)
485       {
486          log.error("Root deployment has missing dependencies; continuing", e);
487       }
488
489       lifeThread = new LifeThread();
490       lifeThread.start();
491
492       started = true;
493       
494       // Send a notification that the startup is complete
495
Notification JavaDoc msg = new Notification JavaDoc(START_NOTIFICATION_TYPE, this, 1);
496       msg.setUserData(new Long JavaDoc(watch.getLapTime()));
497       sendNotification(msg);
498       
499       watch.stop();
500
501       if (jbossPackage != null)
502       {
503          // Tell the world how fast it was =)
504
log.info("JBoss (MX MicroKernel) [" + jbossPackage.getImplementationVersion() +
505                   "] Started in " + watch);
506       }
507       else
508       {
509          log.warn("could not get package info to display release, either the " +
510             "jar manifest in jboss-boot.jar has been mangled or you're " +
511             "running unit tests from ant outside of JBoss itself.");
512       }
513    }
514
515    /**
516     * Instantiate and register a service for the given classname into the MBean server.
517     */

518    private ObjectName JavaDoc createMBean(final String JavaDoc classname, String JavaDoc name)
519       throws Exception JavaDoc
520    {
521       ObjectName JavaDoc mbeanName = null;
522       if( name != null )
523          mbeanName = new ObjectName JavaDoc(name);
524       try
525       {
526          // See if there is an xmbean descriptor for the bootstrap mbean
527
URL JavaDoc xmbeanDD = new URL JavaDoc("resource:xmdesc/"+classname+"-xmbean.xml");
528          Object JavaDoc resource = server.instantiate(classname);
529          // Create the XMBean
530
Object JavaDoc[] args = {resource, xmbeanDD};
531          String JavaDoc[] sig = {Object JavaDoc.class.getName(), URL JavaDoc.class.getName()};
532          ObjectInstance JavaDoc instance = server.createMBean("org.jboss.mx.modelmbean.XMBean",
533                                        mbeanName,
534                                        bootstrapUCLName,
535                                        args,
536                                        sig);
537          mbeanName = instance.getObjectName();
538          log.debug("Created system XMBean: "+mbeanName);
539       }
540       catch(Exception JavaDoc e)
541       {
542          log.debug("Failed to create xmbean for: "+classname);
543          mbeanName = server.createMBean(classname, mbeanName).getObjectName();
544          log.debug("Created system MBean: " + mbeanName);
545       }
546
547       return mbeanName;
548    }
549
550    /**
551     * Instantiate/register, create and start a service for the given classname.
552     */

553    private ObjectName JavaDoc startBootService(final ObjectName JavaDoc controllerName,
554       final String JavaDoc classname, final String JavaDoc name)
555       throws Exception JavaDoc
556    {
557       ObjectName JavaDoc mbeanName = createMBean(classname, name);
558
559       // now go through the create/start sequence on the new service
560

561       Object JavaDoc[] args = { mbeanName };
562       String JavaDoc[] sig = { ObjectName JavaDoc.class.getName() };
563
564       server.invoke(controllerName, "create", args, sig);
565       server.invoke(controllerName, "start", args, sig);
566
567       return mbeanName;
568    }
569
570    /**
571     * Initialize the boot libraries.
572     */

573    private RepositoryClassLoader initBootLibraries() throws Exception JavaDoc
574    {
575       // Build the list of URL for the spine to boot
576
List JavaDoc list = new ArrayList JavaDoc();
577
578       // Add the patch URL. If the url protocol is file, then
579
// add the contents of the directory it points to
580
URL JavaDoc patchURL = config.getPatchURL();
581       if (patchURL != null)
582       {
583          if (patchURL.getProtocol().equals("file"))
584          {
585             File JavaDoc dir = new File JavaDoc(patchURL.getFile());
586             if (dir.exists())
587             {
588                // Add the local file patch directory
589
list.add(dir.toURL());
590
591                // Add the contents of the directory too
592
File JavaDoc[] jars = dir.listFiles(new FileSuffixFilter(new String JavaDoc[] { ".jar", ".zip" }, true));
593
594                for (int j = 0; jars != null && j < jars.length; j++)
595                {
596                   list.add(jars[j].getCanonicalFile().toURL());
597                }
598             }
599          }
600          else
601          {
602             list.add(patchURL);
603          }
604       }
605
606       // Add the server configuration directory to be able to load config files as resources
607
list.add(config.getServerConfigURL());
608
609       // Not needed, ServerImpl will have the basics on its classpath from ServerLoader
610
// may want to bring this back at some point if we want to have reloadable core
611
// components...
612

613       // URL libraryURL = config.getLibraryURL();
614
// list.add(new URL(libraryURL, "jboss-spine.jar"));
615

616       log.debug("Boot url list: " + list);
617
618       // Create loaders for each URL
619
RepositoryClassLoader loader = null;
620       for (Iterator JavaDoc iter = list.iterator(); iter.hasNext();)
621       {
622          URL JavaDoc url = (URL JavaDoc)iter.next();
623          log.debug("Creating loader for URL: " + url);
624
625          // This is a boot URL, so key it on itself.
626
Object JavaDoc[] args = {url, Boolean.TRUE};
627          String JavaDoc[] sig = {"java.net.URL", "boolean"};
628          loader = (RepositoryClassLoader) server.invoke(DEFAULT_LOADER_NAME, "newClassLoader", args, sig);
629       }
630       return loader;
631    }
632
633    /**
634     * Shutdown the Server instance and run shutdown hooks.
635     *
636     * <p>If the exit on shutdown flag is true, then {@link #exit}
637     * is called, else only the shutdown hook is run.
638     *
639     * @jmx:managed-operation
640     *
641     * @throws IllegalStateException No started.
642     */

643    public void shutdown() throws IllegalStateException JavaDoc
644    {
645       if (log.isTraceEnabled())
646          log.trace("Shutdown caller:", new Throwable JavaDoc("Here"));
647       
648       if (!started)
649          throw new IllegalStateException JavaDoc("Server not started");
650
651       isInShutdown = true;
652       boolean exitOnShutdown = config.getExitOnShutdown();
653       boolean blockingShutdown = config.getBlockingShutdown();
654       log.info("Shutting down the server, blockingShutdown: " + blockingShutdown);
655       
656       if (exitOnShutdown)
657       {
658          exit(0);
659       }
660       else
661       {
662          // signal lifethread to exit; if no non-daemon threads
663
// remain, the JVM will eventually exit
664
lifeThread.interrupt();
665          
666          if (blockingShutdown)
667          {
668             shutdownHook.shutdown();
669          }
670          else
671          {
672             // start in new thread to give positive
673
// feedback to requesting client of success.
674
new Thread JavaDoc()
675             {
676                public void run()
677                {
678                   // just run the hook, don't call System.exit, as we may
679
// be embeded in a vm that would not like that very much
680
shutdownHook.shutdown();
681                }
682             }.start();
683          }
684       }
685    }
686
687    /**
688     * Exit the JVM, run shutdown hooks, shutdown the server.
689     *
690     * @jmx:managed-operation
691     *
692     * @param exitcode The exit code returned to the operating system.
693     */

694    public void exit(final int exitcode)
695    {
696       // exit() in new thread so that we might have a chance to give positive
697
// feed back to requesting client of success.
698
new Thread JavaDoc()
699       {
700          public void run()
701          {
702             log.info("Server exit(" + exitcode + ") called");
703             
704             // Set exit code in the shutdown hook, in case halt is enabled
705
shutdownHook.setHaltExitCode(exitcode);
706             
707             // Initiate exiting, shutdown hook will be called
708
Runtime.getRuntime().exit(exitcode);
709          }
710       }.start();
711    }
712
713    /**
714     * Exit the JVM with code 1, run shutdown hooks, shutdown the server.
715     *
716     * @jmx:managed-operation
717     */

718    public void exit()
719    {
720       exit(1);
721    }
722
723    /**
724     * Forcibly terminates the currently running Java virtual machine.
725     *
726     * @param exitcode The exit code returned to the operating system.
727     *
728     * @jmx:managed-operation
729     */

730    public void halt(final int exitcode)
731    {
732       // halt() in new thread so that we might have a chance to give positive
733
// feed back to requesting client of success.
734
new Thread JavaDoc()
735       {
736          public void run()
737          {
738             System.err.println("Server halt(" + exitcode + ") called, halting the JVM now!");
739             Runtime.getRuntime().halt(exitcode);
740          }
741       }.start();
742    }
743
744    /**
745     * Forcibly terminates the currently running Java virtual machine.
746     * Halts with code 1.
747     *
748     * @jmx:managed-operation
749     */

750    public void halt()
751    {
752       halt(1);
753    }
754
755
756    ///////////////////////////////////////////////////////////////////////////
757
// Runtime Access //
758
///////////////////////////////////////////////////////////////////////////
759

760    /** A simple helper used to log the Runtime memory information. */
761    private void logMemoryUsage(final Runtime JavaDoc rt)
762    {
763       log.info("Total/free memory: " + rt.totalMemory() + "/" + rt.freeMemory());
764    }
765
766    /**
767     * Hint to the JVM to run the garbage collector.
768     *
769     * @jmx:managed-operation
770     */

771    public void runGarbageCollector()
772    {
773       Runtime JavaDoc rt = Runtime.getRuntime();
774
775       logMemoryUsage(rt);
776       rt.gc();
777       log.info("Hinted to the JVM to run garbage collection");
778       logMemoryUsage(rt);
779    }
780
781    /**
782     * Hint to the JVM to run any pending object finailizations.
783     *
784     * @jmx:managed-operation
785     */

786    public void runFinalization()
787    {
788       Runtime.getRuntime().runFinalization();
789       log.info("Hinted to the JVM to run any pending object finalizations");
790    }
791
792    /**
793     * Enable or disable tracing method calls at the Runtime level.
794     *
795     * @jmx:managed-operation
796     */

797    public void traceMethodCalls(final Boolean JavaDoc flag)
798    {
799       Runtime.getRuntime().traceMethodCalls(flag.booleanValue());
800    }
801
802    /**
803     * Enable or disable tracing instructions the Runtime level.
804     *
805     * @jmx:managed-operation
806     */

807    public void traceInstructions(final Boolean JavaDoc flag)
808    {
809       Runtime.getRuntime().traceInstructions(flag.booleanValue());
810    }
811
812
813    ///////////////////////////////////////////////////////////////////////////
814
// Server Information //
815
///////////////////////////////////////////////////////////////////////////
816

817    /**
818     * @jmx:managed-attribute
819     */

820    public Date JavaDoc getStartDate()
821    {
822       return startDate;
823    }
824
825    /**
826     * @jmx:managed-attribute
827     */

828    public String JavaDoc getVersion()
829    {
830       return version.toString();
831    }
832
833    /**
834     * @jmx:managed-attribute
835     */

836    public String JavaDoc getVersionName()
837    {
838       return version.getName();
839    }
840
841    /**
842     * @jmx:managed-attribute
843     */

844    public String JavaDoc getBuildNumber()
845    {
846       return version.getBuildNumber();
847    }
848
849    /**
850     * @jmx:managed-attribute
851     */

852    public String JavaDoc getBuildJVM()
853    {
854       return version.getBuildJVM();
855    }
856
857    /**
858     * @jmx:managed-attribute
859     */

860    public String JavaDoc getBuildOS()
861    {
862       return version.getBuildOS();
863    }
864
865    /**
866     * @jmx:managed-attribute
867     */

868    public String JavaDoc getBuildID()
869    {
870       return version.getBuildID();
871    }
872
873    /**
874     * @jmx:managed-attribute
875     */

876    public String JavaDoc getBuildDate()
877    {
878       return version.getBuildDate();
879    }
880
881    ///////////////////////////////////////////////////////////////////////////
882
// NotificationEmitter //
883
///////////////////////////////////////////////////////////////////////////
884

885    public void addNotificationListener(NotificationListener JavaDoc listener, NotificationFilter JavaDoc filter, Object JavaDoc handback)
886    {
887       broadcasterSupport.addNotificationListener(listener, filter, handback);
888    }
889    
890    public void removeNotificationListener(NotificationListener JavaDoc listener) throws ListenerNotFoundException JavaDoc
891    {
892       broadcasterSupport.removeNotificationListener(listener);
893    }
894    
895    public void removeNotificationListener(NotificationListener JavaDoc listener, NotificationFilter JavaDoc filter, Object JavaDoc handback)
896       throws ListenerNotFoundException JavaDoc
897    {
898       broadcasterSupport.removeNotificationListener(listener, filter, handback);
899    }
900       
901    public MBeanNotificationInfo JavaDoc[] getNotificationInfo()
902    {
903       return broadcasterSupport.getNotificationInfo();
904    }
905    
906    public void sendNotification(Notification JavaDoc notification)
907    {
908       broadcasterSupport.sendNotification(notification);
909    }
910    
911    ///////////////////////////////////////////////////////////////////////////
912
// Lifecycle Thread //
913
///////////////////////////////////////////////////////////////////////////
914

915    /** A simple thread that keeps the vm alive in the event there are no
916     * other threads started.
917     */

918    private class LifeThread
919       extends Thread JavaDoc
920    {
921       Object JavaDoc lock = new Object JavaDoc();
922       LifeThread()
923       {
924          super("JBossLifeThread");
925       }
926       public void run()
927       {
928          synchronized (lock)
929          {
930             try
931             {
932                lock.wait();
933             }
934             catch (InterruptedException JavaDoc ignore)
935             {
936             }
937          }
938          log.debug("LifeThread.run() exits!");
939       }
940    }
941
942    ///////////////////////////////////////////////////////////////////////////
943
// Shutdown Hook //
944
///////////////////////////////////////////////////////////////////////////
945

946    private class ShutdownHook
947       extends Thread JavaDoc
948    {
949       /** The ServiceController which we will ask to shut things down with. */
950       private ObjectName JavaDoc controller;
951
952       /** The MainDeployer which we will ask to undeploy everything. */
953       private ObjectName JavaDoc mainDeployer;
954
955       /** Whether to halt the JMV at the end of the shutdown hook */
956       private boolean forceHalt = true;
957       
958       /** The exit code to use if forceHalt is enabled */
959       private int haltExitCode;
960
961       /** Mark when shutdown has been performed */
962       private boolean shutdownCalled;
963       
964       public ShutdownHook(final ObjectName JavaDoc controller, final ObjectName JavaDoc mainDeployer)
965       {
966          super("JBoss Shutdown Hook");
967
968          this.controller = controller;
969          this.mainDeployer = mainDeployer;
970
971          String JavaDoc value = System.getProperty("jboss.shutdown.forceHalt", null);
972          if (value != null)
973          {
974             forceHalt = new Boolean JavaDoc(value).booleanValue();
975          }
976       }
977
978       public void setHaltExitCode(int haltExitCode)
979       {
980          this.haltExitCode = haltExitCode;
981       }
982       
983       public void run()
984       {
985          log.info("Runtime shutdown hook called, forceHalt: " + forceHalt);
986          
987          // shutdown the server
988
shutdown();
989
990          // Execute the jdk JBossJDKLogManager doReset
991
LogManager JavaDoc lm = LogManager.getLogManager();
992          if (lm instanceof JBossJDKLogManager)
993          {
994             JBossJDKLogManager jbosslm = (JBossJDKLogManager)lm;
995             jbosslm.doReset();
996          }
997          
998          // later bitch - other shutdown hooks may be killed
999
if (forceHalt)
1000         {
1001            System.out.println("Halting VM");
1002            Runtime.getRuntime().halt(haltExitCode);
1003         }
1004      }
1005
1006      public void shutdown()
1007      {
1008         if (log.isTraceEnabled())
1009            log.trace("Shutdown caller:", new Throwable JavaDoc("Here"));
1010         
1011         // avoid entering twice; may happen when called directly
1012
// from ServerImpl.shutdown(), then called again when all
1013
// non-daemon threads have exited and the ShutdownHook runs.
1014
if (shutdownCalled)
1015            return;
1016         else
1017            shutdownCalled = true;
1018         
1019         // Send a notification that server stop is initiated
1020
Notification JavaDoc msg = new Notification JavaDoc(STOP_NOTIFICATION_TYPE, this, 2);
1021         sendNotification(msg);
1022         
1023         // MainDeployer.shutdown()
1024
log.info("JBoss SHUTDOWN: Undeploying all packages");
1025         shutdownDeployments();
1026         
1027         // ServiceController.shutdown()
1028
log.debug("Shutting down all services");
1029         shutdownServices();
1030
1031         // Make sure all mbeans are unregistered
1032
removeMBeans();
1033
1034         // Cleanup tmp/deploy dir
1035
log.debug("Deleting server tmp/deploy directory");
1036         File JavaDoc tmp = config.getServerTempDir();
1037         File JavaDoc tmpDeploy = new File JavaDoc(tmp, "deploy");
1038         Files.delete(tmpDeploy);
1039
1040         // Done
1041
log.info("Shutdown complete");
1042         System.out.println("Shutdown complete");
1043      }
1044
1045      protected void shutdownDeployments()
1046      {
1047         try
1048         {
1049            // get the deployed objects from ServiceController
1050
server.invoke(mainDeployer,
1051                          "shutdown",
1052                          new Object JavaDoc[0],
1053                          new String JavaDoc[0]);
1054         }
1055         catch (Exception JavaDoc e)
1056         {
1057            Throwable JavaDoc t = JMXExceptionDecoder.decode(e);
1058            log.error("Failed to shutdown deployer", t);
1059         }
1060      }
1061
1062      /**
1063       * The <code>shutdownServices</code> method calls the one and only
1064       * ServiceController to shut down all the mbeans registered with it.
1065       */

1066      protected void shutdownServices()
1067      {
1068         try
1069         {
1070            // get the deployed objects from ServiceController
1071
server.invoke(controller,
1072                          "shutdown",
1073                          new Object JavaDoc[0],
1074                          new String JavaDoc[0]);
1075         }
1076         catch (Exception JavaDoc e)
1077         {
1078            Throwable JavaDoc t = JMXExceptionDecoder.decode(e);
1079            log.error("Failed to shutdown services", t);
1080         }
1081      }
1082
1083      /**
1084       * The <code>removeMBeans</code> method uses the mbean server to unregister
1085       * all the mbeans registered here.
1086       */

1087      protected void removeMBeans()
1088      {
1089         try
1090         {
1091            server.unregisterMBean(ServiceControllerMBean.OBJECT_NAME);
1092            server.unregisterMBean(ServerConfigImplMBean.OBJECT_NAME);
1093            server.unregisterMBean(ServerImplMBean.OBJECT_NAME);
1094         }
1095         catch (Exception JavaDoc e)
1096         {
1097            Throwable JavaDoc t = JMXExceptionDecoder.decode(e);
1098            log.error("Failed to unregister mbeans", t);
1099         }
1100         try
1101         {
1102            MBeanServer JavaDoc registeredServer = server;
1103            if (config.getPlatformMBeanServer() == true)
1104               registeredServer = LazyMBeanServer.getRegisteredMBeanServer(server);
1105            MBeanServerFactory.releaseMBeanServer(registeredServer);
1106         }
1107         catch (Exception JavaDoc e)
1108         {
1109            Throwable JavaDoc t = JMXExceptionDecoder.decode(e);
1110            log.error("Failed to release mbean server", t);
1111         }
1112      }
1113   }
1114}
1115
Popular Tags