Clover coverage report - picocontainer - 1.2-beta-1
Coverage timestamp: Sun May 29 2005 14:29:04 BST
file stats: LOC: 468   Methods: 34
NCLOC: 268   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
DefaultPicoContainer.java 85.1% 92.3% 94.1% 90.4%
coverage coverage
 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;
 26    import java.util.ArrayList;
 27    import java.util.Collection;
 28    import java.util.Collections;
 29    import java.util.HashMap;
 30    import java.util.HashSet;
 31    import java.util.Iterator;
 32    import java.util.List;
 33    import java.util.Map;
 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 {
 62   
 63    private Map componentKeyToAdapterCache = new HashMap();
 64    private ComponentAdapterFactory componentAdapterFactory;
 65    private PicoContainer parent;
 66    private List componentAdapters = new ArrayList();
 67   
 68    // Keeps track of instantiation order.
 69    private List orderedComponentAdapters = new ArrayList();
 70   
 71    private boolean started = false;
 72    private boolean disposed = false;
 73    private HashSet children = new HashSet();
 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  1066 public DefaultPicoContainer(ComponentAdapterFactory componentAdapterFactory, PicoContainer parent,
 91    LifecycleManager lifecycleManager) {
 92  1066 this.lifecycleManager = lifecycleManager;
 93  0 if (componentAdapterFactory == null) throw new NullPointerException("componentAdapterFactory");
 94  1066 this.componentAdapterFactory = componentAdapterFactory;
 95  1066 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  752 public DefaultPicoContainer(ComponentAdapterFactory componentAdapterFactory, PicoContainer parent) {
 113  752 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  198 public DefaultPicoContainer(PicoContainer parent) {
 121  198 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  118 public DefaultPicoContainer(ComponentAdapterFactory componentAdapterFactory) {
 130  118 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  0 public DefaultPicoContainer(LifecycleManager lifecycleManager) {
 139  0 this(new DefaultComponentAdapterFactory(), null, lifecycleManager);
 140    }
 141   
 142    /**
 143    * Creates a new container with a (caching) {@link DefaultComponentAdapterFactory} and no parent container.
 144    */
 145  354 public DefaultPicoContainer() {
 146  354 this(new DefaultComponentAdapterFactory(), null);
 147    }
 148   
 149  3424 public Collection getComponentAdapters() {
 150  3424 return Collections.unmodifiableList(componentAdapters);
 151    }
 152   
 153  3864 public final ComponentAdapter getComponentAdapter(Object componentKey) throws AmbiguousComponentResolutionException {
 154  3864 ComponentAdapter adapter = (ComponentAdapter) componentKeyToAdapterCache.get(componentKey);
 155  3864 if (adapter == null && parent != null) {
 156  320 adapter = parent.getComponentAdapter(componentKey);
 157    }
 158  3864 return adapter;
 159    }
 160   
 161  180 public ComponentAdapter getComponentAdapterOfType(Class componentType) {
 162    // See http://jira.codehaus.org/secure/ViewIssue.jspa?key=PICO-115
 163  180 ComponentAdapter adapterByKey = getComponentAdapter(componentType);
 164  180 if (adapterByKey != null) {
 165  86 return adapterByKey;
 166    }
 167   
 168  94 List found = getComponentAdaptersOfType(componentType);
 169   
 170  94 if (found.size() == 1) {
 171  48 return ((ComponentAdapter) found.get(0));
 172  46 } else if (found.size() == 0) {
 173  46 if (parent != null) {
 174  0 return parent.getComponentAdapterOfType(componentType);
 175    } else {
 176  46 return null;
 177    }
 178    } else {
 179  0 Class[] foundClasses = new Class[found.size()];
 180  0 for (int i = 0; i < foundClasses.length; i++) {
 181  0 foundClasses[i] = ((ComponentAdapter) found.get(i)).getComponentImplementation();
 182    }
 183   
 184  0 throw new AmbiguousComponentResolutionException(componentType, foundClasses);
 185    }
 186    }
 187   
 188  2396 public List getComponentAdaptersOfType(Class componentType) {
 189  2396 if (componentType == null) {
 190  0 return Collections.EMPTY_LIST;
 191    }
 192  2396 List found = new ArrayList();
 193  2396 for (Iterator iterator = getComponentAdapters().iterator(); iterator.hasNext();) {
 194  5296 ComponentAdapter componentAdapter = (ComponentAdapter) iterator.next();
 195   
 196  5296 if (componentType.isAssignableFrom(componentAdapter.getComponentImplementation())) {
 197  702 found.add(componentAdapter);
 198    }
 199    }
 200  2396 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  1440 public ComponentAdapter registerComponent(ComponentAdapter componentAdapter) throws DuplicateComponentKeyRegistrationException {
 209  1440 Object componentKey = componentAdapter.getComponentKey();
 210  1440 if (componentKeyToAdapterCache.containsKey(componentKey)) {
 211  14 throw new DuplicateComponentKeyRegistrationException(componentKey);
 212    }
 213  1426 componentAdapters.add(componentAdapter);
 214  1426 componentKeyToAdapterCache.put(componentKey, componentAdapter);
 215  1426 return componentAdapter;
 216    }
 217   
 218  34 public ComponentAdapter unregisterComponent(Object componentKey) {
 219  34 ComponentAdapter adapter = (ComponentAdapter) componentKeyToAdapterCache.remove(componentKey);
 220  34 componentAdapters.remove(adapter);
 221  34 orderedComponentAdapters.remove(adapter);
 222  34 return adapter;
 223    }
 224   
 225    /**
 226    * {@inheritDoc}
 227    * The returned ComponentAdapter will be an {@link InstanceComponentAdapter}.
 228    */
 229  166 public ComponentAdapter registerComponentInstance(Object component) throws PicoRegistrationException {
 230  166 return registerComponentInstance(component.getClass(), component);
 231    }
 232   
 233    /**
 234    * {@inheritDoc}
 235    * The returned ComponentAdapter will be an {@link InstanceComponentAdapter}.
 236    */
 237  264 public ComponentAdapter registerComponentInstance(Object componentKey, Object componentInstance) throws PicoRegistrationException {
 238  264 ComponentAdapter componentAdapter = new InstanceComponentAdapter(componentKey, componentInstance);
 239  252 registerComponent(componentAdapter);
 240  250 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  528 public ComponentAdapter registerComponentImplementation(Class componentImplementation) throws PicoRegistrationException {
 249  528 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  810 public ComponentAdapter registerComponentImplementation(Object componentKey, Class componentImplementation) throws PicoRegistrationException {
 258  810 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  956 public ComponentAdapter registerComponentImplementation(Object componentKey, Class componentImplementation, Parameter[] parameters) throws PicoRegistrationException {
 267  956 ComponentAdapter componentAdapter = componentAdapterFactory.createComponentAdapter(componentKey, componentImplementation, parameters);
 268  950 registerComponent(componentAdapter);
 269  938 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  2 public ComponentAdapter registerComponentImplementation(Object componentKey, Class componentImplementation, List parameters) throws PicoRegistrationException {
 277  2 Parameter[] parametersAsArray = (Parameter[]) parameters.toArray(new Parameter[parameters.size()]);
 278  2 return registerComponentImplementation(componentKey, componentImplementation, parametersAsArray);
 279    }
 280   
 281  2022 private void addOrderedComponentAdapter(ComponentAdapter componentAdapter) {
 282  2022 if (!orderedComponentAdapters.contains(componentAdapter)) {
 283  928 orderedComponentAdapters.add(componentAdapter);
 284    }
 285    }
 286   
 287  152 public List getComponentInstances() throws PicoException {
 288  152 return getComponentInstancesOfType(Object.class);
 289    }
 290   
 291  506 public List getComponentInstancesOfType(Class componentType) throws PicoException {
 292  506 if (componentType == null) {
 293  0 return Collections.EMPTY_LIST;
 294    }
 295   
 296  506 Map adapterToInstanceMap = new HashMap();
 297  506 for (Iterator iterator = componentAdapters.iterator(); iterator.hasNext();) {
 298  698 ComponentAdapter componentAdapter = (ComponentAdapter) iterator.next();
 299  698 if (componentType.isAssignableFrom(componentAdapter.getComponentImplementation())) {
 300  496 Object componentInstance = getInstance(componentAdapter);
 301  494 adapterToInstanceMap.put(componentAdapter, componentInstance);
 302   
 303    // This is to ensure all are added. (Indirect dependencies will be added
 304    // from InstantiatingComponentAdapter).
 305  494 addOrderedComponentAdapter(componentAdapter);
 306    }
 307    }
 308  504 List result = new ArrayList();
 309  504 for (Iterator iterator = orderedComponentAdapters.iterator(); iterator.hasNext();) {
 310  652 Object componentAdapter = iterator.next();
 311  652 final Object componentInstance = adapterToInstanceMap.get(componentAdapter);
 312  652 if (componentInstance != null) {
 313    // may be null in the case of the "implicit" adapter
 314    // representing "this".
 315  492 result.add(componentInstance);
 316    }
 317    }
 318  504 return result;
 319    }
 320   
 321  1200 public Object getComponentInstance(Object componentKey) throws PicoException {
 322  1200 ComponentAdapter componentAdapter = getComponentAdapter(componentKey);
 323  1200 if (componentAdapter != null) {
 324  1168 return getInstance(componentAdapter);
 325    } else {
 326  32 return null;
 327    }
 328    }
 329   
 330  88 public Object getComponentInstanceOfType(Class componentType) {
 331  88 final ComponentAdapter componentAdapter = getComponentAdapterOfType(componentType);
 332  88 return componentAdapter == null ? null : getInstance(componentAdapter);
 333    }
 334   
 335  1744 private Object 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  1744 final boolean isLocal = componentAdapters.contains(componentAdapter);
 339   
 340  1744 if (isLocal) {
 341  1634 Object instance = componentAdapter.getComponentInstance(this);
 342   
 343  1528 addOrderedComponentAdapter(componentAdapter);
 344   
 345  1528 return instance;
 346  110 } else if (parent != null) {
 347  110 return parent.getComponentInstance(componentAdapter.getComponentKey());
 348    }
 349   
 350    // TODO: decide .. exception or null?
 351    // exceptrion: mx: +1, joehni +1
 352  0 return null;
 353    }
 354   
 355   
 356  2174 public PicoContainer getParent() {
 357  2174 return parent;
 358    }
 359   
 360  14 public ComponentAdapter unregisterComponentByInstance(Object componentInstance) {
 361  14 Collection componentAdapters = getComponentAdapters();
 362  14 for (Iterator iterator = componentAdapters.iterator(); iterator.hasNext();) {
 363  4 ComponentAdapter componentAdapter = (ComponentAdapter) iterator.next();
 364  4 if (getInstance(componentAdapter).equals(componentInstance)) {
 365  2 return unregisterComponent(componentAdapter.getComponentKey());
 366    }
 367    }
 368  12 return null;
 369    }
 370   
 371    /**
 372    * @deprecated since 1.1 - Use new VerifyingVisitor().traverse(this)
 373    */
 374  0 public void verify() throws PicoVerificationException {
 375  0 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  146 public void start() {
 387  2 if (disposed) throw new IllegalStateException("Already disposed");
 388  4 if (started) throw new IllegalStateException("Already started");
 389  140 lifecycleManager.start(this);
 390  138 for (Iterator iterator = children.iterator(); iterator.hasNext();) {
 391  42 PicoContainer child = (PicoContainer) iterator.next();
 392  42 if (child instanceof Startable) {
 393  42 child.start();
 394    }
 395    }
 396  136 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  96 public void stop() {
 408  2 if (disposed) throw new IllegalStateException("Already disposed");
 409  2 if (!started) throw new IllegalStateException("Not started");
 410  92 for (Iterator iterator = children.iterator(); iterator.hasNext();) {
 411  28 PicoContainer child = (PicoContainer) iterator.next();
 412  28 if (child instanceof Startable) {
 413  28 child.stop();
 414    }
 415    }
 416  92 lifecycleManager.stop(this);
 417  92 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  92 public void dispose() {
 429  2 if (disposed) throw new IllegalStateException("Already disposed");
 430  90 for (Iterator iterator = children.iterator(); iterator.hasNext();) {
 431  28 PicoContainer child = (PicoContainer) iterator.next();
 432  28 if (child instanceof Disposable) {
 433  28 child.dispose();
 434    }
 435    }
 436  90 lifecycleManager.dispose(this);
 437  90 disposed = true;
 438    }
 439   
 440  36 public MutablePicoContainer makeChildContainer() {
 441  36 DefaultPicoContainer pc = new DefaultPicoContainer(componentAdapterFactory, this, lifecycleManager);
 442  36 addChildContainer(pc);
 443  36 return pc;
 444    }
 445   
 446  84 public boolean addChildContainer(PicoContainer child) {
 447  84 return children.add(child);
 448    }
 449   
 450  12 public boolean removeChildContainer(PicoContainer child) {
 451  12 final boolean result = children.remove(child);
 452  12 return result;
 453    }
 454   
 455  66 public void accept(PicoVisitor visitor) {
 456  66 visitor.visitContainer(this);
 457  64 final List componentAdapters = new ArrayList(getComponentAdapters());
 458  64 for (Iterator iterator = componentAdapters.iterator(); iterator.hasNext();) {
 459  144 ComponentAdapter componentAdapter = (ComponentAdapter) iterator.next();
 460  144 componentAdapter.accept(visitor);
 461    }
 462  64 final List allChildren = new ArrayList(children);
 463  64 for (Iterator iterator = allChildren.iterator(); iterator.hasNext();) {
 464  18 PicoContainer child = (PicoContainer) iterator.next();
 465  18 child.accept(visitor);
 466    }
 467    }
 468    }