001    /*****************************************************************************
002     * Copyright (c) PicoContainer Organization. All rights reserved.            *
003     * ------------------------------------------------------------------------- *
004     * The software in this package is published under the terms of the BSD      *
005     * style license a copy of which has been included with this distribution in *
006     * the LICENSE.txt file.                                                     *
007     *                                                                           *
008     * Idea by Rachel Davies, Original code by Aslak Hellesoy and Paul Hammant   *
009     *****************************************************************************/
010    
011    package org.picocontainer.defaults;
012    
013    import org.picocontainer.ComponentAdapter;
014    import org.picocontainer.LifecycleManager;
015    import org.picocontainer.PicoContainer;
016    import org.picocontainer.PicoInitializationException;
017    import org.picocontainer.PicoIntrospectionException;
018    
019    /**
020     * <p>
021     * {@link ComponentAdapter} implementation that caches the component instance.
022     * </p>
023     * <p>
024     * This adapter supports components with a lifecycle, as it is a {@link LifecycleManager lifecycle manager} 
025     * which will apply the delegate's {@link LifecycleStrategy lifecycle strategy} to the cached component instance.
026     * The lifecycle state is maintained so that the component instance behaves in the expected way:
027     * it can't be started if already started, it can't be started or stopped if disposed, it can't
028     * be stopped if not started, it can't be disposed if already disposed.
029     * </p>
030     *   
031     * @author Mauro Talevi
032     * @version $Revision: 2827 $
033     */
034    public class CachingComponentAdapter extends DecoratingComponentAdapter implements LifecycleManager {
035    
036        private ObjectReference instanceReference;
037        private boolean disposed;
038        private boolean started;
039        private boolean delegateHasLifecylce;
040    
041        public CachingComponentAdapter(ComponentAdapter delegate) {
042            this(delegate, new SimpleReference());
043        }
044    
045        public CachingComponentAdapter(ComponentAdapter delegate, ObjectReference instanceReference) {
046            super(delegate);
047            this.instanceReference = instanceReference;
048            this.disposed = false;
049            this.started = false;
050            this.delegateHasLifecylce = delegate instanceof LifecycleStrategy
051                    && ((LifecycleStrategy) delegate).hasLifecycle(delegate.getComponentImplementation());
052        }
053    
054        public Object getComponentInstance(PicoContainer container)
055                throws PicoInitializationException, PicoIntrospectionException, AssignabilityRegistrationException, NotConcreteRegistrationException {
056            Object instance = instanceReference.get();
057            if (instance == null) {
058                instance = super.getComponentInstance(container);
059                instanceReference.set(instance);
060            }
061            return instance;
062        }
063    
064        /**
065         * Flushes the cache.
066         * If the component instance is started is will stop and dispose it before
067         * flushing the cache.
068         */
069        public void flush() {
070            Object instance = instanceReference.get();
071            if ( instance != null && delegateHasLifecylce && started ) {
072                stop(instance);
073                dispose(instance);
074            }
075            instanceReference.set(null);
076        }
077    
078        /**
079         * Starts the cached component instance
080         * {@inheritDoc}
081         */
082        public void start(PicoContainer container) {
083            if ( delegateHasLifecylce ){
084                if (disposed) throw new IllegalStateException("Already disposed");
085                if (started) throw new IllegalStateException("Already started");
086                start(getComponentInstance(container));
087                started = true;
088            }
089        }
090    
091        /**
092         * Stops the cached component instance
093         * {@inheritDoc}
094         */
095        public void stop(PicoContainer container) {
096            if ( delegateHasLifecylce ){
097                if (disposed) throw new IllegalStateException("Already disposed");
098                if (!started) throw new IllegalStateException("Not started");
099                stop(getComponentInstance(container));
100                started = false;
101            }
102        }
103    
104        /**
105         * Disposes the cached component instance
106         * {@inheritDoc}
107         */
108        public void dispose(PicoContainer container) {
109            if ( delegateHasLifecylce ){
110                if (disposed) throw new IllegalStateException("Already disposed");
111                dispose(getComponentInstance(container));
112                disposed = true;
113            }
114        }
115    
116        public boolean hasLifecycle() {
117            return delegateHasLifecylce;
118        }
119        
120    }