Clover coverage report - Code Coverage for hivemind release 1.1-beta-1
Coverage timestamp: Thu Apr 28 2005 19:53:41 EDT
file stats: LOC: 420   Methods: 17
NCLOC: 291   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.1% 95.5% 94.1% 94.7%
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  499
     public BuilderFactoryLogic(ServiceImplementationFactoryParameters factoryParameters,
 61   
             BuilderParameter parameter)
 62   
     {
 63  499
         _factoryParameters = factoryParameters;
 64  499
         _parameter = parameter;
 65   
 
 66  499
         _log = _factoryParameters.getLog();
 67  499
         _serviceId = factoryParameters.getServiceId();
 68  499
         _contributingModule = factoryParameters.getInvokingModule();
 69   
     }
 70   
 
 71  499
     public Object createService()
 72   
     {
 73  499
         try
 74   
         {
 75  499
             Object result = instantiateCoreServiceInstance();
 76   
 
 77  498
             setProperties(result);
 78   
 
 79  498
             registerForEvents(result);
 80   
 
 81  498
             invokeInitializer(result);
 82   
 
 83  498
             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  499
     private Object instantiateCoreServiceInstance()
 99   
     {
 100  499
         Class serviceClass = _contributingModule.resolveType(_parameter.getClassName());
 101   
 
 102  499
         List parameters = _parameter.getParameters();
 103   
 
 104  499
         if (_parameter.getAutowireServices() && parameters.isEmpty())
 105   
         {
 106  452
             return instantiateConstructorAutowiredInstance(serviceClass);
 107   
         }
 108   
 
 109  47
         return instantiateExplicitConstructorInstance(serviceClass, parameters);
 110   
     }
 111   
 
 112  47
     private Object instantiateExplicitConstructorInstance(Class serviceClass, List builderParameters)
 113   
     {
 114  47
         int numberOfParams = builderParameters.size();
 115  47
         List constructorCandidates = getServiceConstructorsOfLength(serviceClass, numberOfParams);
 116   
 
 117  59
         outer: for (Iterator candidates = constructorCandidates.iterator(); candidates.hasNext();)
 118   
         {
 119  59
             Constructor candidate = (Constructor) candidates.next();
 120   
 
 121  59
             Class[] parameterTypes = candidate.getParameterTypes();
 122   
 
 123  59
             Object[] parameters = new Object[parameterTypes.length];
 124   
 
 125  59
             for (int i = 0; i < numberOfParams; i++)
 126   
             {
 127  55
                 BuilderFacet facet = (BuilderFacet) builderParameters.get(i);
 128   
 
 129  55
                 if (!facet.isAssignableToType(_factoryParameters, parameterTypes[i]))
 130  12
                     continue outer;
 131   
 
 132  43
                 parameters[i] = facet.getFacetValue(_factoryParameters, parameterTypes[i]);
 133   
             }
 134   
 
 135  47
             return ConstructorUtils.invoke(candidate, parameters);
 136   
         }
 137   
 
 138  0
         throw new ApplicationRuntimeException(ServiceMessages.unableToFindAutowireConstructor(),
 139   
                 _parameter.getLocation(), null);
 140   
     }
 141   
 
 142  47
     private List getServiceConstructorsOfLength(Class serviceClass, int length)
 143   
     {
 144  47
         List fixedLengthConstructors = new ArrayList();
 145   
 
 146  47
         Constructor[] constructors = serviceClass.getDeclaredConstructors();
 147   
 
 148  47
         outer: for (int i = 0; i < constructors.length; i++)
 149   
         {
 150  153
             if (!Modifier.isPublic(constructors[i].getModifiers()))
 151  0
                 continue;
 152   
 
 153  153
             Class[] parameterTypes = constructors[i].getParameterTypes();
 154   
 
 155  153
             if (parameterTypes.length != length)
 156  82
                 continue;
 157   
 
 158  71
             fixedLengthConstructors.add(constructors[i]);
 159   
         }
 160   
 
 161  47
         return fixedLengthConstructors;
 162   
     }
 163   
 
 164  452
     private Object instantiateConstructorAutowiredInstance(Class serviceClass)
 165   
     {
 166  452
         List serviceConstructorCandidates = getOrderedServiceConstructors(serviceClass);
 167   
 
 168  452
         outer: for (Iterator candidates = serviceConstructorCandidates.iterator(); candidates
 169   
                 .hasNext();)
 170   
         {
 171  455
             Constructor candidate = (Constructor) candidates.next();
 172   
 
 173  455
             Class[] parameterTypes = candidate.getParameterTypes();
 174   
 
 175  455
             Object[] parameters = new Object[parameterTypes.length];
 176   
 
 177  455
             for (int i = 0; i < parameters.length; i++)
 178   
             {
 179  11
                 BuilderFacet facet = _parameter.getFacetForType(
 180   
                         _factoryParameters,
 181   
                         parameterTypes[i]);
 182   
 
 183  11
                 if (facet != null && facet.canAutowireConstructorParameter())
 184  3
                     parameters[i] = facet.getFacetValue(_factoryParameters, parameterTypes[i]);
 185  8
                 else if (_contributingModule.containsService(parameterTypes[i]))
 186  4
                     parameters[i] = _contributingModule.getService(parameterTypes[i]);
 187   
                 else
 188  4
                     continue outer;
 189   
             }
 190   
 
 191  451
             return ConstructorUtils.invoke(candidate, parameters);
 192   
         }
 193   
 
 194  1
         throw new ApplicationRuntimeException(ServiceMessages.unableToFindAutowireConstructor(),
 195   
                 _parameter.getLocation(), null);
 196   
     }
 197   
 
 198  452
     private List getOrderedServiceConstructors(Class serviceClass)
 199   
     {
 200  452
         List orderedInterfaceConstructors = new ArrayList();
 201   
 
 202  452
         Constructor[] constructors = serviceClass.getDeclaredConstructors();
 203   
 
 204  452
         outer: for (int i = 0; i < constructors.length; i++)
 205   
         {
 206  465
             if (!Modifier.isPublic(constructors[i].getModifiers()))
 207  0
                 continue;
 208   
 
 209  465
             Class[] parameterTypes = constructors[i].getParameterTypes();
 210   
 
 211  465
             if (parameterTypes.length > 0)
 212   
             {
 213  15
                 Set seenTypes = new HashSet();
 214   
 
 215  15
                 for (int j = 0; j < parameterTypes.length; j++)
 216   
                 {
 217  23
                     if (!parameterTypes[j].isInterface() || seenTypes.contains(parameterTypes[j]))
 218  4
                         continue outer;
 219   
 
 220  19
                     seenTypes.add(parameterTypes[j]);
 221   
                 }
 222   
             }
 223   
 
 224  461
             orderedInterfaceConstructors.add(constructors[i]);
 225   
         }
 226   
 
 227  452
         Collections.sort(orderedInterfaceConstructors, new Comparator()
 228   
         {
 229  9
             public int compare(Object o1, Object o2)
 230   
             {
 231  9
                 return ((Constructor) o2).getParameterTypes().length
 232   
                         - ((Constructor) o1).getParameterTypes().length;
 233   
             }
 234   
         });
 235   
 
 236  452
         return orderedInterfaceConstructors;
 237   
     }
 238   
 
 239  498
     private void invokeInitializer(Object service)
 240   
     {
 241  498
         String methodName = _parameter.getInitializeMethod();
 242   
 
 243  498
         boolean allowMissing = HiveMind.isBlank(methodName);
 244   
 
 245  498
         String searchMethodName = allowMissing ? "initializeService" : methodName;
 246   
 
 247  498
         try
 248   
         {
 249  498
             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  498
     private void findAndInvokeInitializerMethod(Object service, String methodName,
 266   
             boolean allowMissing) throws IllegalAccessException, InvocationTargetException,
 267   
             NoSuchMethodException
 268   
     {
 269  498
         Class serviceClass = service.getClass();
 270   
 
 271  498
         try
 272   
         {
 273  498
             Method m = serviceClass.getMethod(methodName, null);
 274   
 
 275  51
             m.invoke(service, null);
 276   
         }
 277   
         catch (NoSuchMethodException ex)
 278   
         {
 279  447
             if (allowMissing)
 280  446
                 return;
 281   
 
 282  1
             throw ex;
 283   
         }
 284   
     }
 285   
 
 286  498
     private void registerForEvents(Object result)
 287   
     {
 288  498
         List eventRegistrations = _parameter.getEventRegistrations();
 289   
 
 290  498
         if (eventRegistrations.isEmpty())
 291  495
             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  498
     private void setProperties(Object service)
 308   
     {
 309  498
         List properties = _parameter.getProperties();
 310  498
         int count = properties.size();
 311   
 
 312   
         // Track the writeable properties, removing names as they are wired or autowired.
 313   
 
 314  498
         Set writeableProperties = new HashSet(PropertyUtils.getWriteableProperties(service));
 315   
 
 316  498
         for (int i = 0; i < count; i++)
 317   
         {
 318  3346
             BuilderFacet facet = (BuilderFacet) properties.get(i);
 319   
 
 320  3346
             String propertyName = wireProperty(service, facet);
 321   
 
 322  3346
             if (propertyName != null)
 323  623
                 writeableProperties.remove(propertyName);
 324   
         }
 325   
 
 326  498
         if (_parameter.getAutowireServices())
 327  490
             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  3346
     private String wireProperty(Object service, BuilderFacet facet)
 336   
     {
 337  3346
         String propertyName = facet.getPropertyName();
 338   
 
 339  3346
         try
 340   
         {
 341   
             // Autowire the property (if possible).
 342   
 
 343  3346
             String autowirePropertyName = facet.autowire(service, _factoryParameters);
 344   
 
 345  3346
             if (autowirePropertyName != null)
 346  216
                 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  3130
             if (propertyName == null)
 353  2721
                 return null;
 354   
 
 355  409
             Class targetType = PropertyUtils.getPropertyType(service, propertyName);
 356   
 
 357  408
             Object value = facet.getFacetValue(_factoryParameters, targetType);
 358   
 
 359  407
             PropertyUtils.write(service, propertyName, value);
 360   
 
 361  407
             if (_log.isDebugEnabled())
 362  9
                 _log.debug("Set property " + propertyName + " to " + value);
 363   
 
 364  407
             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  490
     private void autowireServices(Object service, Collection propertyNames)
 375   
     {
 376  490
         Iterator i = propertyNames.iterator();
 377  490
         while (i.hasNext())
 378   
         {
 379  269
             String propertyName = (String) i.next();
 380   
 
 381  269
             autowireProperty(service, propertyName);
 382   
         }
 383   
     }
 384   
 
 385  269
     private void autowireProperty(Object service, String propertyName)
 386   
     {
 387  269
         Class propertyType = PropertyUtils.getPropertyType(service, propertyName);
 388   
 
 389  269
         try
 390   
         {
 391   
             // Ignore properties for which there are no corresponding
 392   
             // service points...
 393  269
             if( _contributingModule.containsService( propertyType ) )
 394   
             {
 395  127
                 Object collaboratingService = _contributingModule.getService(propertyType);
 396  127
                 PropertyUtils.write(service, propertyName, collaboratingService);
 397   
             
 398  127
                 if (_log.isDebugEnabled())
 399   
                 {
 400  0
                     _log.debug("Autowired service property " + propertyName + " to "
 401   
                         + collaboratingService);
 402   
                 }
 403   
             }
 404   
         }
 405   
         catch (Exception ex)
 406   
         {
 407  0
             getErrorHandler().error(
 408   
                     _log,
 409   
                     ServiceMessages.autowirePropertyFailure(propertyName, _serviceId, ex),
 410   
                     _parameter.getLocation(),
 411   
                     ex);
 412   
         }
 413   
     }
 414   
 
 415  0
     private ErrorHandler getErrorHandler()
 416   
     {
 417  0
         return _contributingModule.getErrorHandler();
 418   
     }
 419   
 
 420   
 }