package org.jboss.system;
import java.util.Date;
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.apache.log4j.NDC;
import org.jboss.logging.Logger;
import org.jboss.mx.util.JBossNotificationBroadcasterSupport;
import EDU.oswego.cs.dl.util.concurrent.SynchronizedLong;
public class ServiceMBeanSupport
extends JBossNotificationBroadcasterSupport
implements ServiceMBean, MBeanRegistration
{
public static final String[] SERVICE_CONTROLLER_SIG = new String[] { ObjectName.class.getName() };
protected Logger log;
protected MBeanServer server;
protected ObjectName serviceName;
private int state = UNREGISTERED;
private SynchronizedLong sequenceNumber = new SynchronizedLong(0);
private boolean isJBossInternalLifecycleExposed = false;
public ServiceMBeanSupport()
{
this.log = Logger.getLogger(getClass().getName());
log.trace("Constructing");
}
public ServiceMBeanSupport(final Class type)
{
this(type.getName());
}
public ServiceMBeanSupport(final String category)
{
this(Logger.getLogger(category));
}
public ServiceMBeanSupport(final Logger log)
{
this.log = log;
log.trace("Constructing");
}
public String getName()
{
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;
}
public void create() throws Exception
{
if (serviceName != null && isJBossInternalLifecycleExposed)
server.invoke(ServiceController.OBJECT_NAME, "create", new Object[] { serviceName }, SERVICE_CONTROLLER_SIG);
else
jbossInternalCreate();
}
public void start() throws Exception
{
if (serviceName != null && isJBossInternalLifecycleExposed)
server.invoke(ServiceController.OBJECT_NAME, "start", new Object[] { serviceName }, SERVICE_CONTROLLER_SIG);
else
jbossInternalStart();
}
public void stop()
{
try
{
if (serviceName != null && isJBossInternalLifecycleExposed)
server.invoke(ServiceController.OBJECT_NAME, "stop", new Object[] { serviceName }, SERVICE_CONTROLLER_SIG);
else
jbossInternalStop();
}
catch (Throwable t)
{
log.error("Error in stop " + jbossInternalDescription(), t);
}
}
public void destroy()
{
try
{
if (serviceName != null && isJBossInternalLifecycleExposed)
server.invoke(ServiceController.OBJECT_NAME, "destroy", new Object[] { serviceName }, SERVICE_CONTROLLER_SIG);
else
jbossInternalDestroy();
}
catch (Throwable t)
{
log.error("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
{
NDC.push(getName());
log.debug("Creating " + jbossInternalDescription());
try
{
createService();
state = CREATED;
}
catch (Exception e)
{
log.error("Initialization failed " + jbossInternalDescription(), e);
throw e;
}
finally
{
NDC.pop();
NDC.remove();
}
log.debug("Created " + jbossInternalDescription());
}
public void jbossInternalStart() throws Exception
{
if (state == STARTING || state == STARTED)
return;
state = STARTING;
long now = System.currentTimeMillis();
AttributeChangeNotification stateChange = new AttributeChangeNotification(this,
getNextNotificationSequenceNumber(), now, getName()+" starting",
"State", "java.lang.Integer",
new Integer(STOPPED), new Integer(STARTING));
sendNotification(stateChange);
log.debug("Starting " + jbossInternalDescription());
NDC.push(getName());
try
{
startService();
}
catch (Exception e)
{
state = FAILED;
now = System.currentTimeMillis();
stateChange = new AttributeChangeNotification(this,
getNextNotificationSequenceNumber(), now, getName()+" failed",
"State", "java.lang.Integer",
new Integer(STARTING), new Integer(FAILED));
stateChange.setUserData(e);
sendNotification(stateChange);
log.error("Starting failed " + jbossInternalDescription(), e);
throw e;
}
finally
{
NDC.pop();
NDC.remove();
}
state = STARTED;
now = System.currentTimeMillis();
stateChange = new AttributeChangeNotification(this,
getNextNotificationSequenceNumber(), now, getName()+" started",
"State", "java.lang.Integer",
new Integer(STARTING), new Integer(STARTED));
sendNotification(stateChange);
log.debug("Started " + jbossInternalDescription());
}
public void jbossInternalStop()
{
if (state != STARTED)
return;
state = STOPPING;
long now = System.currentTimeMillis();
AttributeChangeNotification stateChange = new AttributeChangeNotification(this,
getNextNotificationSequenceNumber(), now, getName()+" stopping",
"State", "java.lang.Integer",
new Integer(STARTED), new Integer(STOPPING));
sendNotification(stateChange);
log.debug("Stopping " + jbossInternalDescription());
NDC.push(getName());
try
{
stopService();
}
catch (Throwable e)
{
state = FAILED;
now = System.currentTimeMillis();
stateChange = new AttributeChangeNotification(this,
getNextNotificationSequenceNumber(), now, getName()+" failed",
"State", "java.lang.Integer",
new Integer(STOPPING), new Integer(FAILED));
stateChange.setUserData(e);
sendNotification(stateChange);
log.error("Stopping failed " + jbossInternalDescription(), e);
return;
}
finally
{
NDC.pop();
NDC.remove();
}
state = STOPPED;
now = System.currentTimeMillis();
stateChange = new AttributeChangeNotification(this,
getNextNotificationSequenceNumber(), now, getName()+" stopped",
"State", "java.lang.Integer",
new Integer(STOPPING), new Integer(STOPPED));
sendNotification(stateChange);
log.debug("Stopped " + jbossInternalDescription());
}
public void jbossInternalDestroy()
{
if( state == DESTROYED )
return;
if (state != STOPPED)
stop();
log.debug("Destroying " + jbossInternalDescription());
NDC.push(getName());
try
{
destroyService();
}
catch (Throwable t)
{
log.error("Destroying failed " + jbossInternalDescription(), t);
}
finally
{
NDC.pop();
NDC.remove();
}
state = DESTROYED;
log.debug("Destroyed " + jbossInternalDescription());
}
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;
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;
}
protected long getNextNotificationSequenceNumber()
{
return sequenceNumber.increment();
}
protected ObjectName getObjectName(MBeanServer server, ObjectName name)
throws MalformedObjectNameException
{
return name;
}
protected void createService() throws Exception {}
protected void startService() throws Exception {}
protected void stopService() throws Exception {}
protected void destroyService() throws Exception {}
}