Clover coverage report - Code Coverage for hivemind release 1.0-beta-1
Coverage timestamp: Sat Jul 3 2004 09:41:37 EDT
file stats: LOC: 257   Methods: 11
NCLOC: 128   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
AbstractServiceInterceptorFactory.java 83.3% 95% 90.9% 93%
coverage coverage
 1   
 //  Copyright 2004 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.service.impl;
 16   
 
 17   
 import java.lang.reflect.Constructor;
 18   
 import java.lang.reflect.Method;
 19   
 import java.util.Collections;
 20   
 import java.util.HashMap;
 21   
 import java.util.List;
 22   
 import java.util.Map;
 23   
 
 24   
 import org.apache.hivemind.ApplicationRuntimeException;
 25   
 import org.apache.hivemind.HiveMindMessages;
 26   
 import org.apache.hivemind.InterceptorStack;
 27   
 import org.apache.hivemind.ServiceInterceptorFactory;
 28   
 import org.apache.hivemind.internal.Module;
 29   
 import org.apache.hivemind.service.ClassFab;
 30   
 import org.apache.hivemind.service.ClassFabUtils;
 31   
 import org.apache.hivemind.service.ClassFactory;
 32   
 import org.apache.hivemind.service.MethodSignature;
 33   
 
 34   
 /**
 35   
  * Base class for creating new service interceptors.  Most implementations
 36   
  * merely have to implement 
 37   
  * {@link #addServiceMethodImplementation(ClassFab, String, Class, Class[], Class[])}.
 38   
  * This is only suitable for interceptors which do not use parameters.
 39   
  * 
 40   
  * <p>
 41   
  * Implementations of this service must be configured with:
 42   
  * <ul>
 43   
  * <li>The service point id assigned to the <code>serviceId</code> property
 44   
  * <li>The <code>hivemind.ClassFactory</code> service assigned to the <code>factory</code> property
 45   
  * </ul>
 46   
  *
 47   
  * @author Howard Lewis Ship
 48   
  */
 49   
 public abstract class AbstractServiceInterceptorFactory implements ServiceInterceptorFactory
 50   
 {
 51   
     private ClassFactory _factory;
 52   
     private String _serviceId;
 53   
     private Map _cachedClasses;
 54   
 
 55   
     {
 56  8
         _cachedClasses = Collections.synchronizedMap(new HashMap());
 57   
     }
 58   
 
 59   
     /**
 60   
      * Creates the interceptor. Expects that the parameters list is empty.
 61   
      * The class that is created is cached; if an interceptor is requested
 62   
      * for the same extension point, then the previously constructed class
 63   
      * is reused (this can happen with the threaded service model, for example,
 64   
      * when a thread-local service implementation is created for different threads).
 65   
      */
 66  10
     public void createInterceptor(
 67   
         InterceptorStack stack,
 68   
         Module contributingModule,
 69   
         List parameters)
 70   
     {
 71  10
         Class serviceInterfaceClass = stack.getServiceInterface();
 72  10
         Class interceptorClass = getInterceptorClass(stack, parameters);
 73   
 
 74  10
         try
 75   
         {
 76  10
             Object interceptor = instantiateInterceptor(stack, interceptorClass, parameters);
 77   
 
 78  10
             stack.push(interceptor);
 79   
         }
 80   
         catch (Exception ex)
 81   
         {
 82  0
             throw new ApplicationRuntimeException(
 83   
                 ServiceMessages.errorInstantiatingInterceptor(
 84   
                     _serviceId,
 85   
                     stack,
 86   
                     interceptorClass,
 87   
                     ex),
 88   
                 ex);
 89   
         }
 90   
     }
 91   
 
 92  10
     private Class getInterceptorClass(InterceptorStack stack, List parameters)
 93   
     {
 94  10
         String id = stack.getServiceExtensionPointId();
 95  10
         Class result = (Class) _cachedClasses.get(id);
 96   
 
 97  10
         if (result != null)
 98  2
             return result;
 99   
 
 100  8
         result = constructInterceptorClass(stack, parameters);
 101   
 
 102  8
         _cachedClasses.put(id, result);
 103   
 
 104  8
         return result;
 105   
     }
 106   
 
 107  8
     private Class constructInterceptorClass(InterceptorStack stack, List parameters)
 108   
     {
 109  8
         Class serviceInterfaceClass = stack.getServiceInterface();
 110  8
         Module module = stack.getServiceModule();
 111   
 
 112  8
         String name = ClassFabUtils.generateClassName("Interceptor");
 113   
 
 114  8
         ClassFab classFab = _factory.newClass(name, getInterceptorSuperclass(), module);
 115   
 
 116  8
         classFab.addInterface(serviceInterfaceClass);
 117   
 
 118  8
         createInfrastructure(stack, classFab, parameters);
 119   
 
 120  8
         addServiceMethods(stack, classFab, parameters);
 121   
 
 122  8
         return classFab.createClass();
 123   
     }
 124   
 
 125   
     /**
 126   
      * Overridden in subclasses to identify the super-class
 127   
      * for the interceptor.  This implementation returns java.lang.Object.
 128   
      */
 129   
 
 130  1
     protected Class getInterceptorSuperclass()
 131   
     {
 132  1
         return Object.class;
 133   
     }
 134   
 
 135   
     /**
 136   
      * Invoked in subclasses to create any infrastructure. 
 137   
      * <p>This implementation adds a field, <code>_inner</code> whose
 138   
      * type is the <em>actual</em> type of the 
 139   
      * {@link InterceptorStack#peek() top object on the stack} (which, of
 140   
      * course, implements the service interface).  A constructor is created
 141   
      * to set the field. 
 142   
      * 
 143   
      * @param stack the interceptor stack (used to obtain the service interface and extension point id)
 144   
      * @param classFab the interceptor class being constructed
 145   
      * @param parameters parameters provided to the interceptor factory 
 146   
      */
 147  1
     protected void createInfrastructure(InterceptorStack stack, ClassFab classFab, List parameters)
 148   
     {
 149  1
         Class topClass = stack.peek().getClass();
 150   
 
 151  1
         classFab.addField("_inner", topClass);
 152  1
         classFab.addConstructor(new Class[] { topClass }, null, "_inner = $1;");
 153   
     }
 154   
 
 155   
     /**
 156   
      * Used to instantiate the interceptor.  This implementation passes the top object
 157   
      * on the interceptor stack to the interceptorClass' constructor. Subclasses that
 158   
      * defined a different constructor (in {@link #createInfrastructure(InterceptorStack, ClassFab)})
 159   
      * will need to override this method as well.
 160   
      * 
 161   
      * @param stack the interceptor stack on which the returned interceptor will be placed.
 162   
      * @param interceptorClass the generated class for the interceptor.
 163   
      * @param the parameters provided to the interceptor
 164   
      * 
 165   
      * @throws Exception if there is an error getting or invoking the constructor
 166   
      * @see #createInfrastructure(InterceptorStack, ClassFab)
 167   
      */
 168  1
     protected Object instantiateInterceptor(
 169   
         InterceptorStack stack,
 170   
         Class interceptorClass,
 171   
         List parameters)
 172   
         throws Exception
 173   
     {
 174   
         // Should only be a single constructor in a custom fabricated class.
 175  1
         Constructor c = interceptorClass.getConstructors()[0];
 176   
 
 177  1
         return c.newInstance(new Object[] { stack.peek()});
 178   
     }
 179   
 
 180   
     /**
 181   
      * Invoked by {@link #addServiceMethods(InterceptorStack, ClassFab, List)}
 182   
      * for each method in the service interface to allow the factory to
 183   
      * construct the corresponding method in the interceptor. This implementation
 184   
      * does nothing, and must be overridden. More sophisticated
 185   
      * interceptors will override <code>addServiceMethods()</code> and may by
 186   
      * implemented in such a way that this method is not invoked. 
 187   
      * 
 188   
      * @param classFab the fabricator for the interceptor class
 189   
      * @param sig the method signature for the method
 190   
      */
 191   
 
 192  0
     protected void addServiceMethodImplementation(
 193   
         ClassFab classFab,
 194   
         MethodSignature sig)
 195   
     {
 196  0
         throw new ApplicationRuntimeException(
 197   
             HiveMindMessages.unimplementedMethod(this, "addServiceMethodImplementation"));
 198   
     }
 199   
 
 200   
     /**
 201   
      * Invoked from {@link #createInterceptor(InterceptorStack, Module, List) to add
 202   
      * the service methods to the interceptor class. This implementation ignores
 203   
      * the parameters, and invokes 
 204   
      * {@link #addServiceMethodImplementation(ClassFab, String, Class, Class[], Class[])}
 205   
      * for each method in the service interface. It also may invoke
 206   
      * {@link #addToStringMethod(InterceptorStack, ClassFab)}.
 207   
      * 
 208   
      * 
 209   
      */
 210  1
     protected void addServiceMethods(InterceptorStack stack, ClassFab fab, List parameters)
 211   
     {
 212  1
         boolean toString = false;
 213  1
         Method[] methods = stack.getServiceInterface().getMethods();
 214   
 
 215  1
         for (int i = 0; i < methods.length; i++)
 216   
         {
 217  1
             Method m = methods[i];
 218   
 
 219  1
             addServiceMethodImplementation(fab, new MethodSignature(m));
 220   
 
 221  1
             toString |= ClassFabUtils.isToString(m);
 222   
         }
 223   
 
 224  1
         if (!toString)
 225  1
             addToStringMethod(stack, fab);
 226   
     }
 227   
 
 228   
     /**
 229   
      * Creates a toString() method that identify the interceptor service id,
 230   
      * the intercepted service id, and the service interface class name).
 231   
      */
 232  7
     protected void addToStringMethod(InterceptorStack stack, ClassFab fab)
 233   
     {
 234  7
         ClassFabUtils.addToStringMethod(
 235   
             fab,
 236   
             "<Interceptor: "
 237   
                 + _serviceId
 238   
                 + " for "
 239   
                 + stack.getServiceExtensionPointId()
 240   
                 + "("
 241   
                 + stack.getServiceInterface().getName()
 242   
                 + ")>");
 243   
 
 244   
     }
 245   
 
 246  8
     public void setServiceId(String string)
 247   
     {
 248  8
         _serviceId = string;
 249   
     }
 250   
 
 251  8
     public void setFactory(ClassFactory factory)
 252   
     {
 253  8
         _factory = factory;
 254   
     }
 255   
 
 256   
 }
 257