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