/*
* Copyright (c) 2012-2014, Parallel Universe Software Co. All rights reserved.
*
* This program and the accompanying materials are dual-licensed under
* either the terms of the Eclipse Public License v1.0 as published by
* the Eclipse Foundation
*
* or (per the licensee's choosing)
*
* under the terms of the GNU Lesser General Public License version 3.0
* as published by the Free Software Foundation.
*/
package co.paralleluniverse.common.spring;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedResource;
/**
* An object instance initialized by the Spring container.
*
* Subclasses with methods annotated with {@code org.springframework.jmx.export.annotation.ManagedAttribute} must be public for the property to
* be properly exposed in the MBean.
*/
@ManagedResource
public abstract class Component implements InitializingBean, DisposableBean {
private static final Logger LOG = LoggerFactory.getLogger(Component.class);
private volatile boolean initialized;
private final String name;
/**
* Constructs a component with a given name.
*
* @param name The component's name.
*/
protected Component(String name) {
this.initialized = false;
this.name = name;
}
@ManagedAttribute(currencyTimeLimit = -1, description = "The component's class name")
public String getType() {
return getClass().getName();
}
@ManagedAttribute(currencyTimeLimit = -1, description = "The component's name")
public String getName() {
return name;
}
@Override
public final void afterPropertiesSet() throws Exception {
LOG.info("Initializing component {}", name);
try {
init();
LOG.info("Component {} initialized", name);
} catch (Exception e) {
LOG.error("Exception while initializing " + name, e);
throw e;
}
}
@Override
public final void destroy() throws Exception {
LOG.info("Destroying component {}", name);
try {
shutdown();
LOG.info("Component {} destroyed", name);
} catch (Exception e) {
LOG.warn("Exception while destroying " + name, e);
throw e;
}
}
@ManagedAttribute(currencyTimeLimit = 0, description = "Whether or not this component has been fully initialized")
public boolean isInitialized() {
return initialized;
}
protected void assertDuringInitialization() {
if (initialized)
throw new IllegalStateException("Method must only be called during bean initialization");
}
protected void assertInitialized() {
if (!initialized)
throw new IllegalStateException("Method must only be called after bean initialization");
}
/**
* Called after bean properties have been set. If a derived class overrides this methid, it <b>must</b> call {@code super.init()}
* <b>before</b> doing anything else in the method.
*/
protected void init() throws Exception {
assertDuringInitialization();
}
/**
* Called after bean properties have been set, and init() called. If a derived class overrides this method, it
* <b>must</b> call {@code super.postInit()} <b>after</b> doing anything else in the method.
*/
protected void postInit() throws Exception {
assertDuringInitialization();
this.initialized = true;
}
/**
* Called when the container is destroyed.
*/
protected void shutdown() {
}
@Override
public String toString() {
return name + '(' + this.getClass().getName() + ')';
}
}