All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jboss.system.ServiceMBeanSupport Maven / Gradle / Ivy

The newest version!
/*
 * 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;

import javax.management.AttributeChangeNotification;
import javax.management.MBeanInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanRegistration;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;

import org.jboss.beans.metadata.api.annotations.Create;
import org.jboss.beans.metadata.api.annotations.Destroy;
import org.jboss.beans.metadata.api.annotations.Start;
import org.jboss.beans.metadata.api.annotations.Stop;
import org.jboss.dependency.spi.Controller;
import org.jboss.dependency.spi.ControllerState;
import org.jboss.kernel.spi.dependency.KernelControllerContext;
import org.jboss.kernel.spi.dependency.KernelControllerContextAware;
import org.jboss.logging.Logger;
import org.jboss.mx.util.JBossNotificationBroadcasterSupport;

/**
 * An abstract base class JBoss services can subclass to implement a
 * service that conforms to the ServiceMBean interface. Subclasses must
 * override {@link #getName} method and should override 
 * {@link #startService}, and {@link #stopService} as approriate.
 *
 * @see ServiceMBean
 * 
 * @author Rickard Öberg
 * @author [email protected]
 * @author Andreas Schaefer
 * @author Jason Dillon
 * @version $Revision: 84175 $
 */
public class ServiceMBeanSupport
   extends JBossNotificationBroadcasterSupport
   implements ServiceMBean, MBeanRegistration, KernelControllerContextAware
{
   /** The signature for service controller operations */
   public static final String[] SERVICE_CONTROLLER_SIG = new String[] { ObjectName.class.getName() };
   
   /**
    * The instance logger for the service.  Not using a class logger
    * because we want to dynamically obtain the logger name from
    * concreate sub-classes.
    */
   protected Logger log;
   
   /** The MBeanServer which we have been register with. */
   protected MBeanServer server;

   /** The object name which we are registsred under. */
   protected ObjectName serviceName;

   /** The current state this service is in. */
   private int state = UNREGISTERED;

   /** For backwards compatibility */
   private boolean isJBossInternalLifecycleExposed = false;

   /** The controller context */
   private KernelControllerContext controllerContext;
   
   /**
    * Construct a ServiceMBeanSupport.
    *
    * 

Sets up logging. */ public ServiceMBeanSupport() { // can not call this(Class) because we need to call getClass() this.log = Logger.getLogger(getClass().getName()); log.trace("Constructing"); } /** * Construct a ServiceMBeanSupport. * *

Sets up logging. * * @param type The class type to determine category name from. */ @SuppressWarnings("unchecked") public ServiceMBeanSupport(final Class type) { this(type.getName()); } /** * Construct a ServiceMBeanSupport. * *

Sets up logging. * * @param category The logger category name. */ public ServiceMBeanSupport(final String category) { this(Logger.getLogger(category)); } /** * Construct a ServiceMBeanSupport. * * @param log The logger to use. */ public ServiceMBeanSupport(final Logger log) { this.log = log; log.trace("Constructing"); } public void setKernelControllerContext(KernelControllerContext controllerContext) throws Exception { this.controllerContext = controllerContext; } public void unsetKernelControllerContext(KernelControllerContext controllerContext) throws Exception { this.controllerContext = null; } /** * Use the short class name as the default for the service name. * * @return a description of the mbean */ public String getName() { // TODO: Check if this gets called often, if so cache this or remove if not used // use the logger so we can better be used as a delegate instead of sub-class return org.jboss.util.Classes.stripPackageName(log.getName()); } public ObjectName getServiceName() { return serviceName; } public MBeanServer getServer() { return server; } public int getState() { return state; } public String getStateString() { return states[state]; } public Logger getLog() { return log; } /////////////////////////////////////////////////////////////////////////// // State Mutators // /////////////////////////////////////////////////////////////////////////// @Create public void pojoCreate() throws Exception { jbossInternalCreate(); } @Start public void pojoStart() throws Exception { jbossInternalStart(); } @Stop public void pojoStop() throws Exception { jbossInternalStop(); } @Destroy public void pojoDestroy() throws Exception { jbossInternalDestroy(); } protected void pojoChange(ControllerState state) { Controller controller = controllerContext.getController(); try { controller.change(controllerContext, state); } catch (RuntimeException e) { throw e; } catch (Error e) { throw e; } catch (Throwable t) { throw new RuntimeException("Error changing state of " + controllerContext.getName() + " to " + state.getStateString(), t); } } public void create() throws Exception { if (controllerContext != null) pojoChange(ControllerState.CREATE); else if (serviceName != null && isJBossInternalLifecycleExposed) server.invoke(ServiceController.OBJECT_NAME, "create", new Object[] { serviceName }, SERVICE_CONTROLLER_SIG); else jbossInternalCreate(); } public void start() throws Exception { if (controllerContext != null) pojoChange(ControllerState.START); else if (serviceName != null && isJBossInternalLifecycleExposed) server.invoke(ServiceController.OBJECT_NAME, "start", new Object[] { serviceName }, SERVICE_CONTROLLER_SIG); else jbossInternalStart(); } public void stop() { try { if (controllerContext != null) pojoChange(ControllerState.CREATE); else if (serviceName != null && isJBossInternalLifecycleExposed) server.invoke(ServiceController.OBJECT_NAME, "stop", new Object[] { serviceName }, SERVICE_CONTROLLER_SIG); else jbossInternalStop(); } catch (Throwable t) { log.warn("Error in stop " + jbossInternalDescription(), t); } } public void destroy() { try { if (controllerContext != null) pojoChange(ControllerState.CONFIGURED); else if (serviceName != null && isJBossInternalLifecycleExposed) server.invoke(ServiceController.OBJECT_NAME, "destroy", new Object[] { serviceName }, SERVICE_CONTROLLER_SIG); else jbossInternalDestroy(); } catch (Throwable t) { log.warn("Error in destroy " + jbossInternalDescription(), t); } } protected String jbossInternalDescription() { if (serviceName != null) return serviceName.toString(); else return getName(); } public void jbossInternalLifecycle(String method) throws Exception { if (method == null) throw new IllegalArgumentException("Null method name"); if (method.equals("create")) jbossInternalCreate(); else if (method.equals("start")) jbossInternalStart(); else if (method.equals("stop")) jbossInternalStop(); else if (method.equals("destroy")) jbossInternalDestroy(); else throw new IllegalArgumentException("Unknown lifecyle method " + method); } protected void jbossInternalCreate() throws Exception { if (state == CREATED || state == STARTING || state == STARTED || state == STOPPING || state == STOPPED) { log.debug("Ignoring create call; current state is " + getStateString()); return; } log.debug("Creating " + jbossInternalDescription()); try { createService(); state = CREATED; } catch (Exception e) { log.debug("Initialization failed " + jbossInternalDescription(), e); throw e; } log.debug("Created " + jbossInternalDescription()); } protected void jbossInternalStart() throws Exception { if (state == STARTING || state == STARTED || state == STOPPING) { log.debug("Ignoring start call; current state is " + getStateString()); return; } if (state != CREATED && state != STOPPED && state != FAILED) { log.debug("Start requested before create, calling create now"); create(); } state = STARTING; sendStateChangeNotification(STOPPED, STARTING, getName() + " starting", null); log.debug("Starting " + jbossInternalDescription()); try { startService(); } catch (Exception e) { state = FAILED; sendStateChangeNotification(STARTING, FAILED, getName() + " failed", e); log.debug("Starting failed " + jbossInternalDescription(), e); throw e; } state = STARTED; sendStateChangeNotification(STARTING, STARTED, getName() + " started", null); log.debug("Started " + jbossInternalDescription()); } protected void jbossInternalStop() { if (state != STARTED) { log.debug("Ignoring stop call; current state is " + getStateString()); return; } state = STOPPING; sendStateChangeNotification(STARTED, STOPPING, getName() + " stopping", null); log.debug("Stopping " + jbossInternalDescription()); try { stopService(); } catch (Throwable e) { state = FAILED; sendStateChangeNotification(STOPPING, FAILED, getName() + " failed", e); log.warn("Stopping failed " + jbossInternalDescription(), e); return; } state = STOPPED; sendStateChangeNotification(STOPPING, STOPPED, getName() + " stopped", null); log.debug("Stopped " + jbossInternalDescription()); } protected void jbossInternalDestroy() { if (state == DESTROYED) { log.debug("Ignoring destroy call; current state is " + getStateString()); return; } if (state == STARTED) { log.debug("Destroy requested before stop, calling stop now"); stop(); } log.debug("Destroying " + jbossInternalDescription()); try { destroyService(); } catch (Throwable t) { log.warn("Destroying failed " + jbossInternalDescription(), t); } state = DESTROYED; log.debug("Destroyed " + jbossInternalDescription()); } /////////////////////////////////////////////////////////////////////////// // JMX Hooks // /////////////////////////////////////////////////////////////////////////// /** * Callback method of {@link MBeanRegistration} * before the MBean is registered at the JMX Agent. * *

* Attention: Always call this method when you overwrite it in a subclass * because it saves the Object Name of the MBean. * * @param server Reference to the JMX Agent this MBean is registered on * @param name Name specified by the creator of the MBean. Note that you can * overwrite it when the given ObjectName is null otherwise the * change is discarded (maybe a bug in JMX-RI). * @return the ObjectName * @throws Exception for any error */ public ObjectName preRegister(MBeanServer server, ObjectName name) throws Exception { this.server = server; serviceName = getObjectName(server, name); return serviceName; } public void postRegister(Boolean registrationDone) { if (!registrationDone.booleanValue()) { log.info( "Registration is not done -> stop" ); stop(); } else { state = REGISTERED; // This is for backwards compatibility - see whether jbossInternalLifecycle is exposed try { MBeanInfo info = server.getMBeanInfo(serviceName); MBeanOperationInfo[] ops = info.getOperations(); for (int i = 0; i < ops.length; ++i) { if (ops[i] != null && ServiceController.JBOSS_INTERNAL_LIFECYCLE.equals(ops[i].getName())) { isJBossInternalLifecycleExposed = true; break; } } } catch (Throwable t) { log.warn("Unexcepted error accessing MBeanInfo for " + serviceName, t); } } } public void preDeregister() throws Exception { } public void postDeregister() { server = null; serviceName = null; state = UNREGISTERED; } /** * The getNextNotificationSequenceNumber method returns * the next sequence number for use in notifications. * * @return a long value */ protected long getNextNotificationSequenceNumber() { return nextNotificationSequenceNumber(); } /////////////////////////////////////////////////////////////////////////// // Concrete Service Overrides // /////////////////////////////////////////////////////////////////////////// /** * Sub-classes should override this method if they only need to set their * object name during MBean pre-registration. * * @param server the mbeanserver * @param name the suggested name, maybe null * @return the object name * @throws MalformedObjectNameException for a bad object name */ protected ObjectName getObjectName(MBeanServer server, ObjectName name) throws MalformedObjectNameException { return name; } /** * Sub-classes should override this method to provide * custum 'create' logic. * *

This method is empty, and is provided for convenience * when concrete service classes do not need to perform * anything specific for this state change. * * @throws Exception for any error */ protected void createService() throws Exception {} /** * Sub-classes should override this method to provide * custum 'start' logic. * *

This method is empty, and is provided for convenience * when concrete service classes do not need to perform * anything specific for this state change. * * @throws Exception for any error */ protected void startService() throws Exception {} /** * Sub-classes should override this method to provide * custum 'stop' logic. * *

This method is empty, and is provided for convenience * when concrete service classes do not need to perform * anything specific for this state change. * * @throws Exception for any error */ protected void stopService() throws Exception {} /** * Sub-classes should override this method to provide * custum 'destroy' logic. * *

This method is empty, and is provided for convenience * when concrete service classes do not need to perform * anything specific for this state change. * * @throws Exception for any error */ protected void destroyService() throws Exception {} // Private ------------------------------------------------------- /** * Helper for sending out state change notifications */ private void sendStateChangeNotification(int oldState, int newState, String msg, Throwable t) { long now = System.currentTimeMillis(); AttributeChangeNotification stateChangeNotification = new AttributeChangeNotification( this, getNextNotificationSequenceNumber(), now, msg, "State", "java.lang.Integer", new Integer(oldState), new Integer(newState) ); stateChangeNotification.setUserData(t); sendNotification(stateChangeNotification); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy