/* * JBoss, Home of Professional Open Source. * Copyright 2008, Red Hat Middleware LLC, and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jboss.system.server.jmx; import java.io.File; import java.lang.reflect.Method; import java.net.URL; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Properties; import java.util.Map; import javax.management.ListenerNotFoundException; import javax.management.MBeanNotificationInfo; import javax.management.MBeanServer; import javax.management.MBeanServerFactory; import javax.management.NotificationEmitter; import javax.management.NotificationFilter; import javax.management.NotificationListener; import javax.management.ObjectInstance; import javax.management.ObjectName; import org.jboss.bootstrap.spi.ServerConfig; import org.jboss.bootstrap.spi.ServerProcess; import org.jboss.classloader.spi.ClassLoaderSystem; import org.jboss.classloading.spi.RealClassLoader; import org.jboss.classloading.spi.metadata.ExportAll; import org.jboss.classloading.spi.vfs.policy.VFSClassLoaderPolicy; import org.jboss.kernel.Kernel; import org.jboss.mx.loading.RepositoryClassLoader; import org.jboss.mx.server.ServerConstants; import org.jboss.mx.util.JMXExceptionDecoder; import org.jboss.mx.util.MBeanServerLocator; import org.jboss.mx.util.ObjectNameFactory; import org.jboss.system.ServiceController; import org.jboss.system.ServiceControllerMBean; import org.jboss.system.server.ServerConfigImpl; import org.jboss.system.server.ServerConfigImplMBean; import org.jboss.system.server.ServerImplMBean; import org.jboss.system.server.ServerInfoMBean; import org.jboss.util.JBossObject; import org.jboss.util.file.FileSuffixFilter; import org.jboss.virtual.VFS; import org.jboss.virtual.VirtualFile; /** * A pojo that creates a legacy jmx kernel ala the jboss-4.x server bootstrap. * This is used to support the SARDeployer and mbean integration. * * @author Scott.Stark@jboss.org * @version $Revision: 85945 $ */ public class JMXKernel extends JBossObject implements JMXKernelMBean, NotificationEmitter { private final static ObjectName DEFAULT_LOADER_NAME = ObjectNameFactory.create(ServerConstants.DEFAULT_LOADER_NAME); /** The JMX MBeanServer which will serve as our communication bus. */ private MBeanServer mbeanServer; private ServerProcess serverImpl; private ServiceController controller; private ServerConfig serverConfig; private ServerConfigImplMBean serverConfigMBean; private ServerInfoMBean serverInfo; /** The kernel */ private Kernel kernel; /** The serverImpl cast as an emitter */ private NotificationEmitter notificationEmitter; /** The bootstrap UCL class loader ObjectName */ private ObjectName bootstrapUCLName; private boolean started; /** Whether to use the old classloader */ private boolean oldClassLoader; public ServerProcess getServerImpl() { return serverImpl; } public void setServerImpl(ServerProcess serverImpl) { this.serverImpl = serverImpl; this.notificationEmitter = (NotificationEmitter) serverImpl; } public ServiceControllerMBean getServiceController() { return this.controller; } public MBeanServer getMbeanServer() { return mbeanServer; } /** * Get the optional server configuration metadata * @return a possibly empty map of configuration metadata. */ @SuppressWarnings("unchecked") public Map<String, Object> getMetaData() { return Collections.emptyMap(); } public ServerInfoMBean getServerInfo() { return serverInfo; } /** * Initialize the Server instance. * * @param props The configuration properties for the server. * @param metadata configuration metadata for the server * * @throws IllegalStateException Already initialized. * @throws Exception Failed to initialize. */ public void init(Properties props, Map<String, Object> metaData) throws IllegalStateException, Exception { return; //NOOP for now } public void setServerInfo(ServerInfoMBean serverInfo) { this.serverInfo = serverInfo; } /** * Set the kernel. * * @param kernel the kernel. */ public void setKernel(Kernel kernel) { this.kernel = kernel; } public boolean isOldClassLoader() { return oldClassLoader; } public void setOldClassLoader(boolean oldClassLoader) { this.oldClassLoader = oldClassLoader; } public void start() throws Exception { ClassLoader tcl = Thread.currentThread().getContextClassLoader(); // Create the MBeanServer String builder = System.getProperty(ServerConstants.MBEAN_SERVER_BUILDER_CLASS_PROPERTY, ServerConstants.DEFAULT_MBEAN_SERVER_BUILDER_CLASS); System.setProperty(ServerConstants.MBEAN_SERVER_BUILDER_CLASS_PROPERTY, builder); serverConfig = serverImpl.getConfig(); serverConfigMBean = new ServerConfigImpl(serverConfig); // Check if we'll use the platform MBeanServer or instantiate our own if (serverConfig.getPlatformMBeanServer() == true) { // jdk1.5+ ClassLoader cl = Thread.currentThread().getContextClassLoader(); Class clazz = cl.loadClass("java.lang.management.ManagementFactory"); Class[] sig = null; Method method = clazz.getMethod("getPlatformMBeanServer", sig); Object[] args = null; mbeanServer = (MBeanServer) method.invoke(null, args); // Tell the MBeanServerLocator to point to this mbeanServer MBeanServerLocator.setJBoss(mbeanServer); /* If the LazyMBeanServer was used, we need to reset to the jboss MBeanServer to use our implementation for the jboss services. */ mbeanServer = LazyMBeanServer.resetToJBossServer(mbeanServer); } else { // Create our own MBeanServer mbeanServer = MBeanServerFactory.createMBeanServer("jboss"); } log.debug("Created MBeanServer: " + mbeanServer); // Register mbeanServer components mbeanServer.registerMBean(this, ServerImplMBean.OBJECT_NAME); mbeanServer.registerMBean(serverConfigMBean, ServerConfigImplMBean.OBJECT_NAME); // Initialize spine boot libraries ClassLoader cl; if (oldClassLoader) cl = initBootLibrariesOld(); else cl = initBootLibraries(); // Set ServiceClassLoader as classloader for the construction of // the basic system try { Thread.currentThread().setContextClassLoader(cl); // General Purpose Architecture information -- mbeanServer.registerMBean(serverInfo, new ObjectName("jboss.system:type=ServerInfo")); // Service Controller controller = new ServiceController(); controller.setKernel(kernel); controller.setMBeanServer(mbeanServer); mbeanServer.registerMBean(controller, new ObjectName("jboss.system:service=ServiceController")); log.info("Legacy JMX core initialized"); started = true; } finally { Thread.currentThread().setContextClassLoader(tcl); } } /** * Stop the mbeans * * @throws IllegalStateException - if not started. */ public void stop() throws IllegalStateException { if (log.isTraceEnabled()) log.trace("stop caller:", new Throwable("Here")); if (!started) throw new IllegalStateException("Server not started"); log.debug("Shutting down all services"); shutdownServices(); // Make sure all mbeans are unregistered removeMBeans(); } /////////////////////////////////////////////////////////////////////////// // NotificationEmitter // /////////////////////////////////////////////////////////////////////////// public void addNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) { notificationEmitter.addNotificationListener(listener, filter, handback); } public void removeNotificationListener(NotificationListener listener) throws ListenerNotFoundException { notificationEmitter.removeNotificationListener(listener); } public void removeNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) throws ListenerNotFoundException { notificationEmitter.removeNotificationListener(listener, filter, handback); } public MBeanNotificationInfo[] getNotificationInfo() { return notificationEmitter.getNotificationInfo(); } // ServerImplMBean delegation public void init(Properties props) throws Exception { serverImpl.init(props); } public void exit() { serverImpl.exit(); } public void exit(int exitcode) { serverImpl.exit(exitcode); } public ServerConfig getConfig() { return serverConfig; } public String getBuildDate() { return serverImpl.getBuildDate(); } public String getBuildID() { return serverImpl.getBuildID(); } public String getBuildJVM() { return serverImpl.getBuildJVM(); } public String getBuildNumber() { return serverImpl.getBuildNumber(); } public String getBuildOS() { return serverImpl.getBuildOS(); } public Date getStartDate() { return serverImpl.getStartDate(); } public String getVersion() { return serverImpl.getVersion(); } public String getVersionName() { return serverImpl.getVersionName(); } public String getVersionNumber() { return serverImpl.getVersionNumber(); } public void halt() { serverImpl.halt(); } public void halt(int exitcode) { serverImpl.halt(exitcode); } public boolean isInShutdown() { return serverImpl.isInShutdown(); } public boolean isStarted() { return serverImpl.isStarted(); } public void runFinalization() { } public void runGarbageCollector() { } public void traceInstructions(Boolean flag) { } public void traceMethodCalls(Boolean flag) { } public void shutdown() { if (log.isTraceEnabled()) log.trace("Shutdown caller:", new Throwable("Here")); serverImpl.shutdown(); } /** * The <code>shutdownServices</code> method calls the one and only * ServiceController to shut down all the mbeans registered with it. */ protected void shutdownServices() { try { // get the deployed objects from ServiceController controller.shutdown(); } catch (Exception e) { Throwable t = JMXExceptionDecoder.decode(e); log.error("Failed to shutdown services", t); } } /** * The <code>removeMBeans</code> method uses the mbean mbeanServer to unregister * all the mbeans registered here. */ protected void removeMBeans() { try { mbeanServer.unregisterMBean(ServerConfigImplMBean.OBJECT_NAME); } catch (Exception e) { Throwable t = JMXExceptionDecoder.decode(e); log.error("Failed to unregister mbeans", t); } try { mbeanServer.unregisterMBean(ServerImplMBean.OBJECT_NAME); } catch (Exception e) { Throwable t = JMXExceptionDecoder.decode(e); log.error("Failed to unregister mbeans", t); } try { MBeanServer registeredServer = mbeanServer; if (serverConfig.getPlatformMBeanServer() == true) registeredServer = LazyMBeanServer.getRegisteredMBeanServer(mbeanServer); MBeanServerFactory.releaseMBeanServer(registeredServer); } catch (Exception e) { Throwable t = JMXExceptionDecoder.decode(e); log.error("Failed to release mbean mbeanServer", t); } } /** * Initialize the boot libraries using the old classloader * * @return the classloader * @throws Exception for any error */ private List<URL> getBootURLs() throws Exception { // Build the list of URL for the spine to boot List<URL> list = new ArrayList<URL>(); // Add the patch URL. If the url protocol is file, then // add the contents of the directory it points to URL patchURL = serverConfig.getPatchURL(); if (patchURL != null) { if (patchURL.getProtocol().equals("file")) { File dir = new File(patchURL.getFile()); if (dir.exists()) { // Add the local file patch directory list.add(dir.toURL()); // Add the contents of the directory too File[] jars = dir.listFiles(new FileSuffixFilter(new String[] { ".jar", ".zip" }, true)); for (int j = 0; jars != null && j < jars.length; j++) { list.add(jars[j].getCanonicalFile().toURL()); } } } else { list.add(patchURL); } } // Add the mbeanServer configuration directory to be able to load serverConfig files as resources list.add(serverConfig.getServerConfigURL()); log.debug("Boot url list: " + list); return list; } /** * Initialize the boot libraries using the old classloader * * @return the classloader * @throws Exception for any error */ private ClassLoader initBootLibrariesOld() throws Exception { List<URL> list = getBootURLs(); // Create loaders for each URL RepositoryClassLoader loader = null; for (URL url : list) { log.debug("Creating loader for URL: " + url); // This is a boot URL, so key it on itself. Object[] args = {url, Boolean.TRUE}; String[] sig = {"java.net.URL", "boolean"}; loader = (RepositoryClassLoader) mbeanServer.invoke(DEFAULT_LOADER_NAME, "newClassLoader", args, sig); } bootstrapUCLName = loader.getObjectName(); mbeanServer.registerMBean(loader, bootstrapUCLName); return loader; } /** * Initialize the boot libraries using the new classloader * * @return the classloader * @throws Exception for any error */ private ClassLoader initBootLibraries() throws Exception { ClassLoaderSystem system = ClassLoaderSystem.getInstance(); mbeanServer.registerMBean(system, new ObjectName("jboss.classloader:service=ClassLoaderSystem")); List<URL> list = getBootURLs(); VirtualFile[] files = new VirtualFile[list.size()]; for (int i = 0; i < list.size(); ++i) { URL url = list.get(i); files[i] = VFS.getRoot(url); } VFSClassLoaderPolicy policy = new VFSClassLoaderPolicy(files); policy.setExportAll(ExportAll.NON_EMPTY); policy.setImportAll(true); ClassLoader classLoader = system.registerClassLoaderPolicy(policy); if (classLoader instanceof RealClassLoader) bootstrapUCLName = ((RealClassLoader) classLoader).getObjectName(); return classLoader; } /** * Instantiate and register a service for the given classname into the MBean mbeanServer. * * @param classname the mbean class name * @param name the obejct name * @return the object name * @throws Exception for any error */ private ObjectName createMBean(final String classname, String name) throws Exception { ObjectName mbeanName = null; if( name != null ) mbeanName = new ObjectName(name); try { // See if there is an xmbean descriptor for the bootstrap mbean URL xmbeanDD = new URL("resource:xmdesc/"+classname+"-xmbean.xml"); Object resource = mbeanServer.instantiate(classname); // Create the XMBean Object[] args = {resource, xmbeanDD}; String[] sig = {Object.class.getName(), URL.class.getName()}; ObjectInstance instance = mbeanServer.createMBean("org.jboss.mx.modelmbean.XMBean", mbeanName, bootstrapUCLName, args, sig); mbeanName = instance.getObjectName(); log.debug("Created system XMBean: "+mbeanName); } catch(Exception e) { log.debug("Failed to create xmbean for: "+classname); mbeanName = mbeanServer.createMBean(classname, mbeanName).getObjectName(); log.debug("Created system MBean: " + mbeanName); } return mbeanName; } }