Clover coverage report - Code Coverage for hivemind-lib release 1.1-alpha-2
Coverage timestamp: Wed Feb 23 2005 10:00:02 EST
file stats: LOC: 228   Methods: 5
NCLOC: 99   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
AdapterRegistryImpl.java 90% 95.1% 100% 93.8%
coverage coverage
 1   
 // Copyright 2004, 2005 The Apache Software Foundation
 2   
 //
 3   
 // Licensed under the Apache License, Version 2.0 (the "License");
 4   
 // you may not use this file except in compliance with the License.
 5   
 // You may obtain a copy of the License at
 6   
 //
 7   
 //     http://www.apache.org/licenses/LICENSE-2.0
 8   
 //
 9   
 // Unless required by applicable law or agreed to in writing, software
 10   
 // distributed under the License is distributed on an "AS IS" BASIS,
 11   
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 12   
 // See the License for the specific language governing permissions and
 13   
 // limitations under the License.
 14   
 
 15   
 package org.apache.hivemind.lib.util;
 16   
 
 17   
 import java.util.HashMap;
 18   
 import java.util.Iterator;
 19   
 import java.util.LinkedList;
 20   
 import java.util.Map;
 21   
 import java.util.WeakHashMap;
 22   
 
 23   
 import org.apache.hivemind.service.ClassFabUtils;
 24   
 import org.apache.hivemind.util.Defense;
 25   
 
 26   
 /**
 27   
  * Thread-safe implementation of {@link org.apache.hivemind.lib.util.AdapterRegistry}.
 28   
  * 
 29   
  * @author Howard Lewis Ship
 30   
  * @since 1.1
 31   
  */
 32   
 
 33   
 public class AdapterRegistryImpl implements AdapterRegistry
 34   
 {
 35   
     /**
 36   
      * A Map of adaptor objects, keyed on registration Class.
 37   
      */
 38   
 
 39   
     private Map _registrations = new HashMap();
 40   
 
 41   
     /**
 42   
      * A Map of adaptor objects, keyed on subject Class.
 43   
      */
 44   
 
 45   
     private Map _cache = new WeakHashMap();
 46   
 
 47  104
     public synchronized void register(Class registrationClass, Object adaptor)
 48   
     {
 49  104
         Defense.notNull(registrationClass, "registrationClass");
 50  104
         Defense.notNull(adaptor, "adaptor");
 51   
 
 52  104
         if (_registrations.containsKey(registrationClass))
 53  1
             throw new IllegalArgumentException(UtilMessages
 54   
                     .duplicateRegistration(registrationClass));
 55   
 
 56  103
         _registrations.put(registrationClass, adaptor);
 57   
 
 58   
         // Can't tell what is and isn't valid in the cache.
 59   
         // Also, normally all registrations occur before any adaptors
 60   
         // are searched for, so this is not a big deal.
 61   
 
 62  103
         _cache.clear();
 63   
     }
 64   
 
 65  13
     public synchronized Object getAdapter(Class subjectClass)
 66   
     {
 67  13
         Defense.notNull(subjectClass, "subjectClass");
 68   
 
 69  13
         Object result = _cache.get(subjectClass);
 70   
 
 71  13
         if (result != null)
 72  0
             return result;
 73   
 
 74  13
         result = searchForAdaptor(subjectClass);
 75   
 
 76   
         // Record the result in the cache
 77   
 
 78  12
         _cache.put(subjectClass, result);
 79   
 
 80  12
         return result;
 81   
     }
 82   
 
 83   
     /**
 84   
      * Searches the registration Map for a match, based on inheritance.
 85   
      * <p>
 86   
      * Searches class inheritance first, then interfaces (in a rather vague order). Really should
 87   
      * match the order from the JVM spec.
 88   
      * <p>
 89   
      * There's a degenerate case where we may check the same interface more than once:
 90   
      * <ul>
 91   
      * <li>Two interfaces, I1 and I2
 92   
      * <li>Two classes, C1 and C2
 93   
      * <li>I2 extends I1
 94   
      * <li>C2 extends C1
 95   
      * <li>C1 implements I1
 96   
      * <li>C2 implements I2
 97   
      * <li>The search will be: C2, C1, I2, I1, I1
 98   
      * <li>I1 is searched twice, because C1 implements it, and I2 extends it
 99   
      * <li>There are other such cases, but none of them cause infinite loops and most are rare (we
 100   
      * could guard against it, but its relatively expensive).
 101   
      * <li>Multiple checks only occur if we don't find a registration
 102   
      * </ul>
 103   
      * <p>
 104   
      * This method is only called from a synchronized block, so it is implicitly synchronized.
 105   
      */
 106   
 
 107  13
     private Object searchForAdaptor(Class subjectClass)
 108   
     {
 109  13
         LinkedList queue = null;
 110  13
         Object result = null;
 111   
 
 112   
         // Step one: work up through the class inheritance.
 113   
 
 114  13
         Class searchClass = subjectClass;
 115   
 
 116   
         // Primitive types have null, not Object, as their parent
 117   
         // class.
 118   
 
 119  13
         while (searchClass != Object.class && searchClass != null)
 120   
         {
 121  17
             result = _registrations.get(searchClass);
 122  17
             if (result != null)
 123  6
                 return result;
 124   
 
 125   
             // Not an exact match. If the search class
 126   
             // implements any interfaces, add them to the queue.
 127   
 
 128  11
             Class[] interfaces = searchClass.getInterfaces();
 129  11
             int length = interfaces.length;
 130   
 
 131  11
             if (queue == null && length > 0)
 132  6
                 queue = new LinkedList();
 133   
 
 134  11
             for (int i = 0; i < length; i++)
 135  9
                 queue.addLast(interfaces[i]);
 136   
 
 137   
             // Advance up to the next superclass
 138   
 
 139  11
             searchClass = getSuperclass(searchClass);
 140   
 
 141   
         }
 142   
 
 143   
         // Ok, the easy part failed, lets start searching
 144   
         // interfaces.
 145   
 
 146  7
         if (queue != null)
 147   
         {
 148  5
             while (!queue.isEmpty())
 149   
             {
 150  7
                 searchClass = (Class) queue.removeFirst();
 151   
 
 152  7
                 result = _registrations.get(searchClass);
 153  7
                 if (result != null)
 154  2
                     return result;
 155   
 
 156   
                 // Interfaces can extend other interfaces; add them
 157   
                 // to the queue.
 158   
 
 159  5
                 Class[] interfaces = searchClass.getInterfaces();
 160  5
                 int length = interfaces.length;
 161   
 
 162  5
                 for (int i = 0; i < length; i++)
 163  0
                     queue.addLast(interfaces[i]);
 164   
             }
 165   
         }
 166   
 
 167   
         // Not a match on interface; our last gasp is to check
 168   
         // for a registration for java.lang.Object
 169   
 
 170  5
         result = _registrations.get(Object.class);
 171  5
         if (result != null)
 172  4
             return result;
 173   
 
 174   
         // No match? That's rare ... and an error.
 175   
 
 176  1
         throw new IllegalArgumentException(UtilMessages.adapterNotFound(subjectClass));
 177   
     }
 178   
 
 179   
     /**
 180   
      * Returns the superclass of the given class, with a single tweak: If the search class is an
 181   
      * array class, and the component type is an object class (but not Object), then the simple
 182   
      * Object array class is returned. This reflects the fact that an array of any class may be
 183   
      * assignable to <code>Object[]</code>, even though the superclass of an array is always
 184   
      * simply <code>Object</code>.
 185   
      */
 186   
 
 187  11
     private Class getSuperclass(Class searchClass)
 188   
     {
 189  11
         if (searchClass.isArray())
 190   
         {
 191  2
             Class componentType = searchClass.getComponentType();
 192   
 
 193  2
             if (!componentType.isPrimitive() && componentType != Object.class)
 194  1
                 return Object[].class;
 195   
         }
 196   
 
 197  10
         return searchClass.getSuperclass();
 198   
     }
 199   
 
 200  1
     public synchronized String toString()
 201   
     {
 202  1
         StringBuffer buffer = new StringBuffer();
 203  1
         buffer.append("AdaptorRegistry[");
 204   
 
 205  1
         Iterator i = _registrations.entrySet().iterator();
 206  1
         boolean showSep = false;
 207   
 
 208  1
         while (i.hasNext())
 209   
         {
 210  1
             if (showSep)
 211  0
                 buffer.append(' ');
 212   
 
 213  1
             Map.Entry entry = (Map.Entry) i.next();
 214   
 
 215  1
             Class registeredClass = (Class) entry.getKey();
 216   
 
 217  1
             buffer.append(ClassFabUtils.getJavaClassName(registeredClass));
 218  1
             buffer.append("=");
 219  1
             buffer.append(entry.getValue());
 220   
 
 221  1
             showSep = true;
 222   
         }
 223   
 
 224  1
         buffer.append("]");
 225   
 
 226  1
         return buffer.toString();
 227   
     }
 228   
 }