/** * 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 java.util.List; 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.dspace.services.KernelStartupCallbackService; import org.dspace.services.factory.DSpaceServicesFactory; 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; List<KernelStartupCallbackService> callbackServices = DSpaceServicesFactory.getInstance().getServiceManager().getServicesByType(KernelStartupCallbackService.class); for (KernelStartupCallbackService callbackService : callbackServices) { callbackService.executeCallback(); } // 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. * @return date object **/ public Date getLastLoadDate() { return new Date(lastLoadDate.getTime()); } private long loadTime; /** * Time that this kernel was started, as seconds since the epoch. * @return seconds since epoch (as a long) **/ 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; } }