Clover coverage report - PicoContainer - 1.1
Coverage timestamp: Thu Nov 4 2004 11:55:45 CST
file stats: LOC: 429   Methods: 32
NCLOC: 252   Classes: 1
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover
 
 Source file Conditionals Statements Methods TOTAL
DefaultPicoContainer.java 92.4% 96.4% 96.9% 95.3%
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.MutablePicoContainer;
 14   
 import org.picocontainer.Parameter;
 15   
 import org.picocontainer.PicoContainer;
 16   
 import org.picocontainer.PicoException;
 17   
 import org.picocontainer.PicoRegistrationException;
 18   
 import org.picocontainer.PicoVerificationException;
 19   
 import org.picocontainer.PicoVisitor;
 20   
 import org.picocontainer.alternatives.ImmutablePicoContainer;
 21   
 
 22   
 import java.io.Serializable;
 23   
 import java.util.ArrayList;
 24   
 import java.util.Collection;
 25   
 import java.util.Collections;
 26   
 import java.util.HashMap;
 27   
 import java.util.HashSet;
 28   
 import java.util.Iterator;
 29   
 import java.util.List;
 30   
 import java.util.Map;
 31   
 
 32   
 /**
 33   
  * <p/>
 34   
  * The Standard {@link PicoContainer}/{@link MutablePicoContainer} implementation.
 35   
  * Constructing a container c with a parent p container will cause c to look up components
 36   
  * in p if they cannot be found inside c itself.
 37   
  * </p>
 38   
  * <p/>
 39   
  * Using {@link Class} objects as keys to the various registerXXX() methods makes
 40   
  * a subtle semantic difference:
 41   
  * </p>
 42   
  * <p/>
 43   
  * If there are more than one registered components of the same type and one of them are
 44   
  * registered with a {@link java.lang.Class} key of the corresponding type, this component
 45   
  * will take precedence over other components during type resolution.
 46   
  * </p>
 47   
  * <p/>
 48   
  * Another place where keys that are classes make a subtle difference is in
 49   
  * {@link org.picocontainer.alternatives.ImplementationHidingComponentAdapter}.
 50   
  * </p>
 51   
  *
 52   
  * @author Paul Hammant
 53   
  * @author Aslak Helles&oslash;y
 54   
  * @author Jon Tirs&eacute;n
 55   
  * @author Thomas Heller
 56   
  * @version $Revision: 1.8 $
 57   
  */
 58   
 public class DefaultPicoContainer implements MutablePicoContainer, Serializable {
 59   
 
 60   
     private Map componentKeyToAdapterCache = new HashMap();
 61   
     private ComponentAdapterFactory componentAdapterFactory;
 62   
     private PicoContainer parent;
 63   
     private List componentAdapters = new ArrayList();
 64   
 
 65   
     // Keeps track of instantiation order.
 66   
     private List orderedComponentAdapters = new ArrayList();
 67   
 
 68   
     private boolean started = false;
 69   
     private boolean disposed = false;
 70   
     private HashSet children = new HashSet();
 71   
 
 72   
     /**
 73   
      * Creates a new container with a custom ComponentAdapterFactory and a parent container.
 74   
      * <p/>
 75   
      * <em>
 76   
      * Important note about caching: If you intend the components to be cached, you should pass
 77   
      * in a factory that creates {@link CachingComponentAdapter} instances, such as for example
 78   
      * {@link CachingComponentAdapterFactory}. CachingComponentAdapterFactory can delegate to
 79   
      * other ComponentAdapterFactories.
 80   
      * </em>
 81   
      *
 82   
      * @param componentAdapterFactory the factory to use for creation of ComponentAdapters.
 83   
      * @param parent                  the parent container (used for component dependency lookups).
 84   
      */
 85  1052
     public DefaultPicoContainer(ComponentAdapterFactory componentAdapterFactory, PicoContainer parent) {
 86  0
         if(componentAdapterFactory == null) throw new NullPointerException("componentAdapterFactory");
 87  1052
         this.componentAdapterFactory = componentAdapterFactory;
 88  1052
         this.parent = parent == null ? null : new ImmutablePicoContainer(parent);
 89   
     }
 90   
 
 91   
     /**
 92   
      * Creates a new container with a (caching) {@link DefaultComponentAdapterFactory}
 93   
      * and a parent container.
 94   
      */
 95  200
     public DefaultPicoContainer(PicoContainer parent) {
 96  200
         this(new DefaultComponentAdapterFactory(), parent);
 97   
     }
 98   
 
 99   
     /**
 100   
      * Creates a new container with a custom ComponentAdapterFactory and no parent container.
 101   
      *
 102   
      * @param componentAdapterFactory the ComponentAdapterFactory to use.
 103   
      */
 104  118
     public DefaultPicoContainer(ComponentAdapterFactory componentAdapterFactory) {
 105  118
         this(componentAdapterFactory, null);
 106   
     }
 107   
 
 108   
     /**
 109   
      * Creates a new container with a (caching) {@link DefaultComponentAdapterFactory} and no parent container.
 110   
      */
 111  354
     public DefaultPicoContainer() {
 112  354
         this(new DefaultComponentAdapterFactory(), null);
 113   
     }
 114   
 
 115  3684
     public Collection getComponentAdapters() {
 116  3684
         return Collections.unmodifiableList(componentAdapters);
 117   
     }
 118   
 
 119  3852
     public final ComponentAdapter getComponentAdapter(Object componentKey) throws AmbiguousComponentResolutionException {
 120  3852
         ComponentAdapter adapter = (ComponentAdapter) componentKeyToAdapterCache.get(componentKey);
 121  3852
         if (adapter == null && parent != null) {
 122  320
             adapter = parent.getComponentAdapter(componentKey);
 123   
         }
 124  3852
         return adapter;
 125   
     }
 126   
 
 127  2234
     public ComponentAdapter getComponentAdapterOfType(Class componentType) {
 128   
         // See http://jira.codehaus.org/secure/ViewIssue.jspa?key=PICO-115
 129  2234
         ComponentAdapter adapterByKey = getComponentAdapter(componentType);
 130  2234
         if (adapterByKey != null) {
 131  740
             return adapterByKey;
 132   
         }
 133   
 
 134  1494
         List found = getComponentAdaptersOfType(componentType);
 135   
 
 136  1494
         if (found.size() == 1) {
 137  336
             return ((ComponentAdapter) found.get(0));
 138  1158
         } else if (found.size() == 0) {
 139  1142
             if (parent != null) {
 140  66
                 return parent.getComponentAdapterOfType(componentType);
 141   
             } else {
 142  1076
                 return null;
 143   
             }
 144   
         } else {
 145  16
             Class[] foundClasses = new Class[found.size()];
 146  16
             for (int i = 0; i < foundClasses.length; i++) {
 147  32
                 ComponentAdapter componentAdapter = (ComponentAdapter) found.get(i);
 148  32
                 foundClasses[i] = componentAdapter.getComponentImplementation();
 149   
             }
 150   
 
 151  16
             throw new AmbiguousComponentResolutionException(componentType, foundClasses);
 152   
         }
 153   
     }
 154   
 
 155  2372
     public List getComponentAdaptersOfType(Class componentType) {
 156  2372
         if(componentType == null) {
 157  0
             return Collections.EMPTY_LIST;
 158   
         }
 159  2372
         List found = new ArrayList();
 160  2372
         for (Iterator iterator = getComponentAdapters().iterator(); iterator.hasNext();) {
 161  5232
             ComponentAdapter componentAdapter = (ComponentAdapter) iterator.next();
 162   
 
 163  5232
             if (componentType.isAssignableFrom(componentAdapter.getComponentImplementation())) {
 164  682
                 found.add(componentAdapter);
 165   
             }
 166   
         }
 167  2372
         return found;
 168   
     }
 169   
 
 170   
     /**
 171   
      * {@inheritDoc}
 172   
      * This method can be used to override the ComponentAdapter created by the {@link ComponentAdapterFactory}
 173   
      * passed to the constructor of this container.
 174   
      */
 175  1422
     public ComponentAdapter registerComponent(ComponentAdapter componentAdapter) throws DuplicateComponentKeyRegistrationException {
 176  1422
         Object componentKey = componentAdapter.getComponentKey();
 177  1422
         if (componentKeyToAdapterCache.containsKey(componentKey)) {
 178  14
             throw new DuplicateComponentKeyRegistrationException(componentKey);
 179   
         }
 180  1408
         componentAdapters.add(componentAdapter);
 181  1408
         componentKeyToAdapterCache.put(componentKey, componentAdapter);
 182  1408
         return componentAdapter;
 183   
     }
 184   
 
 185  46
     public ComponentAdapter unregisterComponent(Object componentKey) {
 186  46
         ComponentAdapter adapter = (ComponentAdapter) componentKeyToAdapterCache.remove(componentKey);
 187  46
         componentAdapters.remove(adapter);
 188  46
         orderedComponentAdapters.remove(adapter);
 189  46
         return adapter;
 190   
     }
 191   
 
 192   
     /**
 193   
      * {@inheritDoc}
 194   
      * The returned ComponentAdapter will be an {@link InstanceComponentAdapter}.
 195   
      */
 196  178
     public ComponentAdapter registerComponentInstance(Object component) throws PicoRegistrationException {
 197  178
         return registerComponentInstance(component.getClass(), component);
 198   
     }
 199   
 
 200   
     /**
 201   
      * {@inheritDoc}
 202   
      * The returned ComponentAdapter will be an {@link InstanceComponentAdapter}.
 203   
      */
 204  288
     public ComponentAdapter registerComponentInstance(Object componentKey, Object componentInstance) throws PicoRegistrationException {
 205  288
         if (componentInstance instanceof MutablePicoContainer) {
 206  12
             MutablePicoContainer pc = (MutablePicoContainer) componentInstance;
 207  12
             Object contrivedKey = new Object();
 208  12
             String contrivedComp = "";
 209  12
             pc.registerComponentInstance(contrivedKey, contrivedComp);
 210  12
             try {
 211  12
                 if (this.getComponentInstance(contrivedKey) != null) {
 212  12
                     throw new PicoRegistrationException("Cannot register a container to itself. The container is already implicitly registered.");
 213   
                 }
 214   
             } finally {
 215  12
                 pc.unregisterComponent(contrivedKey);
 216   
             }
 217   
 
 218   
         }
 219  276
         ComponentAdapter componentAdapter = new InstanceComponentAdapter(componentKey, componentInstance);
 220  264
         registerComponent(componentAdapter);
 221  262
         return componentAdapter;
 222   
     }
 223   
 
 224   
     /**
 225   
      * {@inheritDoc}
 226   
      * The returned ComponentAdapter will be instantiated by the {@link ComponentAdapterFactory}
 227   
      * passed to the container's constructor.
 228   
      */
 229  522
     public ComponentAdapter registerComponentImplementation(Class componentImplementation) throws PicoRegistrationException {
 230  522
         return registerComponentImplementation(componentImplementation, componentImplementation);
 231   
     }
 232   
 
 233   
     /**
 234   
      * {@inheritDoc}
 235   
      * The returned ComponentAdapter will be instantiated by the {@link ComponentAdapterFactory}
 236   
      * passed to the container's constructor.
 237   
      */
 238  780
     public ComponentAdapter registerComponentImplementation(Object componentKey, Class componentImplementation) throws PicoRegistrationException {
 239  780
         return registerComponentImplementation(componentKey, componentImplementation, (Parameter[]) null);
 240   
     }
 241   
 
 242   
     /**
 243   
      * {@inheritDoc}
 244   
      * The returned ComponentAdapter will be instantiated by the {@link ComponentAdapterFactory}
 245   
      * passed to the container's constructor.
 246   
      */
 247  926
     public ComponentAdapter registerComponentImplementation(Object componentKey, Class componentImplementation, Parameter[] parameters) throws PicoRegistrationException {
 248  926
         ComponentAdapter componentAdapter = componentAdapterFactory.createComponentAdapter(componentKey, componentImplementation, parameters);
 249  920
         registerComponent(componentAdapter);
 250  908
         return componentAdapter;
 251   
     }
 252   
 
 253   
     /**
 254   
      * Same as {@link #registerComponentImplementation(java.lang.Object, java.lang.Class, org.picocontainer.Parameter[])}
 255   
      * but with parameters as a {@link List}. Makes it possible to use with Groovy arrays (which are actually Lists).
 256   
      */
 257  2
     public ComponentAdapter registerComponentImplementation(Object componentKey, Class componentImplementation, List parameters) throws PicoRegistrationException {
 258  2
         Parameter[] parametersAsArray = (Parameter[]) parameters.toArray(new Parameter[parameters.size()]);
 259  2
         return registerComponentImplementation(componentKey, componentImplementation, parametersAsArray);
 260   
     }
 261   
 
 262  1976
     private void addOrderedComponentAdapter(ComponentAdapter componentAdapter) {
 263  1976
         if (!orderedComponentAdapters.contains(componentAdapter)) {
 264  906
             orderedComponentAdapters.add(componentAdapter);
 265   
         }
 266   
     }
 267   
 
 268  152
     public List getComponentInstances() throws PicoException {
 269  152
         return getComponentInstancesOfType(Object.class);
 270   
     }
 271   
 
 272  480
     public List getComponentInstancesOfType(Class componentType) throws PicoException {
 273  480
         if(componentType == null) {
 274  0
             return Collections.EMPTY_LIST;
 275   
         }
 276   
 
 277  480
         Map adapterToInstanceMap = new HashMap();
 278  480
         for (Iterator iterator = componentAdapters.iterator(); iterator.hasNext();) {
 279  668
             ComponentAdapter componentAdapter = (ComponentAdapter) iterator.next();
 280  668
             if (componentType.isAssignableFrom(componentAdapter.getComponentImplementation())) {
 281  472
                 Object componentInstance = getInstance(componentAdapter);
 282  470
                 adapterToInstanceMap.put(componentAdapter, componentInstance);
 283   
 
 284   
                 // This is to ensure all are added. (Indirect dependencies will be added
 285   
                 // from InstantiatingComponentAdapter).
 286  470
                 addOrderedComponentAdapter(componentAdapter);
 287   
             }
 288   
         }
 289  478
         List result = new ArrayList();
 290  478
         for (Iterator iterator = orderedComponentAdapters.iterator(); iterator.hasNext();) {
 291  628
             Object componentAdapter = iterator.next();
 292  628
             final Object componentInstance = adapterToInstanceMap.get(componentAdapter);
 293  628
             if (componentInstance != null) {
 294   
                 // may be null in the case of the "implicit" adapter
 295   
                 // representing "this".
 296  468
                 result.add(componentInstance);
 297   
             }
 298   
         }
 299  478
         return result;
 300   
     }
 301   
 
 302  1206
     public Object getComponentInstance(Object componentKey) throws PicoException {
 303  1206
         ComponentAdapter componentAdapter = getComponentAdapter(componentKey);
 304  1206
         if (componentAdapter != null) {
 305  1174
             return getInstance(componentAdapter);
 306   
         } else {
 307  32
             return null;
 308   
         }
 309   
     }
 310   
 
 311  86
     public Object getComponentInstanceOfType(Class componentType) {
 312  86
         final ComponentAdapter componentAdapter = getComponentAdapterOfType(componentType);
 313  86
         return componentAdapter == null ? null : getInstance(componentAdapter);
 314   
     }
 315   
 
 316  1724
     private Object getInstance(ComponentAdapter componentAdapter) {
 317   
         // check wether this is our adapter
 318   
         // we need to check this to ensure up-down dependencies cannot be followed
 319  1724
         final boolean isLocal = componentAdapters.contains(componentAdapter);
 320   
 
 321  1724
         if (isLocal) {
 322  1614
             Object instance = componentAdapter.getComponentInstance(this);
 323   
 
 324  1506
             addOrderedComponentAdapter(componentAdapter);
 325   
 
 326  1506
             return instance;
 327  110
         } else if (parent != null) {
 328  110
             return parent.getComponentInstance(componentAdapter.getComponentKey());
 329   
         }
 330   
 
 331   
         // TODO: decide .. exception or null?
 332   
         // exceptrion: mx: +1, joehni +1
 333  0
         return null;
 334   
     }
 335   
 
 336   
 
 337  898
     public PicoContainer getParent() {
 338  898
         return parent;
 339   
     }
 340   
 
 341  14
     public ComponentAdapter unregisterComponentByInstance(Object componentInstance) {
 342  14
         Collection componentAdapters = getComponentAdapters();
 343  14
         for (Iterator iterator = componentAdapters.iterator(); iterator.hasNext();) {
 344  4
             ComponentAdapter componentAdapter = (ComponentAdapter) iterator.next();
 345  4
             if (getInstance(componentAdapter).equals(componentInstance)) {
 346  2
                 return unregisterComponent(componentAdapter.getComponentKey());
 347   
             }
 348   
         }
 349  12
         return null;
 350   
     }
 351   
 
 352   
     /**
 353   
      * @deprecated since 1.1 - Use new VerifyingVisitor().traverse(this)
 354   
     */
 355  0
     public void verify() throws PicoVerificationException {
 356  0
         new VerifyingVisitor().traverse(this);
 357   
     }
 358   
 
 359   
     /**
 360   
      * Start the components of this PicoContainer and all its logical child containers.
 361   
      * Any component implementing the lifecycle interface {@link org.picocontainer.Startable} will be started.
 362   
      * @see #makeChildContainer()
 363   
      * @see #addChildContainer(PicoContainer)
 364   
      * @see #removeChildContainer(PicoContainer)
 365   
      */
 366  90
     public void start() {
 367  2
         if (disposed) throw new IllegalStateException("Already disposed");
 368  4
         if (started) throw new IllegalStateException("Already started");
 369  84
         LifecycleVisitor.start(this);
 370  82
         started = true;
 371   
     }
 372   
 
 373   
     /**
 374   
      * Stop the components of this PicoContainer and all its logical child containers.
 375   
      * Any component implementing the lifecycle interface {@link org.picocontainer.Startable} will be stopped.
 376   
      * @see #makeChildContainer()
 377   
      * @see #addChildContainer(PicoContainer)
 378   
      * @see #removeChildContainer(PicoContainer)
 379   
      */
 380  68
     public void stop() {
 381  2
         if (disposed) throw new IllegalStateException("Already disposed");
 382  2
         if (!started) throw new IllegalStateException("Not started");
 383  64
         LifecycleVisitor.stop(this);
 384  64
         started = false;
 385   
     }
 386   
 
 387   
     /**
 388   
      * Dispose the components of this PicoContainer and all its logical child containers.
 389   
      * Any component implementing the lifecycle interface {@link org.picocontainer.Disposable} will be disposed.
 390   
      * @see #makeChildContainer()
 391   
      * @see #addChildContainer(PicoContainer)
 392   
      * @see #removeChildContainer(PicoContainer)
 393   
      */
 394  64
     public void dispose() {
 395  2
         if (disposed) throw new IllegalStateException("Already disposed");
 396  62
         LifecycleVisitor.dispose(this);
 397  62
         disposed = true;
 398   
     }
 399   
 
 400  30
     public MutablePicoContainer makeChildContainer() {
 401  30
         DefaultPicoContainer pc = new DefaultPicoContainer(componentAdapterFactory, this);
 402  30
         addChildContainer(pc);
 403  30
         return pc;
 404   
     }
 405   
 
 406  72
     public boolean addChildContainer(PicoContainer child) {
 407  72
         return children.add(child);
 408   
     }
 409   
 
 410  12
     public boolean removeChildContainer(PicoContainer child) {
 411  12
         final boolean result = children.remove(child);
 412  12
         return result;
 413   
     }
 414   
 
 415  360
     public void accept(PicoVisitor visitor) {
 416  360
         visitor.visitContainer(this);
 417  356
         final List componentAdapters = new ArrayList(getComponentAdapters());
 418  356
         for (Iterator iterator = componentAdapters.iterator(); iterator.hasNext();) {
 419  506
             ComponentAdapter componentAdapter = (ComponentAdapter) iterator.next();
 420  506
             componentAdapter.accept(visitor);
 421   
         }
 422  356
         final List allChildren = new ArrayList(children);
 423  356
         for (Iterator iterator = allChildren.iterator(); iterator.hasNext();) {
 424  104
             PicoContainer child = (PicoContainer) iterator.next();
 425  104
             child.accept(visitor);
 426   
         }
 427   
     }
 428   
 }
 429