package org.easyrec.plugin.support;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.easyrec.plugin.Plugin;
import org.easyrec.plugin.exception.PluginException;
import org.easyrec.plugin.model.PluginId;
import org.easyrec.plugin.model.Version;
import org.easyrec.plugin.util.ObserverRegistry;
import org.easyrec.plugin.util.ObserverRegistryImpl;
import java.net.URI;
public abstract class PluginSupport implements Plugin {
private String displayName;
private PluginId id;
private LifecyclePhase lifecyclePhase = LifecyclePhase.NOT_INSTALLED;
protected final Log logger = LogFactory.getLog(getClass());
private ObserverRegistryImpl<Plugin> pluginObserverRegistry = new ObserverRegistryImpl<Plugin>(this);
protected PluginSupport(String displayName, URI id, Version version) {
this.displayName = displayName;
this.id = new PluginId(id, version);
}
/**
* Implementations place code here that needs to be executed one time before a
* plugin is able to be used (i.e set up db tables). Any Exception is wrapped
* in a PluginException and thrown on.
*
* @throws Exception
*/
protected void doInstall() throws Exception {}
/**
* Implementations place code here that needs to be executed to properly
* uninstall a plugin (i.e. drop db tables).
* Any Exception is wrapped in a PluginException and thrown on.
*
* @throws Exception
*/
protected void doUninstall() throws Exception {}
/**
* Implementations place their initialization code here. Any Exception is
* wrapped in a PluginException and thrown on.
*
* @throws Exception
*/
protected void doInitialize() throws Exception {}
/**
* Implementations place their cleanup code here. Any Exception is wrapped
* in a PluginException and thrown on.
*
* @throws Exception
*/
protected void doCleanup() throws Exception {}
public String getDisplayName() {
return displayName;
}
public PluginId getId() {
return id;
}
public final void cleanup() {
// valid call states: INITIALIZED, INIT_FAILED, CLEANUP_FAILED
if (!this.lifecyclePhase.isCleanupAllowed()) {
throw new IllegalStateException("Cleanup not allowed from plugin state " + this.lifecyclePhase);
}
try {
changeLifecyclePhaseTo(LifecyclePhase.CLEANING_UP);
//switch classloader to the generator's own classloader so its exclusive classes are visible
ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
ClassLoader generatorClassLoader = this.getClass().getClassLoader();
Thread.currentThread().setContextClassLoader(generatorClassLoader);
doCleanup();
Thread.currentThread().setContextClassLoader(currentClassLoader);
changeLifecyclePhaseTo(LifecyclePhase.INSTALLED);
} catch (Throwable t) {
changeLifecyclePhaseTo(LifecyclePhase.CLEANUP_FAILED);
throw new PluginException(this, "Caught error during doCleanup", t);
}
}
public final void initialize() {
// valid call states: INSTALLED, INIT_FAILED, CLEANUP_FAILED
if (!this.lifecyclePhase.isInitializeAllowed()) {
throw new IllegalStateException("Initialize not allowed from plugin state " + this.lifecyclePhase);
}
try {
changeLifecyclePhaseTo(LifecyclePhase.INITIALIZING);
//switch classloader to the generator's own classloader so its exclusive classes are visible
ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
ClassLoader generatorClassLoader = this.getClass().getClassLoader();
Thread.currentThread().setContextClassLoader(generatorClassLoader);
doInitialize();
Thread.currentThread().setContextClassLoader(currentClassLoader);
this.lifecyclePhase = LifecyclePhase.INITIALIZED;
} catch (Throwable t) {
changeLifecyclePhaseTo(LifecyclePhase.INIT_FAILED);
throw new PluginException(this, "Caught error during doInitialize", t);
}
}
public final void install(boolean executeInstall) throws PluginException {
// valid call states: NOT_INSTALLED, INSTALL_FAILED, UNINSTALL_FAILED
if (!this.lifecyclePhase.isInstallAllowed()) {
throw new IllegalStateException("Install not allowed from plugin state " + this.lifecyclePhase);
}
try {
changeLifecyclePhaseTo(LifecyclePhase.INSTALLING);
if (executeInstall) {
//switch classloader to the generator's own classloader so its exclusive classes are visible
ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
ClassLoader generatorClassLoader = this.getClass().getClassLoader();
Thread.currentThread().setContextClassLoader(generatorClassLoader);
doInstall();
Thread.currentThread().setContextClassLoader(currentClassLoader);
}
this.lifecyclePhase = LifecyclePhase.INSTALLED;
} catch (Throwable t) {
changeLifecyclePhaseTo(LifecyclePhase.INSTALL_FAILED);
throw new PluginException(this, "Caught error during doInstall", t);
}
}
public final void uninstall() throws PluginException {
// valid call states: INSTALLED, INSTALL_FAILED, UNINSTALL_FAILED
if (!this.lifecyclePhase.isUninstallAllowed()) {
throw new IllegalStateException("Uninstall not allowed from plugin state " + this.lifecyclePhase);
}
try {
changeLifecyclePhaseTo(LifecyclePhase.UNINSTALLING);
//switch classloader to the generator's own classloader so its exclusive classes are visible
ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
ClassLoader generatorClassLoader = this.getClass().getClassLoader();
Thread.currentThread().setContextClassLoader(generatorClassLoader);
doUninstall();
Thread.currentThread().setContextClassLoader(currentClassLoader);
this.lifecyclePhase = LifecyclePhase.NOT_INSTALLED;
} catch (Throwable t) {
changeLifecyclePhaseTo(LifecyclePhase.UNINSTALL_FAILED);
throw new PluginException(this, "Caught error during doUninstall", t);
}
}
public ObserverRegistry<Plugin> getPluginObserverRegistry() {
return pluginObserverRegistry;
}
public LifecyclePhase getLifecyclePhase() {
return this.lifecyclePhase;
}
private void changeLifecyclePhaseTo(LifecyclePhase newPhase) {
this.lifecyclePhase = newPhase;
this.pluginObserverRegistry.notifyObservers();
}
}