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    import java.lang.reflect.Type;
010    
011    /**
012     * behaviour for all behaviours wishing to store
013     * their component in "awkward places" ( object references ) 
014     * @author Konstantin Pribluda
015     *
016     * @param <T>
017     */
018    @SuppressWarnings("serial")
019    public class Stored<T> extends AbstractBehavior<T> {
020    
021            protected final boolean delegateHasLifecylce;
022            protected boolean disposed;
023            protected final ObjectReference<T> instanceReference;
024    
025            protected boolean started;
026    
027            public Stored(ComponentAdapter<T> delegate, ObjectReference<T> reference) {
028                    super(delegate);
029                    instanceReference = reference;
030            this.disposed = false;
031            this.started = false;
032            this.delegateHasLifecylce = delegate instanceof LifecycleStrategy
033            && ((LifecycleStrategy) delegate).hasLifecycle(delegate.getComponentImplementation());
034    
035            }
036    
037            public boolean componentHasLifecycle() {
038                return delegateHasLifecylce;
039            }
040    
041            /**
042             * Disposes the cached component instance
043             * {@inheritDoc}
044             */
045            public void dispose(PicoContainer container) {
046                if ( delegateHasLifecylce ){
047                    if (disposed) throw new IllegalStateException("Already disposed");
048                    dispose(getComponentInstance(container, NOTHING.class));
049                    disposed = true;
050                }
051            }
052    
053            /**
054             * Retrieves the stored reference.  May be null if it has
055             * never been set, or possibly if the reference has been
056             * flushed.
057             * @return the stored object or null.
058             */
059            public T getStoredObject() {
060                    return instanceReference.get();
061            }
062            
063            /**
064             * Flushes the cache.
065             * If the component instance is started is will stop and dispose it before
066             * flushing the cache.
067             */
068            public void flush() {
069                Object instance = instanceReference.get();
070                if ( instance != null && delegateHasLifecylce && started ) {
071                    stop(instance);
072                    dispose(instance);
073                }
074                instanceReference.set(null);
075            }
076    
077            public T getComponentInstance(PicoContainer container, Type into) throws PicoCompositionException {
078                T instance = instanceReference.get();
079                if (instance == null) {
080                    instance = super.getComponentInstance(container, into);
081                    instanceReference.set(instance);
082                }
083                return instance;
084            }
085    
086        public String getDescriptor() {
087            return "Stored";
088        }
089    
090        /**
091             * Starts the cached component instance
092             * {@inheritDoc}
093             */
094            public void start(PicoContainer container) {
095                if ( delegateHasLifecylce ){
096                    if (disposed) throw new IllegalStateException("Already disposed");
097                    if (started) throw new IllegalStateException("Already started");
098                    start(getComponentInstance(container, NOTHING.class));
099                    started = true;
100                }
101            }
102    
103            /**
104             * Stops the cached component instance
105             * {@inheritDoc}
106             */
107            public void stop(PicoContainer container) {
108                if ( delegateHasLifecylce ){
109                    if (disposed) throw new IllegalStateException("Already disposed");
110                    if (!started) throw new IllegalStateException("Not started");
111                    stop(getComponentInstance(container, NOTHING.class));
112                    started = false;
113                }
114            }
115    
116    }