org.picocontainer.behaviors.Stored Maven / Gradle / Ivy
The newest version!
/*****************************************************************************
* Copyright (C) PicoContainer Organization. All rights reserved. *
* ------------------------------------------------------------------------- *
* The software in this package is published under the terms of the BSD *
* style license a copy of which has been included with this distribution in *
* the LICENSE.txt file. *
* *
*****************************************************************************/
package org.picocontainer.behaviors;
import org.picocontainer.ComponentAdapter;
import org.picocontainer.LifecycleStrategy;
import org.picocontainer.ObjectReference;
import org.picocontainer.PicoCompositionException;
import org.picocontainer.PicoContainer;
import org.picocontainer.ComponentLifecycle;
import java.lang.reflect.Type;
import java.io.Serializable;
/*
* behaviour for all behaviours wishing to store
* their component in "awkward places" ( object references )
*
* @author Konstantin Pribluda
*/
@SuppressWarnings("serial")
public class Stored extends AbstractBehavior {
private final ObjectReference> instanceReference;
private final ComponentLifecycle lifecycleDelegate;
public Stored(ComponentAdapter delegate, ObjectReference> reference) {
super(delegate);
instanceReference = reference;
this.lifecycleDelegate = hasLifecycle(delegate)
? new RealComponentLifecycle() : new NoComponentLifecycle();
}
private void guardInstRef() {
if (instanceReference.get() == null) {
instanceReference.set(new Instance());
}
}
public boolean componentHasLifecycle() {
return lifecycleDelegate.componentHasLifecycle();
}
/**
* Disposes the cached component instance
* {@inheritDoc}
*/
public void dispose(PicoContainer container) {
lifecycleDelegate.dispose(container);
}
/**
* Retrieves the stored reference. May be null if it has
* never been set, or possibly if the reference has been
* flushed.
*
* @return the stored object or null.
*/
public T getStoredObject() {
guardInstRef();
return instanceReference.get().instance;
}
/**
* Flushes the cache.
* If the component instance is started is will stop and dispose it before
* flushing the cache.
*/
public void flush() {
Instance inst = instanceReference.get();
if (inst != null) {
Object instance = inst.instance;
if (instance != null && instanceReference.get().started) {
stop(instance);
dispose(instance);
}
instanceReference.set(null);
}
}
public T getComponentInstance(PicoContainer container, Type into) throws PicoCompositionException {
guardInstRef();
T instance = instanceReference.get().instance;
if (instance == null) {
instance = super.getComponentInstance(container, into);
instanceReference.get().instance = instance;
}
return instance;
}
public String getDescriptor() {
return "Stored" + getLifecycleDescriptor();
}
protected String getLifecycleDescriptor() {
return (lifecycleDelegate.componentHasLifecycle() ? "+Lifecycle" : "");
}
/**
* Starts the cached component instance
* {@inheritDoc}
*/
public void start(PicoContainer container) {
lifecycleDelegate.start(container);
}
/**
* Stops the cached component instance
* {@inheritDoc}
*/
public void stop(PicoContainer container) {
lifecycleDelegate.stop(container);
}
public boolean isStarted() {
return lifecycleDelegate.isStarted();
}
private class RealComponentLifecycle implements ComponentLifecycle, Serializable {
public void start(PicoContainer container) {
guardInstRef();
guardAlreadyDisposed();
guardStartState(true, "already started");
// Lazily make the component if applicable
Stored.this.start(getComponentInstance(container, NOTHING.class));
instanceReference.get().started = true;
}
public void stop(PicoContainer container) {
guardInstRef();
guardAlreadyDisposed();
guardNotInstantiated();
guardStartState(false, "not started");
Stored.this.stop(instanceReference.get().instance);
instanceReference.get().started = false;
}
public void dispose(PicoContainer container) {
guardInstRef();
Instance> instance = instanceReference.get();
if (instance.instance != null) {
guardAlreadyDisposed();
Stored.this.dispose(instance.instance);
instance.disposed = true;
}
}
private void guardNotInstantiated() {
if (instanceReference.get().instance == null)
throw new IllegalStateException("'" + getComponentKey() + "' not instantiated");
}
private void guardStartState(boolean unexpectedStartState, String message) {
if (instanceReference.get().started == unexpectedStartState)
throw new IllegalStateException("'" + getComponentKey() + "' " + message);
}
private void guardAlreadyDisposed() {
if (instanceReference.get().disposed)
throw new IllegalStateException("'" + getComponentKey() + "' already disposed");
}
public boolean componentHasLifecycle() {
return true;
}
public boolean isStarted() {
guardInstRef();
return instanceReference.get().started;
}
}
private static class NoComponentLifecycle implements ComponentLifecycle, Serializable {
public void start(PicoContainer container) {
}
public void stop(PicoContainer container) {
}
public void dispose(PicoContainer container) {
}
public boolean componentHasLifecycle() {
return false;
}
public boolean isStarted() {
return false;
}
}
private static boolean hasLifecycle(ComponentAdapter delegate) {
return delegate instanceof LifecycleStrategy
&& ((LifecycleStrategy) delegate).hasLifecycle(delegate.getComponentImplementation());
}
public static class Instance implements Serializable {
private T instance;
protected boolean started;
protected boolean disposed;
}
}