Clover coverage report - PicoContainer - 1.0-beta-1
Coverage timestamp: Thu Aug 14 2003 23:16:27 BST
file stats: LOC: 168   Methods: 5
NCLOC: 110   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
DefaultCompositeProxyFactory.java 100% 100% 100% 100%
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.html file.                                                    *
 7   
  *                                                                           *
 8   
  * Idea by Rachel Davies, Original code by Aslak Hellesoy                    *
 9   
  *****************************************************************************/
 10   
 
 11   
 package org.picocontainer.defaults;
 12   
 
 13   
 import org.picocontainer.extras.CompositeProxyFactory;
 14   
 
 15   
 import java.util.List;
 16   
 import java.util.ArrayList;
 17   
 import java.util.Collections;
 18   
 import java.util.Set;
 19   
 import java.util.HashSet;
 20   
 import java.util.Arrays;
 21   
 import java.util.Iterator;
 22   
 import java.lang.reflect.Proxy;
 23   
 import java.lang.reflect.InvocationHandler;
 24   
 import java.lang.reflect.Method;
 25   
 import java.lang.reflect.InvocationTargetException;
 26   
 import java.io.Serializable;
 27   
 
 28   
 /**
 29   
  *
 30   
  * @author Aslak Hellesøy
 31   
  * @version $Revision: 1.1 $
 32   
  */
 33   
 public class DefaultCompositeProxyFactory implements CompositeProxyFactory, Serializable {
 34   
 
 35   
     private static Method equals;
 36   
     private static Method hashCode;
 37   
 
 38   
     static {
 39  14
         try {
 40  14
             equals = Object.class.getMethod("equals", new Class[]{Object.class});
 41  14
             hashCode = Object.class.getMethod("hashCode", null);
 42   
         } catch (NoSuchMethodException e) {
 43   
             ///CLOVER:OFF
 44   
             throw new InternalError();
 45   
             ///CLOVER:ON
 46   
         } catch (SecurityException e) {
 47   
             ///CLOVER:OFF
 48   
             throw new InternalError();
 49   
             ///CLOVER:ON
 50   
         }
 51   
     }
 52   
 
 53  57
     public Object createCompositeProxy(
 54   
             ClassLoader classLoader,
 55   
             List objectsToAggregateCallFor,
 56   
             boolean callInReverseOrder
 57   
             ) {
 58  57
         Class[] interfaces = getInterfaces(objectsToAggregateCallFor);
 59  57
         List copy = new ArrayList(objectsToAggregateCallFor);
 60   
 
 61  57
         if (!callInReverseOrder) {
 62   
             // reverse the list
 63  35
             Collections.reverse(copy);
 64   
         }
 65  57
         Object[] objects = copy.toArray();
 66   
 
 67  57
         Object result = Proxy.newProxyInstance(
 68   
                 classLoader,
 69   
                 interfaces,
 70   
                 new AggregatingInvocationHandler(classLoader, objects)
 71   
         );
 72   
 
 73  57
         return result;
 74   
     }
 75   
 
 76   
     private class AggregatingInvocationHandler implements InvocationHandler {
 77   
         private Object[] children;
 78   
         private ClassLoader classLoader;
 79   
 
 80  57
         public AggregatingInvocationHandler(ClassLoader classLoader, Object[] children) {
 81  57
             this.classLoader = classLoader;
 82  57
             this.children = children;
 83   
         }
 84   
 
 85  28
         public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
 86  28
             Class declaringClass = method.getDeclaringClass();
 87  28
             if (declaringClass.equals(Object.class)) {
 88  5
                 if (method.equals(hashCode)) {
 89   
                     // Return the hashCode of ourself, as Proxy.newProxyInstance() may
 90   
                     // return cached proxies. We want a unique hashCode for each created proxy!
 91  2
                     return new Integer(System.identityHashCode(AggregatingInvocationHandler.this));
 92   
                 }
 93  3
                 if (method.equals(equals)) {
 94  2
                     return new Boolean(proxy == args[0]);
 95   
                 }
 96   
                 // If the method is defined by Object (like hashCode or equals), call
 97   
                 // on ourself. This is a bit of a hack, but actually ok in most cases.
 98  1
                 return method.invoke(AggregatingInvocationHandler.this, args);
 99   
             } else {
 100  23
                 return invokeOnTargetsOfSameTypeAsDeclaringClass(declaringClass, children, method, args);
 101   
             }
 102   
         }
 103   
 
 104  23
         private Object invokeOnTargetsOfSameTypeAsDeclaringClass(Class declaringClass, Object[] targets, Method method, Object[] args) throws IllegalAccessException, InvocationTargetException, InstantiationException {
 105  23
             Class returnType = method.getReturnType();
 106   
 
 107   
             // Lazily created list holding all results.
 108  23
             List results = null;
 109  23
             for (int i = 0; i < targets.length; i++) {
 110  69
                 boolean isValidType = declaringClass.isAssignableFrom(targets[i].getClass());
 111  69
                 if (isValidType) {
 112   
                     // It's ok to call the method on this one
 113  50
                     Object componentResult = method.invoke(targets[i], args);
 114  50
                     if (results == null) {
 115  23
                         results = new ArrayList();
 116   
                     }
 117  50
                     results.add(componentResult);
 118   
                 }
 119   
             }
 120   
 
 121  23
             Object result;
 122   
 
 123  23
             if (results.size() == 1) {
 124   
                 // Got exactly one result. Just return that.
 125  9
                 result = results.get(0);
 126  14
             } else if (returnType.isInterface()) {
 127   
                 // We have two or more results
 128   
                 // We can make a new proxy that aggregates all the results.
 129   
                 //Class[] resultInterfaces = getInterfaces(results.toArray());
 130  1
                 result = createCompositeProxy(
 131   
                         classLoader,
 132   
                         results,
 133   
                         true
 134   
                 );
 135   
             } else {
 136   
                 // Got multiple results that can't be wrapped in a proxy. Try to instantiate a default object.
 137  13
                 result = returnType.equals(Void.TYPE) ? null : returnType.newInstance();
 138   
             }
 139   
 
 140  22
             return result;
 141   
         }
 142   
     }
 143   
 
 144   
     /**
 145   
      * Get all the interfaces implemented by an array of objects.
 146   
      * @return an array of interfaces.
 147   
      */
 148  57
     private final Class[] getInterfaces(List objects) {
 149  57
         Set interfaces = new HashSet();
 150  57
         for (Iterator iterator = objects.iterator(); iterator.hasNext();) {
 151  132
             Object o = iterator.next();
 152  132
             Class componentClass = o.getClass();
 153   
             // Strangely enough Class.getInterfaces() does not include the interfaces
 154   
             // implemented by superclasses. So we must loop up the hierarchy.
 155  132
             while (componentClass != null) {
 156  280
                 Class[] implemeted = componentClass.getInterfaces();
 157  280
                 List implementedList = Arrays.asList(implemeted);
 158  280
                 interfaces.addAll(implementedList);
 159  280
                 componentClass = componentClass.getSuperclass();
 160   
             }
 161   
         }
 162   
 
 163  57
         Class[] result = (Class[]) interfaces.toArray(new Class[interfaces.size()]);
 164  57
         return result;
 165   
     }
 166   
 
 167   
 }
 168