/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.servicemanager;
import java.util.Date;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.AttributeNotFoundException;
import javax.management.Descriptor;
import javax.management.DynamicMBean;
import javax.management.InvalidAttributeValueException;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.ReflectionException;
import javax.management.modelmbean.DescriptorSupport;
import javax.management.modelmbean.ModelMBeanAttributeInfo;
import javax.management.modelmbean.ModelMBeanInfoSupport;
import javax.management.modelmbean.ModelMBeanOperationInfo;
import org.dspace.kernel.CommonLifecycle;
import org.dspace.kernel.DSpaceKernel;
import org.dspace.kernel.DSpaceKernelManager;
import org.dspace.kernel.ServiceManager;
import org.dspace.servicemanager.config.DSpaceConfigurationService;
import org.dspace.services.ConfigurationService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This is the kernel implementation which starts up the core of DSpace,
* registers the mbean, and initializes the DSpace object.
* It also loads up the configuration. Sets a JRE shutdown hook.
* <p>
* Note that this does not start itself and calling the constuctor does
* not actually start it up either. It has to be explicitly started by
* calling the start method so something in the system needs to do that.
* If the bean is already started then calling start on it again has no
* effect.
* <p>
* The name of this instance can be specified if desired.
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public final class DSpaceKernelImpl implements DSpaceKernel, DynamicMBean, CommonLifecycle<DSpaceKernel> {
private static Logger log = LoggerFactory.getLogger(DSpaceKernelImpl.class);
/**
* Creates a DSpace Kernel, does not do any checks though.
* Do not call this; use {@link DSpaceKernelInit#getKernel(String)}.
*
* @param name the name for the kernel
*/
protected DSpaceKernelImpl(String name) {
this.mBeanName = DSpaceKernelManager.checkName(name);
}
private String mBeanName = MBEAN_NAME;
private boolean running = false;
private boolean destroyed = false;
private final Object lock = new Object();
private DSpaceKernel kernel = null;
private Thread shutdownHook;
protected void registerShutdownHook() {
if (this.shutdownHook == null) {
synchronized (lock) {
// No shutdown hook registered yet
this.shutdownHook = new Thread() {
public void run() {
doDestroy();
}
};
Runtime.getRuntime().addShutdownHook(this.shutdownHook);
}
}
}
private ConfigurationService configurationService;
public ConfigurationService getConfigurationService() {
return configurationService;
}
private ServiceManagerSystem serviceManagerSystem;
public ServiceManager getServiceManager() {
return serviceManagerSystem;
}
/* (non-Javadoc)
* @see org.dspace.kernel.DSpaceKernel#getMBeanName()
*/
public String getMBeanName() {
return mBeanName;
}
/* (non-Javadoc)
* @see org.dspace.kernel.DSpaceKernel#isRunning()
*/
public boolean isRunning() {
synchronized (lock) {
return running;
}
}
/* (non-Javadoc)
* @see org.dspace.kernel.CommonLifecycle#getManagedBean()
*/
public DSpaceKernel getManagedBean() {
synchronized (lock) {
return kernel;
}
}
/* (non-Javadoc)
* @see org.dspace.kernel.CommonLifecycle#start()
*/
public void start() {
start(null);
}
/**
* This starts up the entire core system. May be called more than
* once: subsequent calls return without effect.
*
* @param dspaceHome path to DSpace home directory
*/
public void start(String dspaceHome) {
if (running) {
//log.warn("Kernel ("+this+") is already started");
return;
}
synchronized (lock) {
lastLoadDate = new Date();
long startTime = System.currentTimeMillis();
// create the configuration service and get the configuration
DSpaceConfigurationService dsConfigService = new DSpaceConfigurationService(dspaceHome);
configurationService = dsConfigService;
// startup the service manager
serviceManagerSystem = new DSpaceServiceManager(dsConfigService);
serviceManagerSystem.startup();
// initialize the static
// DSpace.initialize(serviceManagerSystem);
loadTime = System.currentTimeMillis() - startTime;
kernel = this;
running = true;
// add in the shutdown hook
registerShutdownHook();
}
log.info("DSpace kernel startup completed in "+loadTime+" ms and registered as MBean: " + mBeanName);
}
/* (non-Javadoc)
* @see org.dspace.kernel.CommonLifecycle#stop()
*/
public void stop() {
if (! running) {
//log.warn("Kernel ("+this+") is already stopped");
return;
}
synchronized (lock) {
// DSpace.initialize(null); // clear out the static cover
// wipe all the variables to free everything up
running = false;
kernel = null;
if (serviceManagerSystem != null) {
serviceManagerSystem.shutdown();
}
serviceManagerSystem = null;
configurationService = null;
}
// log completion (logger may be gone at this point so we cannot really use it)
log.info("DSpace kernel shutdown completed and unregistered MBean: " + mBeanName);
}
/* (non-Javadoc)
* @see org.dspace.kernel.CommonLifecycle#destroy()
*/
public void destroy() {
if (this.destroyed) {
return;
}
synchronized (lock) {
// stop the kernel
try {
stop();
} catch (Exception e) {
// oh well
}
// If this was the default kernel, clear it
if (DSpaceKernelManager.getDefaultKernel() == this) {
DSpaceKernelManager.setDefaultKernel(null);
}
try {
// remove the mbean
DSpaceKernelManager.unregisterMBean(mBeanName);
} finally {
// trash the shutdown hook as we do not need it anymore
if (this.shutdownHook != null) {
try {
Runtime.getRuntime().removeShutdownHook(this.shutdownHook);
this.shutdownHook = null;
} catch (Exception e) {
// ok, keep going
}
}
}
this.destroyed = true;
}
}
/**
* Called from within the shutdown thread.
*/
protected void doDestroy() {
if (! this.destroyed) {
destroy();
}
}
@Override
protected void finalize() throws Throwable {
try {
doDestroy();
} catch (Exception e) {
log.error("WARN Failure attempting to cleanup the DSpace kernel: " + e.getMessage(), e);
}
super.finalize();
}
@Override
public String toString() {
return "DSpaceKernel:" + mBeanName + ":lastLoad=" + lastLoadDate + ":loadTime=" + loadTime + ":running=" + running + ":kernel=" + (kernel == null ? null : kernel.getClass().getName() +"@"+kernel.getClass().getClassLoader() + ":" + super.toString());
}
// MBEAN methods
private Date lastLoadDate;
/** Time that this kernel was started, as a java.util.Date. */
public Date getLastLoadDate() {
return new Date(lastLoadDate.getTime());
}
private long loadTime;
/** Time that this kernel was started, as seconds since the epoch. */
public long getLoadTime() {
return loadTime;
}
public Object invoke(String actionName, Object[] params, String[] signature)
throws MBeanException, ReflectionException {
return this;
}
public MBeanInfo getMBeanInfo() {
Descriptor lastLoadDateDesc = new DescriptorSupport(new String[] {"name=LastLoadDate",
"descriptorType=attribute", "default=0", "displayName=Last Load Date",
"getMethod=getLastLoadDate"});
Descriptor lastLoadTimeDesc = new DescriptorSupport(new String[] {"name=LastLoadTime",
"descriptorType=attribute", "default=0", "displayName=Last Load Time",
"getMethod=getLoadTime" });
ModelMBeanAttributeInfo[] mmbai = new ModelMBeanAttributeInfo[2];
mmbai[0] = new ModelMBeanAttributeInfo("LastLoadDate", "java.util.Date", "Last Load Date",
true, false, false, lastLoadDateDesc);
mmbai[1] = new ModelMBeanAttributeInfo("LastLoadTime", "java.lang.Long", "Last Load Time",
true, false, false, lastLoadTimeDesc);
ModelMBeanOperationInfo[] mmboi = new ModelMBeanOperationInfo[7];
mmboi[0] = new ModelMBeanOperationInfo("start", "Start DSpace Kernel", null, "void",
ModelMBeanOperationInfo.ACTION);
mmboi[1] = new ModelMBeanOperationInfo("stop", "Stop DSpace Kernel", null, "void",
ModelMBeanOperationInfo.ACTION);
mmboi[2] = new ModelMBeanOperationInfo("getManagedBean", "Get the Current Kernel", null,
DSpaceKernel.class.getName(), ModelMBeanOperationInfo.INFO);
return new ModelMBeanInfoSupport(this.getClass().getName(), "DSpace Kernel", mmbai, null, mmboi, null);
}
public Object getAttribute(String attribute) throws AttributeNotFoundException, MBeanException, ReflectionException {
if ("LastLoadDate".equals(attribute)) {
return getLastLoadDate();
} else if ("LastLoadTime".equals(attribute)) {
return getLoadTime();
}
throw new AttributeNotFoundException("invalid attribute: " + attribute);
}
public AttributeList getAttributes(String[] attributes) {
// TODO Auto-generated method stub
return null;
}
public void setAttribute(Attribute attribute) throws AttributeNotFoundException,
InvalidAttributeValueException, MBeanException, ReflectionException {
throw new InvalidAttributeValueException("Cannot set attribute: " + attribute);
}
public AttributeList setAttributes(AttributeList attributes) {
// TODO Auto-generated method stub
return null;
}
}