KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > picocontainer > defaults > DefaultPicoContainer


1 /*****************************************************************************
2  * Copyright (C) PicoContainer Organization. All rights reserved. *
3  * ------------------------------------------------------------------------- *
4  * The software in this package is published under the terms of the BSD *
5  * style license a copy of which has been included with this distribution in *
6  * the LICENSE.txt file. *
7  * *
8  * Original code by *
9  *****************************************************************************/

10 package org.picocontainer.defaults;
11
12 import org.picocontainer.ComponentAdapter;
13 import org.picocontainer.LifecycleManager;
14 import org.picocontainer.MutablePicoContainer;
15 import org.picocontainer.Parameter;
16 import org.picocontainer.PicoContainer;
17 import org.picocontainer.PicoException;
18 import org.picocontainer.PicoRegistrationException;
19 import org.picocontainer.PicoVerificationException;
20 import org.picocontainer.PicoVisitor;
21 import org.picocontainer.Startable;
22 import org.picocontainer.Disposable;
23 import org.picocontainer.alternatives.ImmutablePicoContainer;
24
25 import java.io.Serializable JavaDoc;
26 import java.util.ArrayList JavaDoc;
27 import java.util.Collection JavaDoc;
28 import java.util.Collections JavaDoc;
29 import java.util.HashMap JavaDoc;
30 import java.util.HashSet JavaDoc;
31 import java.util.Iterator JavaDoc;
32 import java.util.List JavaDoc;
33 import java.util.Map JavaDoc;
34
35 /**
36  * <p/>
37  * The Standard {@link PicoContainer}/{@link MutablePicoContainer} implementation.
38  * Constructing a container c with a parent p container will cause c to look up components
39  * in p if they cannot be found inside c itself.
40  * </p>
41  * <p/>
42  * Using {@link Class} objects as keys to the various registerXXX() methods makes
43  * a subtle semantic difference:
44  * </p>
45  * <p/>
46  * If there are more than one registered components of the same type and one of them are
47  * registered with a {@link java.lang.Class} key of the corresponding type, this component
48  * will take precedence over other components during type resolution.
49  * </p>
50  * <p/>
51  * Another place where keys that are classes make a subtle difference is in
52  * {@link org.picocontainer.alternatives.ImplementationHidingComponentAdapter}.
53  * </p>
54  *
55  * @author Paul Hammant
56  * @author Aslak Helles&oslash;y
57  * @author Jon Tirs&eacute;n
58  * @author Thomas Heller
59  * @version $Revision: 1.8 $
60  */

