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 }