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