61 public class DefaultPicoContainer implements MutablePicoContainer, Serializable JavaDoc {
62
63     private Map JavaDoc componentKeyToAdapterCache = new HashMap JavaDoc();
64     private ComponentAdapterFactory componentAdapterFactory;
65     private PicoContainer parent;
66     private List JavaDoc componentAdapters = new ArrayList JavaDoc();
67
68     // Keeps track of instantiation order.
69
private List JavaDoc orderedComponentAdapters = new ArrayList JavaDoc();
70
71     private boolean started = false;
72     private boolean disposed = false;
73     private HashSet JavaDoc children = new HashSet JavaDoc();
74     private LifecycleManager lifecycleManager;
75
76     /**
77      * Creates a new container with a custom ComponentAdapterFactory and a parent container.
78      * <p/>
79      * <em>
80      * Important note about caching: If you intend the components to be cached, you should pass
81      * in a factory that creates {@link CachingComponentAdapter} instances, such as for example
82      * {@link CachingComponentAdapterFactory}. CachingComponentAdapterFactory can delegate to
83      * other ComponentAdapterFactories.
84      * </em>
85      *
86      * @param componentAdapterFactory the factory to use for creation of ComponentAdapters.
87      * @param parent the parent container (used for component dependency lookups).
88      * @param lifecycleManager the liftcycle manager used to handle start/stop etc.
89      */

90     public DefaultPicoContainer(ComponentAdapterFactory componentAdapterFactory, PicoContainer parent,
91                                 LifecycleManager lifecycleManager) {
92         this.lifecycleManager = lifecycleManager;
93         if (componentAdapterFactory == null) throw new NullPointerException JavaDoc("componentAdapterFactory");
94         this.componentAdapterFactory = componentAdapterFactory;
95         this.parent = parent == null ? null : new ImmutablePicoContainer(parent);
96     }
97
98
99     /**
100      * Creates a new container with a custom ComponentAdapterFactory and a parent container.
101      * <p/>
102      * <em>
103      * Important note about caching: If you intend the components to be cached, you should pass
104      * in a factory that creates {@link CachingComponentAdapter} instances, such as for example
105      * {@link CachingComponentAdapterFactory}. CachingComponentAdapterFactory can delegate to
106      * other ComponentAdapterFactories.
107      * </em>
108      *
109      * @param componentAdapterFactory the factory to use for creation of ComponentAdapters.
110      * @param parent the parent container (used for component dependency lookups).
111      */

112     public DefaultPicoContainer(ComponentAdapterFactory componentAdapterFactory, PicoContainer parent) {
113         this(componentAdapterFactory, parent, new DefaultLifecycleManager());
114     }
115
116     /**
117      * Creates a new container with a (caching) {@link DefaultComponentAdapterFactory}
118      * and a parent container.
119      */

120     public DefaultPicoContainer(PicoContainer parent) {
121         this(new DefaultComponentAdapterFactory(), parent);
122     }
123
124     /**
125      * Creates a new container with a custom ComponentAdapterFactory and no parent container.
126      *
127      * @param componentAdapterFactory the ComponentAdapterFactory to use.
128      */

129     public DefaultPicoContainer(ComponentAdapterFactory componentAdapterFactory) {
130         this(componentAdapterFactory, null);
131     }
132
133     /**
134      * Creates a new container with a custom LifecycleManger and no parent container.
135      *
136      * @param lifecycleManager the lifecycle manager to manage start/stop/dispose calls on the container.
137      */

138     public DefaultPicoContainer(LifecycleManager lifecycleManager) {
139         this(new DefaultComponentAdapterFactory(), null, lifecycleManager);
140     }
141
142     /**
143      * Creates a new container with a (caching) {@link DefaultComponentAdapterFactory} and no parent container.
144      */

145     public DefaultPicoContainer() {
146         this(new DefaultComponentAdapterFactory(), null);
147     }
148
149     public Collection JavaDoc getComponentAdapters() {
150         return Collections.unmodifiableList(componentAdapters);
151     }
152
153     public final ComponentAdapter getComponentAdapter(Object JavaDoc componentKey) throws AmbiguousComponentResolutionException {
154         ComponentAdapter adapter = (ComponentAdapter) componentKeyToAdapterCache.get(componentKey);
155         if (adapter == null && parent != null) {
156             adapter = parent.getComponentAdapter(componentKey);
157         }
158         return adapter;
159     }
160
161     public ComponentAdapter getComponentAdapterOfType(Class JavaDoc componentType) {
162         // See http://jira.codehaus.org/secure/ViewIssue.jspa?key=PICO-115
163
ComponentAdapter adapterByKey = getComponentAdapter(componentType);
164         if (adapterByKey != null) {
165             return adapterByKey;
166         }
167
168         List JavaDoc found = getComponentAdaptersOfType(componentType);
169
170         if (found.size() == 1) {
171             return ((ComponentAdapter) found.get(0));
172         } else if (found.size() == 0) {
173             if (parent != null) {
174                 return parent.getComponentAdapterOfType(componentType);
175             } else {
176                 return null;
177             }
178         } else {
179             Class JavaDoc[] foundClasses = new Class JavaDoc[found.size()];
180             for (int i = 0; i < foundClasses.length; i++) {
181                 foundClasses[i] = ((ComponentAdapter) found.get(i)).getComponentImplementation();
182             }
183
184             throw new AmbiguousComponentResolutionException(componentType, foundClasses);
185         }
186     }
187
188     public List JavaDoc getComponentAdaptersOfType(Class JavaDoc componentType) {
189         if (componentType == null) {
190             return Collections.EMPTY_LIST;
191         }
192         List JavaDoc found = new ArrayList JavaDoc();
193         for (Iterator JavaDoc iterator = getComponentAdapters().iterator(); iterator.hasNext();) {
194             ComponentAdapter componentAdapter = (ComponentAdapter) iterator.next();
195
196             if (componentType.isAssignableFrom(componentAdapter.getComponentImplementation())) {
197                 found.add(componentAdapter);
198             }
199         }
200         return found;
201     }
202
203     /**
204      * {@inheritDoc}
205      * This method can be used to override the ComponentAdapter created by the {@link ComponentAdapterFactory}
206      * passed to the constructor of this container.
207      */

208     public ComponentAdapter registerComponent(ComponentAdapter componentAdapter) throws DuplicateComponentKeyRegistrationException {
209         Object JavaDoc componentKey = componentAdapter.getComponentKey();
210         if (componentKeyToAdapterCache.containsKey(componentKey)) {
211             throw new DuplicateComponentKeyRegistrationException(componentKey);
212         }
213         componentAdapters.add(componentAdapter);
214         componentKeyToAdapterCache.put(componentKey, componentAdapter);
215         return componentAdapter;
216     }
217
218     public ComponentAdapter unregisterComponent(Object JavaDoc componentKey) {
219         ComponentAdapter adapter = (ComponentAdapter) componentKeyToAdapterCache.remove(componentKey);
220         componentAdapters.remove(adapter);
221         orderedComponentAdapters.remove(adapter);
222         return adapter;
223     }
224
225     /**
226      * {@inheritDoc}
227      * The returned ComponentAdapter will be an {@link InstanceComponentAdapter}.
228      */

229     public ComponentAdapter registerComponentInstance(Object JavaDoc component) throws PicoRegistrationException {
230         return registerComponentInstance(component.getClass(), component);
231     }
232
233     /**
234      * {@inheritDoc}
235      * The returned ComponentAdapter will be an {@link InstanceComponentAdapter}.
236      */

237     public ComponentAdapter registerComponentInstance(Object JavaDoc componentKey, Object JavaDoc componentInstance) throws PicoRegistrationException {
238         ComponentAdapter componentAdapter = new InstanceComponentAdapter(componentKey, componentInstance);
239         registerComponent(componentAdapter);
240         return componentAdapter;
241     }
242
243     /**
244      * {@inheritDoc}
245      * The returned ComponentAdapter will be instantiated by the {@link ComponentAdapterFactory}
246      * passed to the container's constructor.
247      */

248     public ComponentAdapter registerComponentImplementation(Class JavaDoc componentImplementation) throws PicoRegistrationException {
249         return registerComponentImplementation(componentImplementation, componentImplementation);
250     }
251
252     /**
253      * {@inheritDoc}
254      * The returned ComponentAdapter will be instantiated by the {@link ComponentAdapterFactory}
255      * passed to the container's constructor.
256      */

257     public ComponentAdapter registerComponentImplementation(Object JavaDoc componentKey, Class JavaDoc componentImplementation) throws PicoRegistrationException {
258         return registerComponentImplementation(componentKey, componentImplementation, (Parameter[]) null);
259     }
260
261     /**
262      * {@inheritDoc}
263      * The returned ComponentAdapter will be instantiated by the {@link ComponentAdapterFactory}
264      * passed to the container's constructor.
265      */

266     public ComponentAdapter registerComponentImplementation(Object JavaDoc componentKey, Class JavaDoc componentImplementation, Parameter[] parameters) throws PicoRegistrationException {
267         ComponentAdapter componentAdapter = componentAdapterFactory.createComponentAdapter(componentKey, componentImplementation, parameters);
268         registerComponent(componentAdapter);
269         return componentAdapter;
270     }
271
272     /**
273      * Same as {@link #registerComponentImplementation(java.lang.Object, java.lang.Class, org.picocontainer.Parameter[])}
274      * but with parameters as a {@link List}. Makes it possible to use with Groovy arrays (which are actually Lists).
275      */

276     public ComponentAdapter registerComponentImplementation(Object JavaDoc componentKey, Class JavaDoc componentImplementation, List JavaDoc parameters) throws PicoRegistrationException {
277         Parameter[] parametersAsArray = (Parameter[]) parameters.toArray(new Parameter[parameters.size()]);
278         return registerComponentImplementation(componentKey, componentImplementation, parametersAsArray);
279     }
280
281     private void addOrderedComponentAdapter(ComponentAdapter componentAdapter) {
282         if (!orderedComponentAdapters.contains(componentAdapter)) {
283             orderedComponentAdapters.add(componentAdapter);
284         }
285     }
286
287     public List JavaDoc getComponentInstances() throws PicoException {
288         return getComponentInstancesOfType(Object JavaDoc.class);
289     }
290
291     public List JavaDoc getComponentInstancesOfType(Class JavaDoc componentType) throws PicoException {
292         if (componentType == null) {
293             return Collections.EMPTY_LIST;
294         }
295
296         Map JavaDoc adapterToInstanceMap = new HashMap JavaDoc();
297         for (Iterator JavaDoc iterator = componentAdapters.iterator(); iterator.hasNext();) {
298             ComponentAdapter componentAdapter = (ComponentAdapter) iterator.next();
299             if (componentType.isAssignableFrom(componentAdapter.getComponentImplementation())) {
300                 Object JavaDoc componentInstance = getInstance(componentAdapter);
301                 adapterToInstanceMap.put(componentAdapter, componentInstance);
302
303                 // This is to ensure all are added. (Indirect dependencies will be added
304
// from InstantiatingComponentAdapter).
305
addOrderedComponentAdapter(componentAdapter);
306             }
307         }
308         List JavaDoc result = new ArrayList JavaDoc();
309         for (Iterator JavaDoc iterator = orderedComponentAdapters.iterator(); iterator.hasNext();) {
310             Object JavaDoc componentAdapter = iterator.next();
311             final Object JavaDoc componentInstance = adapterToInstanceMap.get(componentAdapter);
312             if (componentInstance != null) {
313                 // may be null in the case of the "implicit" adapter
314
// representing "this".
315
result.add(componentInstance);
316             }
317         }
318         return result;
319     }
320
321     public Object JavaDoc getComponentInstance(Object JavaDoc componentKey) throws PicoException {
322         ComponentAdapter componentAdapter = getComponentAdapter(componentKey);
323         if (componentAdapter != null) {
324             return getInstance(componentAdapter);
325         } else {
326             return null;
327         }
328     }
329
330     public Object JavaDoc getComponentInstanceOfType(Class JavaDoc componentType) {
331         final ComponentAdapter componentAdapter = getComponentAdapterOfType(componentType);
332         return componentAdapter == null ? null : getInstance(componentAdapter);
333     }
334
335     private Object JavaDoc getInstance(ComponentAdapter componentAdapter) {
336         // check wether this is our adapter
337
// we need to check this to ensure up-down dependencies cannot be followed
338
final boolean isLocal = componentAdapters.contains(componentAdapter);
339
340         if (isLocal) {
341             Object JavaDoc instance = componentAdapter.getComponentInstance(this);
342
343             addOrderedComponentAdapter(componentAdapter);
344
345             return instance;
346         } else if (parent != null) {
347             return parent.getComponentInstance(componentAdapter.getComponentKey());
348         }
349
350         // TODO: decide .. exception or null?
351
// exceptrion: mx: +1, joehni +1
352
return null;
353     }
354
355
356     public PicoContainer getParent() {
357         return parent;
358     }
359
360     public ComponentAdapter unregisterComponentByInstance(Object JavaDoc componentInstance) {
361         Collection JavaDoc componentAdapters = getComponentAdapters();
362         for (Iterator JavaDoc iterator = componentAdapters.iterator(); iterator.hasNext();) {
363             ComponentAdapter componentAdapter = (ComponentAdapter) iterator.next();
364             if (getInstance(componentAdapter).equals(componentInstance)) {
365                 return unregisterComponent(componentAdapter.getComponentKey());
366             }
367         }
368         return null;
369     }
370
371     /**
372      * @deprecated since 1.1 - Use new VerifyingVisitor().traverse(this)
373      */

374     public void verify() throws PicoVerificationException {
375         new VerifyingVisitor().traverse(this);
376     }
377
378     /**
379      * Start the components of this PicoContainer and all its logical child containers.
380      * Any component implementing the lifecycle interface {@link org.picocontainer.Startable} will be started.
381      *
382      * @see #makeChildContainer()
383      * @see #addChildContainer(PicoContainer)
384      * @see #removeChildContainer(PicoContainer)
385      */

386     public void start() {
387         if (disposed) throw new IllegalStateException JavaDoc("Already disposed");
388         if (started) throw new IllegalStateException JavaDoc("Already started");
389         lifecycleManager.start(this);
390         for (Iterator JavaDoc iterator = children.iterator(); iterator.hasNext();) {
391             PicoContainer child = (PicoContainer) iterator.next();
392             if (child instanceof Startable) {
393                 child.start();
394             }
395         }
396         started = true;
397     }
398
399     /**
400      * Stop the components of this PicoContainer and all its logical child containers.
401      * Any component implementing the lifecycle interface {@link org.picocontainer.Startable} will be stopped.
402      *
403      * @see #makeChildContainer()
404      * @see #addChildContainer(PicoContainer)
405      * @see #removeChildContainer(PicoContainer)
406      */

407     public void stop() {
408         if (disposed) throw new IllegalStateException JavaDoc("Already disposed");
409         if (!started) throw new IllegalStateException JavaDoc("Not started");
410         for (Iterator JavaDoc iterator = children.iterator(); iterator.hasNext();) {
411             PicoContainer child = (PicoContainer) iterator.next();
412             if (child instanceof Startable) {
413                 child.stop();
414             }
415         }
416         lifecycleManager.stop(this);
417         started = false;
418     }
419
420     /**
421      * Dispose the components of this PicoContainer and all its logical child containers.
422      * Any component implementing the lifecycle interface {@link org.picocontainer.Disposable} will be disposed.
423      *
424      * @see #makeChildContainer()
425      * @see #addChildContainer(PicoContainer)
426      * @see #removeChildContainer(PicoContainer)
427      */

428     public void dispose() {
429         if (disposed) throw new IllegalStateException JavaDoc("Already disposed");
430         for (Iterator JavaDoc iterator = children.iterator(); iterator.hasNext();) {
431             PicoContainer child = (PicoContainer) iterator.next();
432             if (child instanceof Disposable) {
433                 child.dispose();
434             }
435         }
436         lifecycleManager.dispose(this);
437         disposed = true;
438     }
439
440     public MutablePicoContainer makeChildContainer() {
441         DefaultPicoContainer pc = new DefaultPicoContainer(componentAdapterFactory, this, lifecycleManager);
442         addChildContainer(pc);
443         return pc;
444     }
445
446     public boolean addChildContainer(PicoContainer child) {
447         return children.add(child);
448     }
449
450     public boolean removeChildContainer(PicoContainer child) {
451         final boolean result = children.remove(child);
452         return result;
453     }
454
455     public void accept(PicoVisitor visitor) {
456         visitor.visitContainer(this);
457         final List JavaDoc componentAdapters = new ArrayList JavaDoc(getComponentAdapters());
458         for (Iterator JavaDoc iterator = componentAdapters.iterator(); iterator.hasNext();) {
459             ComponentAdapter componentAdapter = (ComponentAdapter) iterator.next();
460             componentAdapter.accept(visitor);
461         }
462         final List JavaDoc allChildren = new ArrayList JavaDoc(children);
463         for (Iterator JavaDoc iterator = allChildren.iterator(); iterator.hasNext();) {
464             PicoContainer child = (PicoContainer) iterator.next();
465             child.accept(visitor);
466         }
467     }
468 }
469
Popular Tags