    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     * Original code by Mike Rimov                                               *
    009     *****************************************************************************/
    010    package org.picocontainer.gems.containers;
    011
    012    import java.util.ArrayList;
    013    import java.util.HashMap;
    014    import java.util.List;
    015    import java.util.Map;
    016    import java.util.Properties;
    017
    018    import org.picocontainer.ComponentAdapter;
    019    import org.picocontainer.ComponentFactory;
    020    import org.picocontainer.ComponentMonitor;
    021    import org.picocontainer.DefaultPicoContainer;
    022    import org.picocontainer.LifecycleStrategy;
    023    import org.picocontainer.MutablePicoContainer;
    024    import org.picocontainer.Parameter;
    025    import org.picocontainer.PicoCompositionException;
    026    import org.picocontainer.PicoContainer;
    027    import org.picocontainer.adapters.InstanceAdapter;
    028    import org.picocontainer.behaviors.Stored;
    029
    030    /**
    031     * Normal PicoContainers are meant to be created, started, stopped, disposed and
    032     * garbage collected. The goal of this container is to reduce the number of
    033     * registration calls (and therefore objects created) in areas where performance
    034     * is key (for example, this might be used in NanoContainer request containers).
    035     * <p>
    036     * It accomplishes its goal in two ways: <br/> (1) Once a container is disposed
    037     * of, start() may be called again, allowing for recycling of the container. (This is default
    038     * behavior with a picocontainer)
    039     * </p>
    040     * <p>
    041     * (2) All instance registrations will be unregistered when stop is called. (For example,
    042     * HttpServletRequest would be removed), and all component adapter instance values
    043     * are flushed.
    044     * </p>
    045     * <h4>Container Storage</h4>
    046     * <p>It is still up to the builder of this container to decide where to store its reference.  Since
    047     * it is reusable, it needs to be stored someplace that doesn't easily expire.  Probably the most
    048     * common storage location would be ThreadLocal storage.  HttpSession might be another valid
    049     * storage location.</p>
    050     * @author Michael Rimov
    051     */
    052    @SuppressWarnings("serial")
    053    public class ReusablePicoContainer extends DefaultPicoContainer {
    054
    055            private final List<ComponentAdapter<?>> instanceRegistrations = new ArrayList<ComponentAdapter<?>>();
    056
    057            private final Map<ComponentAdapter<?>, Stored<?>> storedReferences = new HashMap<ComponentAdapter<?>, Stored<?>>();
    058
    059            public ReusablePicoContainer() {
    060                    super();
    061            }
    062
    063            public ReusablePicoContainer(final ComponentFactory componentFactory,
    064                            final LifecycleStrategy lifecycleStrategy, final PicoContainer parent,
    065                            final ComponentMonitor componentMonitor) {
    066                    super(componentFactory, lifecycleStrategy, parent, componentMonitor);
    067            }
    068
    069            public ReusablePicoContainer(final ComponentFactory componentFactory,
    070                            final LifecycleStrategy lifecycleStrategy, final PicoContainer parent) {
    071                    super(componentFactory, lifecycleStrategy, parent);
    072            }
    073
    074            public ReusablePicoContainer(final ComponentFactory componentFactory,
    075                            final PicoContainer parent) {
    076                    super(componentFactory, parent);
    077            }
    078
    079            public ReusablePicoContainer(final ComponentFactory componentFactory) {
    080                    super(componentFactory);
    081            }
    082
    083            public ReusablePicoContainer(final ComponentMonitor monitor,
    084                            final LifecycleStrategy lifecycleStrategy, final PicoContainer parent) {
    085                    super(monitor, lifecycleStrategy, parent);
    086            }
    087
    088            public ReusablePicoContainer(final ComponentMonitor monitor, final PicoContainer parent) {
    089                    super(monitor, parent);
    090            }
    091
    092            public ReusablePicoContainer(final ComponentMonitor monitor) {
    093                    super(monitor);
    094            }
    095
    096            public ReusablePicoContainer(final LifecycleStrategy lifecycleStrategy,
    097                            final PicoContainer parent) {
    098                    super(lifecycleStrategy, parent);
    099            }
    100
    101            public ReusablePicoContainer(final PicoContainer parent) {
    102                    super(parent);
    103            }
    104
    105            @Override
    106            public MutablePicoContainer addComponent(final Object componentKey,
    107                            final Object componentImplementationOrInstance,
    108                            final Parameter... parameters) throws PicoCompositionException {
    109
    110                    if (componentKey == null) {
    111                            throw new NullPointerException("componentKey");
    112                    }
    113
    114                    if (componentImplementationOrInstance == null) {
    115                            throw new NullPointerException("componentImplementationOrInstance");
    116                    }
    117
    118                    super.addComponent(componentKey,
    119                                    componentImplementationOrInstance,
    120                                    parameters);
    121
    122                    if (! (componentImplementationOrInstance instanceof Class)) {
    123                            instanceRegistrations.add(super.getComponentAdapter(componentKey));
    124                    } else {
    125                            addStoredReference(componentKey);
    126                    }
    127
    128                    return this;
    129            }
    130
    131            @Override
    132            public  MutablePicoContainer addComponent(final Object implOrInstance)
    133                            throws PicoCompositionException {
    134                    if ((implOrInstance instanceof Class)) {
    135                            super.addComponent(implOrInstance);
    136                            addStoredReference(implOrInstance);
    137                            return this;
    138                    } else {
    139                            return this.addComponent(implOrInstance.getClass(), implOrInstance);
    140                    }
    141            }
    142
    143            /**
    144             * Precalculates all references to Stored behaviors.
    145             * @param key the object key.
    146             */
    147            private void addStoredReference(final Object key) {
    148                    ComponentAdapter<?> ca = this.getComponentAdapter(key);
    149                    Stored<?> stored =  ca.findAdapterOfType(Stored.class);
    150                if (stored != null) {
    151                    storedReferences.put(ca, stored);
    152                }
    153        }
    154
    155            @Override
    156            public synchronized void stop() {
    157                    super.stop();
    158
    159                    //Remove all instance registrations.
    160                    for (ComponentAdapter<?> eachAdapter : this.instanceRegistrations) {
    161                            this.removeComponent(eachAdapter.getComponentKey());
    162                    }
    163
    164                    instanceRegistrations.clear();
    165
    166                    //Flush all remaining objects.
    167                    for (Stored<?> eachStoredBehavior : this.storedReferences.values()) {
    168                            eachStoredBehavior.flush();
    169                    }
    170            }
    171
    172            @Override
    173        public MutablePicoContainer addAdapter(final ComponentAdapter<?> componentAdapter, final Properties properties) {
    174                    super.addAdapter(componentAdapter, properties);
    175                    if (componentAdapter.findAdapterOfType(InstanceAdapter.class) != null) {
    176                            this.instanceRegistrations.add(componentAdapter);
    177                    } else {
    178                            this.addStoredReference(componentAdapter.getComponentKey());
    179                    }
    180
    181                    return this;
    182        }
    183
    184            @Override
    185        public MutablePicoContainer addAdapter(final ComponentAdapter<?> componentAdapter) {
    186                    super.addAdapter(componentAdapter);
    187                    if (componentAdapter.findAdapterOfType(InstanceAdapter.class) != null) {
    188                            this.instanceRegistrations.add(componentAdapter);
    189                    } else {
    190                            this.addStoredReference(componentAdapter.getComponentKey());
    191                    }
    192
    193                    return this;
    194        }
    195
    196            private void removeLocalReferences(final ComponentAdapter<?> ca) {
    197                    this.storedReferences.remove(ca);
    198            }
    199
    200            @Override
    201        public <T> ComponentAdapter<T> removeComponent(final Object componentKey) {
    202                    ComponentAdapter<T> result =  super.removeComponent(componentKey);
    203                    if (result != null) {
    204                            removeLocalReferences(result);
    205                    }
    206
    207                    return result;
    208        }
    209
    210            @Override
    211        public <T> ComponentAdapter<T> removeComponentByInstance(final T componentInstance) {
    212                    ComponentAdapter<T> result =  super.removeComponentByInstance(componentInstance);
    213                    if (result != null) {
    214                            removeLocalReferences(result);
    215                    }
    216
    217                    return result;
    218        }
    219
    220        @Override
    221            public MutablePicoContainer makeChildContainer() {
    222            ReusablePicoContainer pc = new ReusablePicoContainer(componentFactory, lifecycleStrategy, this);
    223            addChildContainer(pc);
    224            return pc;
    225        }
    226
    227    }