    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     *****************************************************************************/
    009    package org.picocontainer.behaviors;
    010
    011    import org.picocontainer.ComponentAdapter;
    012    import org.picocontainer.LifecycleStrategy;
    013    import org.picocontainer.ObjectReference;
    014    import org.picocontainer.PicoCompositionException;
    015    import org.picocontainer.PicoContainer;
    016    import org.picocontainer.ComponentLifecycle;
    017
    018    import java.lang.reflect.Type;
    019    import java.io.Serializable;
    020
    021    /**
    022     * behaviour for all behaviours wishing to store
    023     * their component in "awkward places" ( object references )
    024     *
    025     * @author Konstantin Pribluda
    026     * @param <T>
    027     */
    028    @SuppressWarnings("serial")
    029    public class Stored<T> extends AbstractBehavior<T> {
    030
    031        private final ObjectReference<Instance<T>> instanceReference;
    032        private final ComponentLifecycle lifecycleDelegate;
    033
    034        public Stored(ComponentAdapter<T> delegate, ObjectReference<Instance<T>> reference) {
    035            super(delegate);
    036            instanceReference = reference;
    037            this.lifecycleDelegate = hasLifecycle(delegate)
    038                    ? new RealComponentLifecycle<T>() : new NoComponentLifecycle<T>();
    039        }
    040
    041        private void guardInstRef() {
    042            if (instanceReference.get() == null) {
    043                instanceReference.set(new Instance());
    044            }
    045        }
    046
    047        public boolean componentHasLifecycle() {
    048            return lifecycleDelegate.componentHasLifecycle();
    049        }
    050
    051        /**
    052         * Disposes the cached component instance
    053         * {@inheritDoc}
    054         */
    055        public void dispose(PicoContainer container) {
    056            lifecycleDelegate.dispose(container);
    057        }
    058
    059        /**
    060         * Retrieves the stored reference.  May be null if it has
    061         * never been set, or possibly if the reference has been
    062         * flushed.
    063         *
    064         * @return the stored object or null.
    065         */
    066        public T getStoredObject() {
    067            guardInstRef();
    068            return instanceReference.get().instance;
    069        }
    070
    071        /**
    072         * Flushes the cache.
    073         * If the component instance is started is will stop and dispose it before
    074         * flushing the cache.
    075         */
    076        public void flush() {
    077            Instance<T> inst = instanceReference.get();
    078            if (inst != null) {
    079                Object instance = inst.instance;
    080                if (instance != null && instanceReference.get().started) {
    081                    stop(instance);
    082                    dispose(instance);
    083                }
    084                instanceReference.set(null);
    085            }
    086        }
    087
    088        public T getComponentInstance(PicoContainer container, Type into) throws PicoCompositionException {
    089            guardInstRef();
    090            T instance = instanceReference.get().instance;
    091            if (instance == null) {
    092                instance = super.getComponentInstance(container, into);
    093                instanceReference.get().instance = instance;
    094            }
    095            return instance;
    096        }
    097
    098        public String getDescriptor() {
    099            return "Stored" + getLifecycleDescriptor();
    100        }
    101
    102        protected String getLifecycleDescriptor() {
    103            return (lifecycleDelegate.componentHasLifecycle() ? "+Lifecycle" : "");
    104        }
    105
    106        /**
    107         * Starts the cached component instance
    108         * {@inheritDoc}
    109         */
    110        public void start(PicoContainer container) {
    111            lifecycleDelegate.start(container);
    112        }
    113
    114        /**
    115         * Stops the cached component instance
    116         * {@inheritDoc}
    117         */
    118        public void stop(PicoContainer container) {
    119            lifecycleDelegate.stop(container);
    120
    121        }
    122
    123        public boolean isStarted() {
    124            return lifecycleDelegate.isStarted();
    125        }
    126
    127        private class RealComponentLifecycle<T> implements ComponentLifecycle<T>, Serializable {
    128
    129            public void start(PicoContainer container) {
    130                guardInstRef();
    131                guardAlreadyDisposed();
    132                guardStartState(true, "already started");
    133                // Lazily make the component if applicable
    134                Stored.this.start(getComponentInstance(container, NOTHING.class));
    135                instanceReference.get().started = true;
    136            }
    137
    138            public void stop(PicoContainer container) {
    139                guardInstRef();
    140                guardAlreadyDisposed();
    141                guardNotInstantiated();
    142                guardStartState(false, "not started");
    143                Stored.this.stop(instanceReference.get().instance);
    144                instanceReference.get().started = false;
    145
    146            }
    147
    148            public void dispose(PicoContainer container) {
    149                guardInstRef();
    150                guardNotInstantiated();
    151                guardAlreadyDisposed();
    152                Stored.this.dispose(instanceReference.get().instance);
    153                instanceReference.get().disposed = true;
    154            }
    155
    156
    157            private void guardNotInstantiated() {
    158                if (instanceReference.get().instance == null)
    159                    throw new IllegalStateException("'" + getComponentKey() + "' not instantiated");
    160            }
    161
    162            private void guardStartState(boolean unexpectedStartState, String message) {
    163                if (instanceReference.get().started == unexpectedStartState)
    164                    throw new IllegalStateException("'" + getComponentKey() + "' " + message);
    165            }
    166
    167            private void guardAlreadyDisposed() {
    168                if (instanceReference.get().disposed)
    169                    throw new IllegalStateException("'" + getComponentKey() + "' already disposed");
    170            }
    171
    172            public boolean componentHasLifecycle() {
    173                return true;
    174            }
    175
    176            public boolean isStarted() {
    177                guardInstRef();
    178                return instanceReference.get().started;
    179            }
    180        }
    181
    182        private static class NoComponentLifecycle<T> implements ComponentLifecycle<T>, Serializable {
    183            public void start(PicoContainer container) {
    184            }
    185
    186            public void stop(PicoContainer container) {
    187            }
    188
    189            public void dispose(PicoContainer container) {
    190            }
    191
    192            public boolean componentHasLifecycle() {
    193                return false;
    194            }
    195
    196            public boolean isStarted() {
    197                return false;
    198            }
    199        }
    200
    201        private static boolean hasLifecycle(ComponentAdapter delegate) {
    202            return delegate instanceof LifecycleStrategy
    203                    && ((LifecycleStrategy) delegate).hasLifecycle(delegate.getComponentImplementation());
    204        }
    205
    206        public static class Instance<T> implements Serializable {
    207            private T instance;
    208            protected boolean started;
    209            protected boolean disposed;
    210        }
    211
    212
    213
    214    }