package net.sourceforge.javautil.container.impl;
import java.util.HashMap;
import java.util.Map;
import net.sourceforge.javautil.common.classloader.ClassLoaderResource;
import net.sourceforge.javautil.common.shutdown.Shutdown;
import net.sourceforge.javautil.container.IContainer;
import net.sourceforge.javautil.lifecycle.ILifecycle;
import net.sourceforge.javautil.lifecycle.ILifecycle.PhaseType;
import net.sourceforge.javautil.lifecycle.LifecycleException;
import net.sourceforge.javautil.lifecycle.annotation.Phase;
import net.sourceforge.javautil.lifecycle.impl.ChildLifecycle;
import net.sourceforge.javautil.lifecycle.impl.LifecycleAbstract;
import net.sourceforge.javautil.lifecycle.impl.LifecyclePojo;
import net.sourceforge.javautil.lifecycle.impl.ParentLifecycle;
/**
* The base for most {@link IContainer} implementations.
*
* @author elponderador
* @author $Author$
* @version $Id$
*/
public abstract class ContainerAbstract<L extends ILifecycle<?>> implements IContainer {
protected final String name;
protected final Map<IContainer, BoundLifecycle> bindings = new HashMap<IContainer, BoundLifecycle>();
private L lifecycle;
public ContainerAbstract(String name) {
this.name = name;
}
public String getName() { return this.name; }
public final void start() { this.getLifecycleInternal().start(); }
public final void stop() { this.getLifecycleInternal().stop(); }
public L getLifecycle() { return this.getLifecycleInternal(); }
@Override public synchronized void bind(IContainer childContainer, boolean autoStartChild) {
switch (this.getLifecycle().getCurrentPhase()) {
case DESTROY:
throw new LifecycleException("Cannot bind child container after destroy", childContainer.getLifecycle());
default:
if (this.bindings.containsKey(childContainer))
throw new IllegalArgumentException("Child container already bound");
ParentLifecycle parent = new ParentLifecycle(childContainer.getLifecycle(), autoStartChild);
ChildLifecycle child = new ChildLifecycle(getLifecycle());
this.bindings.put(childContainer, new BoundLifecycle(parent, child));
getLifecycle().addListener(parent);
childContainer.getLifecycle().addListener(child);
if (this.isStarted() && !childContainer.isStarted()) childContainer.start();
}
}
@Override public synchronized void unbind(IContainer childContainer) {
if (this.bindings.containsKey(childContainer)) {
BoundLifecycle bound = this.bindings.get(childContainer);
getLifecycle().removeListener(bound.parent);
childContainer.getLifecycle().removeListener(bound.child);
this.bindings.remove(childContainer);
}
}
public boolean isStarted() {
return this.getLifecycleInternal().getCurrentPhase() == PhaseType.START;
}
public boolean isStopped() {
return this.getLifecycleInternal().getCurrentPhase().ordinal() >= PhaseType.STOP.ordinal();
}
public void shutdown() {
switch (this.getLifecycleInternal().getCurrentPhase()) {
case START:
this.getLifecycleInternal().stop();
case CREATE: case STOP:
this.getLifecycleInternal().destroy();
default:
// Ignore other phases
}
}
/**
* @return The lazily-initialized life-cycle
*/
protected L getLifecycleInternal () {
if (this.lifecycle == null) {
synchronized (this) {
if (this.lifecycle == null) {
this.lifecycle = this.createLifecycle();
}
}
}
return this.lifecycle;
}
/**
* @return The implementation specific life cycle for this container
*/
protected abstract L createLifecycle ();
/**
* A composite of information about bound {@link ILifecycle}'s.
*
* @author elponderador
* @author $Author$
* @version $Id$
*/
protected class BoundLifecycle {
protected final ParentLifecycle parent;
protected final ChildLifecycle child;
public BoundLifecycle(ParentLifecycle parent, ChildLifecycle child) {
this.parent = parent;
this.child = child;
}
}
}