Clover coverage report - PicoContainer - 1.0
Coverage timestamp: Sat Jun 5 2004 21:34:14 EDT
file stats: LOC: 403   Methods: 31
NCLOC: 256   Classes: 2
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 90.3% 91.7% 90.3% 91.2%
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.Disposable;
 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.Startable;
 21   
 
 22   
 import java.io.Serializable;
 23   
 import java.lang.reflect.InvocationHandler;
 24   
 import java.lang.reflect.Method;
 25   
 import java.lang.reflect.Proxy;
 26   
 import java.util.ArrayList;
 27   
 import java.util.Collection;
 28   
 import java.util.Collections;
 29   
 import java.util.Comparator;
 30   
 import java.util.HashMap;
 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 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   
      * Empty immutable container. The lifecycle methods can be invoked several times without
 64   
      * throwing exceptions.
 65   
      */
 66   
     public static final PicoContainer EMPTY_IMMUTABLE_INSTANCE;
 67   
 
 68   
     static {
 69  27
         final PicoContainer picoContainer = new DefaultPicoContainer();
 70  27
         EMPTY_IMMUTABLE_INSTANCE = (PicoContainer) Proxy.newProxyInstance(DefaultPicoContainer.class.getClassLoader(), new Class[]{PicoContainer.class}, new InvocationHandler() {
 71  0
             public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
 72  0
                 String methodName = method.getName();
 73  0
                 if (methodName.equals("start") || methodName.equals("stop") || methodName.equals("dispose")) {
 74  0
                     return null;
 75   
                 }
 76  0
                 return method.invoke(picoContainer, args);
 77   
             }
 78   
         });
 79   
     }
 80   
 
 81   
     private Map componentKeyToAdapterCache = new HashMap();
 82   
     private ComponentAdapterFactory componentAdapterFactory;
 83   
     private PicoContainer parent;
 84   
     private List componentAdapters = new ArrayList();
 85   
 
 86   
     // Keeps track of instantiation order.
 87   
     private List orderedComponentAdapters = new ArrayList();
 88   
     private boolean started = false;
 89   
     private boolean disposed = false;
 90   
 
 91   
     /**
 92   
      * Creates a new container with a custom ComponentAdapterFactory and a parent container.
 93   
      * <p/>
 94   
      * <em>
 95   
      * Important note about caching: If you intend the components to be cached, you should pass
 96   
      * in a factory that creates {@link CachingComponentAdapter} instances, such as for example
 97   
      * {@link CachingComponentAdapterFactory}. CachingComponentAdapterFactory can delegate to
 98   
      * other ComponentAdapterFactories.
 99   
      * </em>
 100   
      *
 101   
      * @param componentAdapterFactory the factory to use for creation of ComponentAdapters.
 102   
      * @param parent                  the parent container.
 103   
      */
 104  209
     public DefaultPicoContainer(ComponentAdapterFactory componentAdapterFactory, PicoContainer parent) {
 105  209
         this.componentAdapterFactory = componentAdapterFactory;
 106  209
         this.parent = parent;
 107   
     }
 108   
 
 109   
     /**
 110   
      * Creates a new container with a (caching) {@link DefaultComponentAdapterFactory} and a parent container.
 111   
      */
 112  65
     public DefaultPicoContainer(PicoContainer parent) {
 113  65
         this(new DefaultComponentAdapterFactory(), parent);
 114   
     }
 115   
 
 116   
     /**
 117   
      * Creates a new container with a custom ComponentAdapterFactory and no parent container.
 118   
      */
 119  14
     public DefaultPicoContainer(ComponentAdapterFactory componentAdapterFactory) {
 120  14
         this(componentAdapterFactory, null);
 121   
     }
 122   
 
 123   
     /**
 124   
      * Creates a new container with a (caching) {@link DefaultComponentAdapterFactory} and no parent container.
 125   
      */
 126  130
     public DefaultPicoContainer() {
 127  130
         this(new DefaultComponentAdapterFactory(), null);
 128   
     }
 129   
 
 130  625
     public Collection getComponentAdapters() {
 131  625
         return Collections.unmodifiableList(componentAdapters);
 132   
     }
 133   
 
 134  742
     public final ComponentAdapter getComponentAdapter(Object componentKey) throws AmbiguousComponentResolutionException {
 135  742
         ComponentAdapter adapter = (ComponentAdapter) componentKeyToAdapterCache.get(componentKey);
 136  742
         if (adapter == null && parent != null) {
 137  19
             adapter = parent.getComponentAdapter(componentKey);
 138   
         }
 139  742
         return adapter;
 140   
     }
 141   
 
 142  582
     public ComponentAdapter getComponentAdapterOfType(Class componentType) {
 143   
         // See http://jira.codehaus.org/secure/ViewIssue.jspa?key=PICO-115
 144  582
         ComponentAdapter adapterByKey = getComponentAdapter(componentType);
 145  582
         if (adapterByKey != null) {
 146  114
             return adapterByKey;
 147   
         }
 148   
 
 149  468
         List found = getComponentAdaptersOfType(componentType);
 150   
 
 151  468
         if (found.size() == 1) {
 152  98
             return ((ComponentAdapter) found.get(0));
 153  370
         } else if (found.size() == 0) {
 154  368
             if (parent != null) {
 155  5
                 return parent.getComponentAdapterOfType(componentType);
 156   
             } else {
 157  363
                 return null;
 158   
             }
 159   
         } else {
 160  2
             Class[] foundClasses = new Class[found.size()];
 161  2
             for (int i = 0; i < foundClasses.length; i++) {
 162  4
                 ComponentAdapter componentAdapter = (ComponentAdapter) found.get(i);
 163  4
                 foundClasses[i] = componentAdapter.getComponentImplementation();
 164   
             }
 165   
 
 166  2
             throw new AmbiguousComponentResolutionException(componentType, foundClasses);
 167   
         }
 168   
     }
 169   
 
 170  604
     public List getComponentAdaptersOfType(Class componentType) {
 171  604
         List found = new ArrayList();
 172  604
         for (Iterator iterator = getComponentAdapters().iterator(); iterator.hasNext();) {
 173  1371
             ComponentAdapter componentAdapter = (ComponentAdapter) iterator.next();
 174   
 
 175  1371
             if (componentType.isAssignableFrom(componentAdapter.getComponentImplementation())) {
 176  123
                 found.add(componentAdapter);
 177   
             }
 178   
         }
 179  604
         return Collections.unmodifiableList(found);
 180   
     }
 181   
 
 182   
     /**
 183   
      * {@inheritDoc}
 184   
      * This method can be used to override the ComponentAdapter created by the {@link ComponentAdapterFactory}
 185   
      * passed to the constructor of this container.
 186   
      */
 187  264
     public ComponentAdapter registerComponent(ComponentAdapter componentAdapter) throws DuplicateComponentKeyRegistrationException {
 188  264
         Object componentKey = componentAdapter.getComponentKey();
 189  264
         if (componentKeyToAdapterCache.containsKey(componentKey)) {
 190  3
             throw new DuplicateComponentKeyRegistrationException(componentKey);
 191   
         }
 192  261
         componentAdapter.setContainer(this);
 193  261
         componentAdapters.add(componentAdapter);
 194  261
         componentKeyToAdapterCache.put(componentKey, componentAdapter);
 195  261
         return componentAdapter;
 196   
     }
 197   
 
 198  12
     public ComponentAdapter unregisterComponent(Object componentKey) {
 199  12
         ComponentAdapter adapter = (ComponentAdapter) componentKeyToAdapterCache.remove(componentKey);
 200  12
         componentAdapters.remove(adapter);
 201  12
         orderedComponentAdapters.remove(adapter);
 202  12
         return adapter;
 203   
     }
 204   
 
 205   
     /**
 206   
      * {@inheritDoc}
 207   
      * The returned ComponentAdapter will be an {@link InstanceComponentAdapter}.
 208   
      */
 209  8
     public ComponentAdapter registerComponentInstance(Object component) throws PicoRegistrationException {
 210  8
         return registerComponentInstance(component.getClass(), component);
 211   
     }
 212   
 
 213   
     /**
 214   
      * {@inheritDoc}
 215   
      * The returned ComponentAdapter will be an {@link InstanceComponentAdapter}.
 216   
      */
 217  23
     public ComponentAdapter registerComponentInstance(Object componentKey, Object componentInstance) throws PicoRegistrationException {
 218  23
         if (componentInstance == this)
 219  2
             throw new PicoRegistrationException("Cannot register a container to itself. The container is already implicitly registered.");
 220  21
         ComponentAdapter componentAdapter = new InstanceComponentAdapter(componentKey, componentInstance);
 221  19
         registerComponent(componentAdapter);
 222  18
         return componentAdapter;
 223   
     }
 224   
 
 225   
     /**
 226   
      * {@inheritDoc}
 227   
      * The returned ComponentAdapter will be instantiated by the {@link ComponentAdapterFactory}
 228   
      * passed to the container's constructor.
 229   
      */
 230  137
     public ComponentAdapter registerComponentImplementation(Class componentImplementation) throws PicoRegistrationException {
 231  137
         return registerComponentImplementation(componentImplementation, componentImplementation);
 232   
     }
 233   
 
 234   
     /**
 235   
      * {@inheritDoc}
 236   
      * The returned ComponentAdapter will be instantiated by the {@link ComponentAdapterFactory}
 237   
      * passed to the container's constructor.
 238   
      */
 239  189
     public ComponentAdapter registerComponentImplementation(Object componentKey, Class componentImplementation) throws PicoRegistrationException {
 240  189
         return registerComponentImplementation(componentKey, componentImplementation, (Parameter[]) null);
 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  212
     public ComponentAdapter registerComponentImplementation(Object componentKey, Class componentImplementation, Parameter[] parameters) throws PicoRegistrationException {
 249  212
         ComponentAdapter componentAdapter = componentAdapterFactory.createComponentAdapter(componentKey, componentImplementation, parameters);
 250  209
         registerComponent(componentAdapter);
 251  207
         return componentAdapter;
 252   
     }
 253   
 
 254  0
     public ComponentAdapter registerComponentImplementation(Object componentKey, Class componentImplementation, List parameters) throws PicoRegistrationException {
 255  0
         Parameter[] parametersAsArray = (Parameter[]) parameters.toArray(new Parameter[parameters.size()]);
 256  0
         return registerComponentImplementation(componentKey, componentImplementation, parametersAsArray);
 257   
     }
 258   
 
 259  238
     public void addOrderedComponentAdapter(ComponentAdapter componentAdapter) {
 260  238
         if (!orderedComponentAdapters.contains(componentAdapter)) {
 261  135
             orderedComponentAdapters.add(componentAdapter);
 262   
         }
 263   
     }
 264   
 
 265  35
     public List getComponentInstances() throws PicoException {
 266  35
         return getComponentInstancesOfType(null);
 267   
     }
 268   
 
 269  63
     public List getComponentInstancesOfType(Class type) throws PicoException {
 270  63
         Map adapterToInstanceMap = new HashMap();
 271  63
         for (Iterator iterator = componentAdapters.iterator(); iterator.hasNext();) {
 272  122
             ComponentAdapter componentAdapter = (ComponentAdapter) iterator.next();
 273  122
             if (type == null || type.isAssignableFrom(componentAdapter.getComponentImplementation())) {
 274  103
                 Object componentInstance = componentAdapter.getComponentInstance();
 275  103
                 adapterToInstanceMap.put(componentAdapter, componentInstance);
 276   
 
 277   
                 // This is to ensure all are added. (Indirect dependencies will be added
 278   
                 // from InstantiatingComponentAdapter).
 279  103
                 addOrderedComponentAdapter(componentAdapter);
 280   
             }
 281   
         }
 282  63
         List result = new ArrayList();
 283  63
         for (Iterator iterator = orderedComponentAdapters.iterator(); iterator.hasNext();) {
 284  132
             Object componentAdapter = iterator.next();
 285  132
             final Object componentInstance = adapterToInstanceMap.get(componentAdapter);
 286  132
             if (componentInstance != null) {
 287   
                 // may be null in the case of the "implicit" adapter
 288   
                 // representing "this".
 289  103
                 result.add(componentInstance);
 290   
             }
 291   
         }
 292  63
         return Collections.unmodifiableList(result);
 293   
     }
 294   
 
 295  117
     public Object getComponentInstance(Object componentKey) throws PicoException {
 296  117
         ComponentAdapter componentAdapter = getComponentAdapter(componentKey);
 297  117
         if (componentAdapter != null) {
 298  109
             return componentAdapter.getComponentInstance();
 299   
         } else {
 300  8
             return null;
 301   
         }
 302   
     }
 303   
 
 304  12
     public Object getComponentInstanceOfType(Class componentType) {
 305  12
         final ComponentAdapter componentAdapter = getComponentAdapterOfType(componentType);
 306  12
         return componentAdapter == null ? null : componentAdapter.getComponentInstance();
 307   
     }
 308   
 
 309  2
     public PicoContainer getParent() {
 310  2
         return parent;
 311   
     }
 312   
 
 313  0
     public void setParent(PicoContainer parent) {
 314  0
         this.parent = parent;
 315   
     }
 316   
 
 317  1
     public ComponentAdapter unregisterComponentByInstance(Object componentInstance) {
 318  1
         Collection componentAdapters = getComponentAdapters();
 319  2
         for (Iterator iterator = componentAdapters.iterator(); iterator.hasNext();) {
 320  2
             ComponentAdapter componentAdapter = (ComponentAdapter) iterator.next();
 321  2
             if (componentAdapter.getComponentInstance().equals(componentInstance)) {
 322  1
                 return unregisterComponent(componentAdapter.getComponentKey());
 323   
             }
 324   
         }
 325  0
         return null;
 326   
     }
 327   
 
 328  5
     public void verify() throws PicoVerificationException {
 329  5
         List nestedVerificationExceptions = new ArrayList();
 330  5
         for (Iterator iterator = getComponentAdapters().iterator(); iterator.hasNext();) {
 331  10
             ComponentAdapter componentAdapter = (ComponentAdapter) iterator.next();
 332  10
             try {
 333  10
                 componentAdapter.verify();
 334   
             } catch (UnsatisfiableDependenciesException e) {
 335  4
                 nestedVerificationExceptions.add(e);
 336   
             }
 337   
         }
 338   
 
 339  3
         if (!nestedVerificationExceptions.isEmpty()) {
 340  2
             throw new PicoVerificationException(nestedVerificationExceptions);
 341   
         }
 342   
     }
 343   
 
 344  12
     public void start() {
 345  1
         if (started) throw new IllegalStateException("Already started");
 346  0
         if (disposed) throw new IllegalStateException("Already disposed");
 347  11
         List componentInstances = getComponentInstancesOfTypeWithContainerAdaptersLast(Startable.class);
 348  11
         for (Iterator iterator = componentInstances.iterator(); iterator.hasNext();) {
 349  16
             ((Startable) iterator.next()).start();
 350   
         }
 351  11
         started = true;
 352   
     }
 353   
 
 354  11
     public void stop() {
 355  1
         if (!started) throw new IllegalStateException("Not started");
 356  0
         if (disposed) throw new IllegalStateException("Already disposed");
 357  10
         List componentInstances = getComponentInstancesOfTypeWithContainerAdaptersLast(Startable.class);
 358  10
         Collections.reverse(componentInstances);
 359  10
         for (Iterator iterator = componentInstances.iterator(); iterator.hasNext();) {
 360  16
             ((Startable) iterator.next()).stop();
 361   
         }
 362  10
         started = false;
 363   
     }
 364   
 
 365  8
     public void dispose() {
 366  1
         if (disposed) throw new IllegalStateException("Already disposed");
 367  7
         List componentInstances = getComponentInstancesOfTypeWithContainerAdaptersLast(Disposable.class);
 368  7
         Collections.reverse(componentInstances);
 369  7
         for (Iterator iterator = componentInstances.iterator(); iterator.hasNext();) {
 370  13
             ((Disposable) iterator.next()).dispose();
 371   
         }
 372  7
         disposed = true;
 373   
     }
 374   
 
 375  28
     private List getComponentInstancesOfTypeWithContainerAdaptersLast(Class type) {
 376  28
         List result = new ArrayList();
 377  28
         result.addAll(getComponentInstancesOfType(type));
 378  28
         Collections.sort(result, new StackContainersAtEndComparator());
 379  28
         return result;
 380   
     }
 381   
 
 382   
     /**
 383   
      * This comparator makes sure containers are always stacked at the end of the collection,
 384   
      * leaving the order of the others unchanged. This is needed in order to have proper
 385   
      * breadth-first traversal when calling lifecycle methods on container hierarchies.
 386   
      *
 387   
      * @author Aslak Helles&oslash;y
 388   
      * @version $Revision: 1.4 $
 389   
      */
 390   
     class StackContainersAtEndComparator implements Comparator {
 391  24
         public int compare(Object o1, Object o2) {
 392  24
             if (PicoContainer.class.isAssignableFrom(o1.getClass())) {
 393  0
                 return 1;
 394   
             }
 395  24
             if (PicoContainer.class.isAssignableFrom(o2.getClass())) {
 396  3
                 return -1;
 397   
             }
 398  21
             return 0;
 399   
         }
 400   
     }
 401   
 
 402   
 }
 403