1 /***************************************
2 * *
3 * JBoss: The OpenSource J2EE WebOS *
4 * *
5 * Distributable under LGPL license. *
6 * See terms of license at gnu.org. *
7 * *
8 ***************************************/
9
10 package org.jboss.system.server;
11
12 import java.io.File;
13 import java.net.URL;
14
15 import java.util.List;
16 import java.util.ArrayList;
17 import java.util.Date;
18 import java.util.Iterator;
19 import java.util.Properties;
20
21 import javax.management.Attribute;
22 import javax.management.MBeanServer;
23 import javax.management.MBeanServerFactory;
24 import javax.management.NotificationBroadcasterSupport;
25 import javax.management.ObjectName;
26 import javax.management.Notification;
27 import javax.management.NotificationListener;
28 import javax.management.NotificationFilter;
29 import javax.management.ListenerNotFoundException;
30 import javax.management.MBeanNotificationInfo;
31 import javax.management.NotificationBroadcaster;
32
33 import org.jboss.Version;
34 import org.jboss.deployment.MainDeployerMBean;
35 import org.jboss.deployment.IncompleteDeploymentException;
36 import org.jboss.logging.Logger;
37 import org.jboss.mx.loading.UnifiedClassLoader;
38 import org.jboss.mx.server.ServerConstants;
39 import org.jboss.net.protocol.URLStreamHandlerFactory;
40 import org.jboss.util.StopWatch;
41 import org.jboss.util.file.Files;
42 import org.jboss.util.file.FileSuffixFilter;
43 import org.jboss.mx.util.JMXExceptionDecoder;
44 import org.jboss.mx.util.ObjectNameFactory;
45 import org.jboss.mx.util.MBeanProxyExt;
46 import org.jboss.system.ServiceControllerMBean;
47
48
49 /**
50 * The main container component of a JBoss server instance.
51 *
52 * <h3>Concurrency</h3>
53 * This class is <b>not</b> thread-safe.
54 *
55 * @jmx:mbean name="jboss.system:type=Server"
56 *
57 * @author <a href="mailto:marc.fleury@jboss.org">Marc Fleury</a>
58 * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
59 * @author Scott.Stark@jboss.org
60 * @version $Revision: 1.25.2.17 $
61 */
62 public class ServerImpl
63 implements Server, ServerImplMBean, NotificationBroadcaster
64 {
65 private final static ObjectName DEFAULT_LOADER_NAME =
66 ObjectNameFactory.create(ServerConstants.DEFAULT_LOADER_NAME);
67
68 /** Instance logger. */
69 private Logger log;
70
71 /** Container for version information. */
72 private final Version version = Version.getInstance();
73
74 /** Package information for org.jboss */
75 private final Package jbossPackage = Package.getPackage("org.jboss");
76
77 /** The basic configuration for the server. */
78 private ServerConfigImpl config;
79
80 /** The JMX MBeanServer which will serve as our communication bus. */
81 private MBeanServer server;
82
83 /** When the server was started. */
84 private Date startDate;
85
86 /** Flag to indicate if we are started. */
87 private boolean started;
88
89 /** The JVM shutdown hook */
90 private ShutdownHook shutdownHook;
91
92 /** The JBoss Life Thread */
93 private LifeThread lifeThread;
94
95 /** The NotificationBroadcaster implementation delegate */
96 private NotificationBroadcasterSupport broadcasterSupport;
97
98 /**
99 * No-arg constructor for {@link ServerLoader}.
100 */
101 public ServerImpl()
102 {
103 }
104
105 /**
106 * Initialize the Server instance.
107 *
108 * @param props The configuration properties for the server.
109 * @return Typed server configuration object.
110 *
111 * @throws IllegalStateException Already initialized.
112 * @throws Exception Failed to initialize.
113 */
114 public void init(final Properties props) throws IllegalStateException, Exception
115 {
116 if (props == null)
117 throw new IllegalArgumentException("props is null");
118 if (config != null)
119 throw new IllegalStateException("already initialized");
120
121 ClassLoader oldCL = Thread.currentThread().getContextClassLoader();
122
123 try
124 {
125 Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
126 doInit(props);
127 }
128 finally
129 {
130 Thread.currentThread().setContextClassLoader(oldCL);
131 }
132 }
133
134 /** Actually does the init'ing... */
135 private void doInit(final Properties props) throws Exception
136 {
137 // Create a new config object from the give properties
138 this.config = new ServerConfigImpl(props);
139
140 // Create the NotificationBroadcaster delegate
141 broadcasterSupport = new NotificationBroadcasterSupport();
142
143 // Set the VM temp directory to the server tmp dir
144 boolean overrideTmpDir = Boolean.getBoolean("jboss.server.temp.dir.overrideJavaTmpDir");
145 if( overrideTmpDir )
146 {
147 File serverTmpDir = config.getServerTempDir();
148 System.setProperty("java.io.tmpdir", serverTmpDir.getCanonicalPath());
149 }
150
151 // masqurade as Server.class (cause Impl is not really important)
152 log = Logger.getLogger(Server.class);
153
154 // Setup URL handlers - do this before initializing the ServerConfig
155 initURLHandlers();
156 config.initURLs();
157
158 log.info("Starting JBoss (MX MicroKernel)...");
159
160 // Show what release this is...
161 log.info("Release ID: " +
162 jbossPackage.getImplementationTitle() + " " +
163 jbossPackage.getImplementationVersion());
164
165 log.debug("Using config: " + config);
166
167 // make sure our impl type is exposed
168 log.debug("Server type: " + getClass());
169
170 // Log the basic configuration elements
171 log.info("Home Dir: " + config.getHomeDir());
172 log.info("Home URL: " + config.getHomeURL());
173 log.info("Library URL: " + config.getLibraryURL());
174 log.info("Patch URL: " + config.getPatchURL());
175 log.info("Server Name: " + config.getServerName());
176 log.info("Server Home Dir: " + config.getServerHomeDir());
177 log.info("Server Home URL: " + config.getServerHomeURL());
178 log.info("Server Data Dir: " + config.getServerDataDir());
179 log.info("Server Temp Dir: " + config.getServerTempDir());
180 log.info("Server Config URL: " + config.getServerConfigURL());
181 log.info("Server Library URL: " + config.getServerLibraryURL());
182 log.info("Root Deployemnt Filename: " + config.getRootDeploymentFilename());
183 }
184
185 /**
186 * The <code>initURLHandlers</code> method calls
187 * internalInitURLHandlers. if requireJBossURLStreamHandlers is
188 * false, any exceptions are logged and ignored.
189 *
190 */
191 private void initURLHandlers()
192 {
193 if (config.getRequireJBossURLStreamHandlerFactory())
194 {
195 internalInitURLHandlers();
196 } // end of if ()
197 else
198 {
199 try
200 {
201 internalInitURLHandlers();
202 }
203 catch (SecurityException e)
204 {
205 log.warn("You do not have permissions to set URLStreamHandlerFactory", e);
206 } // end of try-catch
207 catch (Error e)
208 {
209 log.warn("URLStreamHandlerFactory already set", e);
210 } // end of catch
211 } // end of else
212 }
213
214 /**
215 * Set up our only URLStreamHandlerFactory.
216 * This is needed to ensure Sun's version is not used (as it leaves files
217 * locked on Win2K/WinXP platforms.
218 */
219 private void internalInitURLHandlers()
220 {
221 // Install a URLStreamHandlerFactory that uses the TCL
222 URL.setURLStreamHandlerFactory(new URLStreamHandlerFactory());
223
224 // Preload JBoss URL handlers
225 URLStreamHandlerFactory.preload();
226
227 // Include the default JBoss protocol handler package
228 String handlerPkgs = System.getProperty("java.protocol.handler.pkgs");
229 if (handlerPkgs != null)
230 {
231 handlerPkgs += "|org.jboss.net.protocol";
232 }
233 else
234 {
235 handlerPkgs = "org.jboss.net.protocol";
236 }
237 System.setProperty("java.protocol.handler.pkgs", handlerPkgs);
238 }
239
240 /**
241 * Get the typed server configuration object which the
242 * server has been initalized to use.
243 *
244 * @return Typed server configuration object.
245 *
246 * @throws IllegalStateException Not initialized.
247 */
248 public ServerConfig getConfig() throws IllegalStateException
249 {
250 if (config == null)
251 throw new IllegalStateException("not initialized");
252
253 return config;
254 }
255
256 /**
257 * Check if the server is started.
258 *
259 * @return True if the server is started, else false.
260 * @jmx:managed-attribute
261 */
262 public boolean isStarted()
263 {
264 return started;
265 }
266
267 /**
268 * Start the Server instance.
269 *
270 * @throws IllegalStateException Already started or not initialized.
271 * @throws Exception Failed to start.
272 */
273 public void start() throws IllegalStateException, Exception
274 {
275 // make sure we are initialized
276 getConfig();
277
278 // make sure we aren't started yet
279 if (started)
280 throw new IllegalStateException("already started");
281
282 ClassLoader oldCL = Thread.currentThread().getContextClassLoader();
283
284 try
285 {
286 Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
287
288 // Deal with those pesky JMX throwables
289 try
290 {
291 doStart();
292 }
293 catch (Exception e)
294 {
295 JMXExceptionDecoder.rethrow(e);
296 }
297 }
298 catch (Throwable t)
299 {
300 log.debug("Failed to start", t);
301
302 if (t instanceof Exception)
303 throw (Exception)t;
304 if (t instanceof Error)
305 throw (Error)t;
306
307 throw new org.jboss.util.UnexpectedThrowable(t);
308 }
309 finally
310 {
311 Thread.currentThread().setContextClassLoader(oldCL);
312 }
313 }
314
315 /** Actually does the starting... */
316 private void doStart() throws Exception
317 {
318 // See how long it takes us to start up
319 StopWatch watch = new StopWatch(true);
320
321 // remeber when we we started
322 startDate = new Date();
323
324 log.info("Starting General Purpose Architecture (GPA)...");
325
326 // Create the MBeanServer
327 server = MBeanServerFactory.createMBeanServer("jboss");
328 log.debug("Created MBeanServer: " + server);
329
330 // Register server components
331 server.registerMBean(this, ServerImplMBean.OBJECT_NAME);
332 server.registerMBean(config, ServerConfigImplMBean.OBJECT_NAME);
333
334 // Initialize spine boot libraries
335 UnifiedClassLoader ucl = initBootLibraries();
336
337 // Set ServiceClassLoader as classloader for the construction of
338 // the basic system
339 Thread.currentThread().setContextClassLoader(ucl);
340
341 // General Purpose Architecture information
342 createMBean("org.jboss.system.server.ServerInfo");
343
344 // Service Controller
345 ObjectName controller = createMBean("org.jboss.system.ServiceController");
346
347 // Main Deployer
348 ObjectName mainDeployer = startBootService(controller, "org.jboss.deployment.MainDeployer");
349 server.setAttribute(mainDeployer,
350 new Attribute("ServiceController", controller));
351
352 // Install the shutdown hook
353 shutdownHook = new ShutdownHook(controller, mainDeployer);
354 shutdownHook.setDaemon(true);
355
356 try
357 {
358 Runtime.getRuntime().addShutdownHook(shutdownHook);
359 log.debug("Shutdown hook added");
360 }
361 catch (Exception e)
362 {
363 log.warn("Failed to add shutdown hook; ignoring", e);
364 }
365
366 // JARDeployer, required to process <classpath>
367 startBootService(controller, "org.jboss.deployment.JARDeployer");
368
369 // SARDeployer, required to process *-service.xml
370 startBootService(controller, "org.jboss.deployment.SARDeployer");
371
372 log.info("Core system initialized");
373
374 // TODO: Split up init (ie. create) from start ops so we can expose more control
375 // to embeded clients.
376
377 // Ok, now deploy the root deployable to finish the job
378
379 MainDeployerMBean md = (MainDeployerMBean)
380 MBeanProxyExt.create(MainDeployerMBean.class, mainDeployer, server);
381
382 try
383 {
384 md.deploy(config.getServerConfigURL() + config.getRootDeploymentFilename());
385 }
386 catch (IncompleteDeploymentException e) {
387 log.error("Root deployment has missing dependencies; continuing", e);
388 }
389
390 lifeThread = new LifeThread();
391 lifeThread.start();
392
393 watch.stop();
394 // Tell the world how fast it was =)
395 log.info("JBoss (MX MicroKernel) [" + jbossPackage.getImplementationVersion() +
396 "] Started in " + watch);
397 started = true;
398
399 // Send a notification that the startup is complete
400 Notification msg = new Notification(START_NOTIFICATION_TYPE, this, 1);
401 msg.setUserData(new Long(watch.getLapTime()));
402 sendNotification(msg);
403 }
404
405 /**
406 * Instantiate and register a service for the given classname into the MBean server.
407 */
408 private ObjectName createMBean(final String classname)
409 throws Exception
410 {
411 ObjectName name = server.createMBean(classname, null).getObjectName();
412 log.debug("Created system MBean: " + name);
413
414 return name;
415 }
416
417 /**
418 * Instantiate/register, create and start a service for the given classname.
419 */
420 private ObjectName startBootService(final ObjectName controllerName, final String classname)
421 throws Exception
422 {
423 ObjectName name = createMBean(classname);
424
425 // now go through the create/start sequence on the new service
426
427 Object[] args = { name };
428 String[] sig = { ObjectName.class.getName() };
429
430 server.invoke(controllerName, "create", args, sig);
431 server.invoke(controllerName, "start", args, sig);
432
433 return name;
434 }
435
436 /**
437 * Initialize the boot libraries.
438 */
439 private UnifiedClassLoader initBootLibraries() throws Exception
440 {
441 boolean debug = log.isDebugEnabled();
442
443 // Build the list of URL for the spine to boot
444 List list = new ArrayList();
445
446 // Add the patch URL. If the url protocol is file, then
447 // add the contents of the directory it points to
448 URL patchURL = config.getPatchURL();
449 if (patchURL != null)
450 {
451 if (patchURL.getProtocol().equals("file"))
452 {
453 File dir = new File(patchURL.getFile());
454 if (dir.exists())
455 {
456 // Add the local file patch directory
457 list.add(dir.toURL());
458
459 // Add the contents of the directory too
460 File[] jars = dir.listFiles(new FileSuffixFilter(new String[] { ".jar", ".zip" }, true));
461
462 for (int j = 0; jars != null && j < jars.length; j++)
463 {
464 list.add(jars[j].getCanonicalFile().toURL());
465 }
466 }
467 }
468 else
469 {
470 list.add(patchURL);
471 }
472 }
473
474 // Add the server configuration directory to be able to load config files as resources
475 list.add(config.getServerConfigURL());
476
477 // Not needed, ServerImpl will have the basics on its classpath from ServerLoader
478 // may want to bring this back at some point if we want to have reloadable core
479 // components...
480
481 // URL libraryURL = config.getLibraryURL();
482 // list.add(new URL(libraryURL, "jboss-spine.jar"));
483
484 log.debug("Boot url list: " + list);
485
486 // Create loaders for each URL
487 UnifiedClassLoader loader = null;
488 for (Iterator iter = list.iterator(); iter.hasNext();)
489 {
490 URL url = (URL)iter.next();
491 if (debug)
492 {
493 log.debug("Creating loader for URL: " + url);
494 }
495
496 // This is a boot URL, so key it on itself.
497 Object[] args = {url, Boolean.TRUE};
498 String[] sig = {"java.net.URL", "boolean"};
499 loader = (UnifiedClassLoader) server.invoke(DEFAULT_LOADER_NAME, "newClassLoader", args, sig);
500 }
501 return loader;
502 }
503
504 /**
505 * Shutdown the Server instance and run shutdown hooks.
506 *
507 * <p>If the exit on shutdown flag is true, then {@link #exit}
508 * is called, else only the shutdown hook is run.
509 *
510 * @jmx:managed-operation
511 *
512 * @throws IllegalStateException No started.
513 */
514 public void shutdown() throws IllegalStateException
515 {
516 if (!started)
517 throw new IllegalStateException("not started");
518
519 final ServerImpl server = this;
520
521 log.info("Shutting down");
522
523 boolean exitOnShutdown = config.getExitOnShutdown();
524 boolean blockingShutdown = config.getBlockingShutdown();
525 if (log.isDebugEnabled())
526 {
527 log.debug("exitOnShutdown: " + exitOnShutdown);
528 log.debug("blockingShutdown: " + blockingShutdown);
529 }
530
531 lifeThread.interrupt();
532
533 if (exitOnShutdown)
534 {
535 server.exit(0);
536 }
537 else if (blockingShutdown)
538 {
539 shutdownHook.shutdown();
540 } // end of if ()
541 else
542 {
543 // start in new thread to give positive
544 // feedback to requesting client of success.
545 new Thread()
546 {
547 public void run()
548 {
549 // just run the hook, don't call System.exit, as we may
550 // be embeded in a vm that would not like that very much
551 shutdownHook.shutdown();
552 }
553 }.start();
554 }
555 }
556
557 /**
558 * Shutdown the server, the JVM and run shutdown hooks.
559 *
560 * @jmx:managed-operation
561 *
562 * @param exitcode The exit code returned to the operating system.
563 */
564 public void exit(final int exitcode)
565 {
566 // start in new thread so that we might have a chance to give positive
567 // feed back to requesting client of success.
568 new Thread()
569 {
570 public void run()
571 {
572 log.info("Shutting down the JVM now!");
573 Runtime.getRuntime().exit(exitcode);
574 }
575 }.start();
576 }
577
578 /**
579 * Shutdown the server, the JVM and run shutdown hooks. Exits with
580 * code 1.
581 *
582 * @jmx:managed-operation
583 */
584 public void exit()
585 {
586 exit(1);
587 }
588
589 /**
590 * Forcibly terminates the currently running Java virtual machine.
591 *
592 * @param exitcode The exit code returned to the operating system.
593 *
594 * @jmx:managed-operation
595 */
596 public void halt(final int exitcode)
597 {
598 // Send a notification that the startup is complete
599 Notification msg = new Notification(STOP_NOTIFICATION_TYPE, this, 2);
600 sendNotification(msg);
601
602 // start in new thread so that we might have a chance to give positive
603 // feed back to requesting client of success.
604 new Thread()
605 {
606 public void run()
607 {
608 System.err.println("Halting the system now!");
609 Runtime.getRuntime().halt(exitcode);
610 }
611 }.start();
612 }
613
614 /**
615 * Forcibly terminates the currently running Java virtual machine.
616 * Exits with code 1.
617 *
618 * @jmx:managed-operation
619 */
620 public void halt()
621 {
622 halt(1);
623 }
624
625
626 ///////////////////////////////////////////////////////////////////////////
627 // Runtime Access //
628 ///////////////////////////////////////////////////////////////////////////
629
630 /** A simple helper used to log the Runtime memory information. */
631 private void logMemoryUsage(final Runtime rt)
632 {
633 log.info("Total/free memory: " + rt.totalMemory() + "/" + rt.freeMemory());
634 }
635
636 /**
637 * Hint to the JVM to run the garbage collector.
638 *
639 * @jmx:managed-operation
640 */
641 public void runGarbageCollector()
642 {
643 Runtime rt = Runtime.getRuntime();
644
645 logMemoryUsage(rt);
646 rt.gc();
647 log.info("Hinted to the JVM to run garbage collection");
648 logMemoryUsage(rt);
649 }
650
651 /**
652 * Hint to the JVM to run any pending object finailizations.
653 *
654 * @jmx:managed-operation
655 */
656 public void runFinalization()
657 {
658 Runtime.getRuntime().runFinalization();
659 log.info("Hinted to the JVM to run any pending object finalizations");
660 }
661
662 /**
663 * Enable or disable tracing method calls at the Runtime level.
664 *
665 * @jmx:managed-operation
666 */
667 public void traceMethodCalls(final Boolean flag)
668 {
669 Runtime.getRuntime().traceMethodCalls(flag.booleanValue());
670 }
671
672 /**
673 * Enable or disable tracing instructions the Runtime level.
674 *
675 * @jmx:managed-operation
676 */
677 public void traceInstructions(final Boolean flag)
678 {
679 Runtime.getRuntime().traceInstructions(flag.booleanValue());
680 }
681
682
683 ///////////////////////////////////////////////////////////////////////////
684 // Server Information //
685 ///////////////////////////////////////////////////////////////////////////
686
687 /**
688 * @jmx:managed-attribute
689 */
690 public Date getStartDate()
691 {
692 return startDate;
693 }
694
695 /**
696 * @jmx:managed-attribute
697 */
698 public String getVersion()
699 {
700 return version.toString();
701 }
702
703 /**
704 * @jmx:managed-attribute
705 */
706 public String getVersionName()
707 {
708 return version.getName();
709 }
710
711 /**
712 * @jmx:managed-attribute
713 */
714 public String getBuildNumber()
715 {
716 return version.getBuildNumber();
717 }
718
719 /**
720 * @jmx:managed-attribute
721 */
722 public String getBuildID()
723 {
724 return version.getBuildID();
725 }
726
727 /**
728 * @jmx:managed-attribute
729 */
730 public String getBuildDate()
731 {
732 return version.getBuildDate();
733 }
734
735 // Begin NotificationBroadcaster interface methods
736 public void addNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback)
737 {
738 broadcasterSupport.addNotificationListener(listener, filter, handback);
739 }
740
741 public void removeNotificationListener(NotificationListener listener) throws ListenerNotFoundException
742 {
743 broadcasterSupport.removeNotificationListener(listener);
744 }
745
746 public MBeanNotificationInfo[] getNotificationInfo()
747 {
748 return broadcasterSupport.getNotificationInfo();
749 }
750
751 public void sendNotification(Notification notification)
752 {
753 broadcasterSupport.sendNotification(notification);
754 }
755 // End NotificationBroadcaster interface methods
756
757 ///////////////////////////////////////////////////////////////////////////
758 // Life Thread //
759 ///////////////////////////////////////////////////////////////////////////
760
761 private class LifeThread
762 extends Thread
763 {
764 Object lock = new Object();
765
766 public void run()
767 {
768 synchronized (lock)
769 {
770 try
771 {
772 lock.wait();
773 }
774 catch (InterruptedException ignore)
775 {
776 }
777 }
778 log.info("LifeThread.run exits!");
779 }
780 }
781
782 ///////////////////////////////////////////////////////////////////////////
783 // Shutdown Hook //
784 ///////////////////////////////////////////////////////////////////////////
785
786 private class ShutdownHook
787 extends Thread
788 {
789 /** The ServiceController which we will ask to shut things down with. */
790 private ObjectName controller;
791
792 /** The MainDeployer which we will ask to undeploy everything. */
793 private ObjectName mainDeployer;
794
795 private boolean forceHalt = true;
796
797 public ShutdownHook(final ObjectName controller, final ObjectName mainDeployer)
798 {
799 super("JBoss Shutdown Hook");
800
801 this.controller = controller;
802 this.mainDeployer = mainDeployer;
803
804 String value = System.getProperty("jboss.shutdown.forceHalt", null);
805 if (value != null) {
806 forceHalt = new Boolean(value).booleanValue();
807 }
808 }
809
810 public void run()
811 {
812 shutdown();
813
814 // later bitch
815 if (forceHalt) {
816 System.out.println("Halting VM");
817 Runtime.getRuntime().halt(0);
818 }
819 }
820
821 public void shutdown()
822 {
823 log.info("JBoss SHUTDOWN: Undeploying all packages");
824 shutdownDeployments();
825
826 log.info("Shutting down all services");
827 System.out.println("Shutting down");
828
829 // Make sure all services are down properly
830 shutdownServices();
831
832 // Make sure all mbeans are unregistered
833 removeMBeans();
834
835 log.debug("Deleting server tmp/deploy directory");
836 File tmp = config.getServerTempDir();
837 File tmpDeploy = new File(tmp, "deploy");
838 Files.delete(tmpDeploy);
839
840 log.info("Shutdown complete");
841 System.out.println("Shutdown complete");
842 }
843
844 protected void shutdownDeployments()
845 {
846 try
847 {
848 // get the deployed objects from ServiceController
849 server.invoke(mainDeployer,
850 "shutdown",
851 new Object[0],
852 new String[0]);
853 }
854 catch (Exception e)
855 {
856 Throwable t = JMXExceptionDecoder.decode(e);
857 log.error("Failed to shutdown deployer", t);
858 }
859 }
860
861 /**
862 * The <code>shutdownServices</code> method calls the one and only
863 * ServiceController to shut down all the mbeans registered with it.
864 */
865 protected void shutdownServices()
866 {
867 try
868 {
869 // get the deployed objects from ServiceController
870 server.invoke(controller,
871 "shutdown",
872 new Object[0],
873 new String[0]);
874 }
875 catch (Exception e)
876 {
877 Throwable t = JMXExceptionDecoder.decode(e);
878 log.error("Failed to shutdown services", t);
879 }
880 }
881
882 /**
883 * The <code>removeMBeans</code> method uses the mbean server to unregister
884 * all the mbeans registered here.
885 */
886 protected void removeMBeans()
887 {
888 try
889 {
890 server.unregisterMBean(ServiceControllerMBean.OBJECT_NAME);
891 server.unregisterMBean(ServerConfigImplMBean.OBJECT_NAME);
892 server.unregisterMBean(ServerImplMBean.OBJECT_NAME);
893 }
894 catch (Exception e)
895 {
896 Throwable t = JMXExceptionDecoder.decode(e);
897 log.error("Failed to unregister mbeans", t);
898 }
899 try
900 {
901 MBeanServerFactory.releaseMBeanServer(server);
902 }
903 catch (Exception e)
904 {
905 Throwable t = JMXExceptionDecoder.decode(e);
906 log.error("Failed to release mbean server", t);
907 }
908 }
909 }
910 }