Clover coverage report - Code Coverage for hivemind release 1.1-alpha-2
Coverage timestamp: Wed Feb 23 2005 09:59:04 EST
file stats: LOC: 434   Methods: 17
NCLOC: 292   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
BuilderFactoryLogic.java 93.3% 97.1% 100% 96.2%
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.service.impl;
 16   
 
 17   
 import java.lang.reflect.Constructor;
 18   
 import java.lang.reflect.InvocationTargetException;
 19   
 import java.lang.reflect.Method;
 20   
 import java.lang.reflect.Modifier;
 21   
 import java.util.ArrayList;
 22   
 import java.util.Collection;
 23   
 import java.util.Collections;
 24   
 import java.util.Comparator;
 25   
 import java.util.HashSet;
 26   
 import java.util.Iterator;
 27   
 import java.util.List;
 28   
 import java.util.Set;
 29   
 
 30   
 import org.apache.commons.logging.Log;
 31   
 import org.apache.hivemind.ApplicationRuntimeException;
 32   
 import org.apache.hivemind.ErrorHandler;
 33   
 import org.apache.hivemind.HiveMind;
 34   
 import org.apache.hivemind.Location;
 35   
 import org.apache.hivemind.ServiceImplementationFactoryParameters;
 36   
 import org.apache.hivemind.internal.Module;
 37   
 import org.apache.hivemind.service.EventLinker;
 38   
 import org.apache.hivemind.util.ConstructorUtils;
 39   
 import org.apache.hivemind.util.PropertyUtils;
 40   
 
 41   
 /**
 42   
  * Created by {@link org.apache.hivemind.service.impl.BuilderFactory}for each service to be
 43   
  * created; encapsulates all the direct and indirect parameters used to construct a service.
 44   
  * 
 45   
  * @author Howard Lewis Ship
 46   
  */
 47   
 public class BuilderFactoryLogic
 48   
 {
 49   
     /** @since 1.1 */
 50   
     private ServiceImplementationFactoryParameters _factoryParameters;
 51   
 
 52   
     private String _serviceId;
 53   
 
 54   
     private BuilderParameter _parameter;
 55   
 
 56   
     private Log _log;
 57   
 
 58   
     private Module _contributingModule;
 59   
 
 60  464
     public BuilderFactoryLogic(ServiceImplementationFactoryParameters factoryParameters,
 61   
             BuilderParameter parameter)
 62   
     {
 63  464
         _factoryParameters = factoryParameters;
 64  464
         _parameter = parameter;
 65   
 
 66  464
         _log = _factoryParameters.getLog();
 67  464
         _serviceId = factoryParameters.getServiceId();
 68  464
         _contributingModule = factoryParameters.getInvokingModule();
 69   
     }
 70   
 
 71  464
     public Object createService()
 72   
     {
 73  464
         Object result = null;
 74   
 
 75  464
         try
 76   
         {
 77  464
             result = instantiateCoreServiceInstance();
 78   
 
 79  463
             setProperties(result);
 80   
 
 81  463
             registerForEvents(result);
 82   
 
 83  463
             invokeInitializer(result);
 84   
         }
 85   
         catch (Exception ex)
 86   
         {
 87  1
             error(
 88   
                     ServiceMessages.failureBuildingService(_serviceId, ex),
 89   
                     _parameter.getLocation(),
 90   
                     ex);
 91   
         }
 92   
 
 93  464
         return result;
 94   
     }
 95   
 
 96  5
     private void error(String message, Location location, Throwable cause)
 97   
     {
 98  5
         _factoryParameters.getErrorLog().error(message, location, cause);
 99   
     }
 100   
 
 101  464
     private Object instantiateCoreServiceInstance()
 102   
     {
 103  464
         Class serviceClass = _contributingModule.resolveType(_parameter.getClassName());
 104   
 
 105  464
         List parameters = _parameter.getParameters();
 106   
 
 107  464
         if (_parameter.getAutowireServices() && parameters.isEmpty())
 108   
         {
 109  426
             return instantiateConstructorAutowiredInstance(serviceClass);
 110   
         }
 111   
 
 112  38
         return instantiateExplicitConstructorInstance(serviceClass, parameters);
 113   
     }
 114   
 
 115  38
     private Object instantiateExplicitConstructorInstance(Class serviceClass, List builderParameters)
 116   
     {
 117  38
         int numberOfParams = builderParameters.size();
 118  38
         List constructorCandidates = getServiceConstructorsOfLength(serviceClass, numberOfParams);
 119   
 
 120  50
         outer: for (Iterator candidates = constructorCandidates.iterator(); candidates.hasNext();)
 121   
         {
 122  50
             Constructor candidate = (Constructor) candidates.next();
 123   
 
 124  50
             Class[] parameterTypes = candidate.getParameterTypes();
 125   
 
 126  50
             Object[] parameters = new Object[parameterTypes.length];
 127   
 
 128  50
             for (int i = 0; i < numberOfParams; i++)
 129   
             {
 130  49
                 BuilderFacet facet = (BuilderFacet) builderParameters.get(i);
 131   
 
 132  49
                 if (!facet.isAssignableToType(_factoryParameters, parameterTypes[i]))
 133  12
                     continue outer;
 134   
 
 135  37
                 parameters[i] = facet.getFacetValue(_factoryParameters, parameterTypes[i]);
 136   
             }
 137   
 
 138  38
             return ConstructorUtils.invoke(candidate, parameters);
 139   
         }
 140   
 
 141  0
         throw new ApplicationRuntimeException(ServiceMessages.unableToFindAutowireConstructor(),
 142   
                 _parameter.getLocation(), null);
 143   
     }
 144   
 
 145  38
     private List getServiceConstructorsOfLength(Class serviceClass, int length)
 146   
     {
 147  38
         List fixedLengthConstructors = new ArrayList();
 148   
 
 149  38
         Constructor[] constructors = serviceClass.getDeclaredConstructors();
 150   
 
 151  38
         outer: for (int i = 0; i < constructors.length; i++)
 152   
         {
 153  135
             if (!Modifier.isPublic(constructors[i].getModifiers()))
 154  0
                 continue;
 155   
 
 156  135
             Class[] parameterTypes = constructors[i].getParameterTypes();
 157   
 
 158  135
             if (parameterTypes.length != length)
 159  73
                 continue;
 160   
 
 161  62
             fixedLengthConstructors.add(constructors[i]);
 162   
         }
 163   
 
 164  38
         return fixedLengthConstructors;
 165   
     }
 166   
 
 167  426
     private Object instantiateConstructorAutowiredInstance(Class serviceClass)
 168   
     {
 169  426
         List serviceConstructorCandidates = getOrderedServiceConstructors(serviceClass);
 170   
 
 171  426
         outer: for (Iterator candidates = serviceConstructorCandidates.iterator(); candidates
 172   
                 .hasNext();)
 173   
         {
 174  429
             Constructor candidate = (Constructor) candidates.next();
 175   
 
 176  429
             Class[] parameterTypes = candidate.getParameterTypes();
 177   
 
 178  429
             Object[] parameters = new Object[parameterTypes.length];
 179   
 
 180  429
             for (int i = 0; i < parameters.length; i++)
 181   
             {
 182  8
                 BuilderFacet facet = _parameter.getFacetForType(
 183   
                         _factoryParameters,
 184   
                         parameterTypes[i]);
 185   
 
 186  8
                 if (facet != null && facet.canAutowireConstructorParameter())
 187  3
                     parameters[i] = facet.getFacetValue(_factoryParameters, parameterTypes[i]);
 188  5
                 else if (_contributingModule.containsService(parameterTypes[i]))
 189  1
                     parameters[i] = _contributingModule.getService(parameterTypes[i]);
 190   
                 else
 191  4
                     continue outer;
 192   
             }
 193   
 
 194  425
             return ConstructorUtils.invoke(candidate, parameters);
 195   
         }
 196   
 
 197  1
         throw new ApplicationRuntimeException(ServiceMessages.unableToFindAutowireConstructor(),
 198   
                 _parameter.getLocation(), null);
 199   
     }
 200   
 
 201  426
     private List getOrderedServiceConstructors(Class serviceClass)
 202   
     {
 203  426
         List orderedInterfaceConstructors = new ArrayList();
 204   
 
 205  426
         Constructor[] constructors = serviceClass.getDeclaredConstructors();
 206   
 
 207  426
         outer: for (int i = 0; i < constructors.length; i++)
 208   
         {
 209  436
             if (!Modifier.isPublic(constructors[i].getModifiers()))
 210  0
                 continue;
 211   
 
 212  436
             Class[] parameterTypes = constructors[i].getParameterTypes();
 213   
 
 214  436
             if (parameterTypes.length > 0)
 215   
             {
 216  12
                 Set seenTypes = new HashSet();
 217   
 
 218  12
                 for (int j = 0; j < parameterTypes.length; j++)
 219   
                 {
 220  20
                     if (!parameterTypes[j].isInterface() || seenTypes.contains(parameterTypes[j]))
 221  4
                         continue outer;
 222   
 
 223  16
                     seenTypes.add(parameterTypes[j]);
 224   
                 }
 225   
             }
 226   
 
 227  432
             orderedInterfaceConstructors.add(constructors[i]);
 228   
         }
 229   
 
 230  426
         Collections.sort(orderedInterfaceConstructors, new Comparator()
 231   
         {
 232  6
             public int compare(Object o1, Object o2)
 233   
             {
 234  6
                 return ((Constructor) o2).getParameterTypes().length
 235   
                         - ((Constructor) o1).getParameterTypes().length;
 236   
             }
 237   
         });
 238   
 
 239  426
         return orderedInterfaceConstructors;
 240   
     }
 241   
 
 242  463
     private void invokeInitializer(Object service)
 243   
     {
 244  463
         String methodName = _parameter.getInitializeMethod();
 245   
 
 246  463
         boolean allowMissing = HiveMind.isBlank(methodName);
 247   
 
 248  463
         String searchMethodName = allowMissing ? "initializeService" : methodName;
 249   
 
 250  463
         try
 251   
         {
 252  463
             findAndInvokeInitializerMethod(service, searchMethodName, allowMissing);
 253   
         }
 254   
         catch (InvocationTargetException ex)
 255   
         {
 256  1
             Throwable cause = ex.getTargetException();
 257   
 
 258  1
             error(ServiceMessages.unableToInitializeService(_serviceId, searchMethodName, service
 259   
                     .getClass(), cause), _parameter.getLocation(), cause);
 260   
         }
 261   
         catch (Exception ex)
 262   
         {
 263  1
             error(ServiceMessages.unableToInitializeService(_serviceId, searchMethodName, service
 264   
                     .getClass(), ex), _parameter.getLocation(), ex);
 265   
         }
 266   
     }
 267   
 
 268  463
     private void findAndInvokeInitializerMethod(Object service, String methodName,
 269   
             boolean allowMissing) throws IllegalAccessException, InvocationTargetException,
 270   
             NoSuchMethodException
 271   
     {
 272  463
         Class serviceClass = service.getClass();
 273   
 
 274  463
         try
 275   
         {
 276  463
             Method m = serviceClass.getMethod(methodName, null);
 277   
 
 278  52
             m.invoke(service, null);
 279   
         }
 280   
         catch (NoSuchMethodException ex)
 281   
         {
 282  411
             if (allowMissing)
 283  410
                 return;
 284   
 
 285  1
             throw ex;
 286   
         }
 287   
     }
 288   
 
 289  463
     private void registerForEvents(Object result)
 290   
     {
 291  463
         List eventRegistrations = _parameter.getEventRegistrations();
 292   
 
 293  463
         if (eventRegistrations.isEmpty())
 294  460
             return;
 295   
 
 296  3
         EventLinker linker = new EventLinkerImpl(_factoryParameters.getErrorLog());
 297   
 
 298  3
         Iterator i = eventRegistrations.iterator();
 299  3
         while (i.hasNext())
 300   
         {
 301  3
             EventRegistration er = (EventRegistration) i.next();
 302   
 
 303   
             // Will log any errors to the errorHandler
 304   
 
 305  3
             linker.addEventListener(er.getProducer(), er.getEventSetName(), result, er
 306   
                     .getLocation());
 307   
         }
 308   
     }
 309   
 
 310  463
     private void setProperties(Object service)
 311   
     {
 312  463
         List properties = _parameter.getProperties();
 313  463
         int count = properties.size();
 314   
 
 315   
         // Track the writeable properties, removing names as they are wired or autowired.
 316   
 
 317  463
         Set writeableProperties = new HashSet(PropertyUtils.getWriteableProperties(service));
 318   
 
 319  463
         for (int i = 0; i < count; i++)
 320   
         {
 321  3114
             BuilderFacet facet = (BuilderFacet) properties.get(i);
 322   
 
 323  3114
             String propertyName = wireProperty(service, facet);
 324   
 
 325  3114
             if (propertyName != null)
 326  596
                 writeableProperties.remove(propertyName);
 327   
         }
 328   
 
 329  463
         if (_parameter.getAutowireServices())
 330  458
             autowireServices(service, writeableProperties);
 331   
 
 332   
     }
 333   
 
 334   
     /**
 335   
      * Wire (or auto-wire) the property; return the name of the property actually set (if a property
 336   
      * is set, which is not always the case).
 337   
      */
 338  3114
     private String wireProperty(Object service, BuilderFacet facet)
 339   
     {
 340  3114
         String propertyName = facet.getPropertyName();
 341   
 
 342  3114
         try
 343   
         {
 344   
             // Autowire the property (if possible).
 345   
 
 346  3114
             String autowirePropertyName = facet.autowire(service, _factoryParameters);
 347   
 
 348  3114
             if (autowirePropertyName != null)
 349  211
                 return autowirePropertyName;
 350   
 
 351   
             // There will be a facet for log, messages, service-id, etc. even if no
 352   
             // property name is specified, so we skip it here. In many cases, those
 353   
             // facets will have just done an autowire.
 354   
 
 355  2903
             if (propertyName == null)
 356  2516
                 return null;
 357   
 
 358  387
             Class targetType = PropertyUtils.getPropertyType(service, propertyName);
 359   
 
 360  386
             Object value = facet.getFacetValue(_factoryParameters, targetType);
 361   
 
 362  385
             PropertyUtils.write(service, propertyName, value);
 363   
 
 364  385
             if (_log.isDebugEnabled())
 365  9
                 _log.debug("Set property " + propertyName + " to " + value);
 366   
 
 367  385
             return propertyName;
 368   
         }
 369   
         catch (Exception ex)
 370   
         {
 371  2
             error(ex.getMessage(), facet.getLocation(), ex);
 372   
 
 373  2
             return null;
 374   
         }
 375   
     }
 376   
 
 377  458
     private void autowireServices(Object service, Collection propertyNames)
 378   
     {
 379  458
         Iterator i = propertyNames.iterator();
 380  458
         while (i.hasNext())
 381   
         {
 382  261
             String propertyName = (String) i.next();
 383   
 
 384  261
             autowireProperty(service, propertyName);
 385   
         }
 386   
     }
 387   
 
 388  261
     private void autowireProperty(Object service, String propertyName)
 389   
     {
 390  261
         Class propertyType = PropertyUtils.getPropertyType(service, propertyName);
 391   
 
 392   
         // Yes, not all interfaces are services, but there's no real way to be sure.
 393   
         // Moral of the story: don't leave around writeable properties that are interfaces
 394   
         // (and therefore look like services)! A future improvement may be to ignore
 395   
         // properties for which there are no service points. This is why autowiring
 396   
         // can be turned off.
 397   
 
 398  261
         if (!propertyType.isInterface())
 399  10
             return;
 400   
 
 401   
         // Here's the problem with autowiring; there can be other stuff besides
 402   
         // services that are writable; since lots of classes inherite from
 403   
         // BaseLocatable, Location is one of those property types.
 404   
 
 405  251
         if (propertyType.equals(Location.class))
 406  120
             return;
 407   
 
 408  131
         try
 409   
         {
 410  131
             Object collaboratingService = _contributingModule.getService(propertyType);
 411   
 
 412  129
             PropertyUtils.write(service, propertyName, collaboratingService);
 413   
 
 414  129
             if (_log.isDebugEnabled())
 415  0
                 _log.debug("Autowired service property " + propertyName + " to "
 416   
                         + collaboratingService);
 417   
 
 418   
         }
 419   
         catch (Exception ex)
 420   
         {
 421  2
             getErrorHandler().error(
 422   
                     _log,
 423   
                     ServiceMessages.autowirePropertyFailure(propertyName, _serviceId, ex),
 424   
                     _parameter.getLocation(),
 425   
                     ex);
 426   
         }
 427   
     }
 428   
 
 429  2
     private ErrorHandler getErrorHandler()
 430   
     {
 431  2
         return _contributingModule.getErrorHandler();
 432   
     }
 433   
 
 434   
 }