001    package org.picocontainer.behaviors;
002    
003    import org.picocontainer.ComponentAdapter;
004    import org.picocontainer.LifecycleStrategy;
005    import org.picocontainer.ObjectReference;
006    import org.picocontainer.PicoCompositionException;
007    import org.picocontainer.PicoContainer;
008    
009    /**
010     * abstract base behaviour for all behaviours wishing to store
011     * their component in "awkward places" ( object references ) 
012     * @author Konstantin Pribluda
013     *
014     * @param <T>
015     */
016    public abstract class Stored<T> extends AbstractBehavior<T> {
017    
018                
019            protected final boolean delegateHasLifecylce;
020            protected boolean disposed;
021            protected final ObjectReference<T> instanceReference;
022    
023            protected boolean started;
024    
025            public Stored(ComponentAdapter<T> delegate, ObjectReference<T> reference) {
026                    super(delegate);
027                    instanceReference = reference;
028            this.disposed = false;
029            this.started = false;
030            this.delegateHasLifecylce = delegate instanceof LifecycleStrategy
031            && ((LifecycleStrategy) delegate).hasLifecycle(delegate.getComponentImplementation());
032    
033            }
034    
035            public boolean componentHasLifecycle() {
036                return delegateHasLifecylce;
037            }
038    
039            /**
040             * Disposes the cached component instance
041             * {@inheritDoc}
042             */
043            public void dispose(PicoContainer container) {
044                if ( delegateHasLifecylce ){
045                    if (disposed) throw new IllegalStateException("Already disposed");
046                    dispose(getComponentInstance(container));
047                    disposed = true;
048                }
049            }
050    
051            /**
052             * Flushes the cache.
053             * If the component instance is started is will stop and dispose it before
054             * flushing the cache.
055             */
056            public void flush() {
057                Object instance = instanceReference.get();
058                if ( instance != null && delegateHasLifecylce && started ) {
059                    stop(instance);
060                    dispose(instance);
061                }
062                instanceReference.set(null);
063            }
064    
065            public T getComponentInstance(PicoContainer container) throws PicoCompositionException {
066                T instance = instanceReference.get();
067                if (instance == null) {
068                    instance = super.getComponentInstance(container);
069                    instanceReference.set(instance);
070                }
071                return (T)instance;
072            }
073    
074            /**
075             * Starts the cached component instance
076             * {@inheritDoc}
077             */
078            public void start(PicoContainer container) {
079                if ( delegateHasLifecylce ){
080                    if (disposed) throw new IllegalStateException("Already disposed");
081                    if (started) throw new IllegalStateException("Already started");
082                    start(getComponentInstance(container));
083                    started = true;
084                }
085            }
086    
087            /**
088             * Stops the cached component instance
089             * {@inheritDoc}
090             */
091            public void stop(PicoContainer container) {
092                if ( delegateHasLifecylce ){
093                    if (disposed) throw new IllegalStateException("Already disposed");
094                    if (!started) throw new IllegalStateException("Not started");
095                    stop(getComponentInstance(container));
096                    started = false;
097                }
098            }
099    
100    }