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