2009/04/15 - Apache HiveMind has been retired.

For more information, please explore the Attic.

Clover coverage report - Code Coverage for hivemind release 1.2.1
Coverage timestamp: Fri Feb 10 2006 16:33:43 PST
file stats: LOC: 420   Methods: 17
NCLOC: 291   Classes: 1
 
 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  790 public BuilderFactoryLogic(ServiceImplementationFactoryParameters factoryParameters,
 61    BuilderParameter parameter)
 62    {
 63  790 _factoryParameters = factoryParameters;
 64  790 _parameter = parameter;
 65   
 66  790 _log = _factoryParameters.getLog();
 67  790 _serviceId = factoryParameters.getServiceId();
 68  790 _contributingModule = factoryParameters.getInvokingModule();
 69    }
 70   
 71  790 public Object createService()
 72    {
 73  790 try
 74    {
 75  790 Object result = instantiateCoreServiceInstance();
 76   
 77  789 setProperties(result);
 78   
 79  789 registerForEvents(result);
 80   
 81  789 invokeInitializer(result);
 82   
 83  789 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  790 private Object instantiateCoreServiceInstance()
 99    {
 100  790 Class serviceClass = _contributingModule.resolveType(_parameter.getClassName());
 101   
 102  790 List parameters = _parameter.getParameters();
 103   
 104  790 if (_parameter.getAutowireServices() && parameters.isEmpty())
 105    {
 106  740 return instantiateConstructorAutowiredInstance(serviceClass);
 107    }
 108   
 109  50 return instantiateExplicitConstructorInstance(serviceClass, parameters);
 110    }
 111   
 112  50 private Object instantiateExplicitConstructorInstance(Class serviceClass, List builderParameters)
 113    {
 114  50 int numberOfParams = builderParameters.size();
 115  50 List constructorCandidates = getServiceConstructorsOfLength(serviceClass, numberOfParams);
 116   
 117  62 outer: for (Iterator candidates = constructorCandidates.iterator(); candidates.hasNext();)
 118    {
 119  62 Constructor candidate = (Constructor) candidates.next();
 120   
 121  62 Class[] parameterTypes = candidate.getParameterTypes();
 122   
 123  62 Object[] parameters = new Object[parameterTypes.length];
 124   
 125  62 for (int i = 0; i < numberOfParams; i++)
 126    {
 127  58 BuilderFacet facet = (BuilderFacet) builderParameters.get(i);
 128   
 129  58 if (!facet.isAssignableToType(_factoryParameters, parameterTypes[i]))
 130  12 continue outer;
 131   
 132  46 parameters[i] = facet.getFacetValue(_factoryParameters, parameterTypes[i]);
 133    }
 134   
 135  50 return ConstructorUtils.invoke(candidate, parameters);
 136    }
 137   
 138  0 throw new ApplicationRuntimeException(ServiceMessages.unableToFindAutowireConstructor(),
 139    _parameter.getLocation(), null);
 140    }
 141   
 142  50 private List getServiceConstructorsOfLength(Class serviceClass, int length)
 143    {
 144  50 List fixedLengthConstructors = new ArrayList();
 145   
 146  50 Constructor[] constructors = serviceClass.getDeclaredConstructors();
 147   
 148  50 outer: for (int i = 0; i < constructors.length; i++)
 149    {
 150  159 if (!Modifier.isPublic(constructors[i].getModifiers()))
 151  0 continue;
 152   
 153  159 Class[] parameterTypes = constructors[i].getParameterTypes();
 154   
 155  159 if (parameterTypes.length != length)
 156  85 continue;
 157   
 158  74 fixedLengthConstructors.add(constructors[i]);
 159    }
 160   
 161  50 return fixedLengthConstructors;
 162    }
 163   
 164  740 private Object instantiateConstructorAutowiredInstance(Class serviceClass)
 165    {
 166  740 List serviceConstructorCandidates = getOrderedServiceConstructors(serviceClass);
 167   
 168  740 outer: for (Iterator candidates = serviceConstructorCandidates.iterator(); candidates
 169    .hasNext();)
 170    {
 171  743 Constructor candidate = (Constructor) candidates.next();
 172   
 173  743 Class[] parameterTypes = candidate.getParameterTypes();
 174   
 175  743 Object[] parameters = new Object[parameterTypes.length];
 176   
 177  743 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  739 return ConstructorUtils.invoke(candidate, parameters);
 192    }
 193   
 194  1 throw new ApplicationRuntimeException(ServiceMessages.unableToFindAutowireConstructor(),
 195    _parameter.getLocation(), null);
 196    }
 197   
 198  740 private List getOrderedServiceConstructors(Class serviceClass)
 199    {
 200  740 List orderedInterfaceConstructors = new ArrayList();
 201   
 202  740 Constructor[] constructors = serviceClass.getDeclaredConstructors();
 203   
 204  740 outer: for (int i = 0; i < constructors.length; i++)
 205    {
 206  753 if (!Modifier.isPublic(constructors[i].getModifiers()))
 207  0 continue;
 208   
 209  753 Class[] parameterTypes = constructors[i].getParameterTypes();
 210   
 211  753 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  749 orderedInterfaceConstructors.add(constructors[i]);
 225    }
 226   
 227  740 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  740 return orderedInterfaceConstructors;
 237    }
 238   
 239  789 private void invokeInitializer(Object service)
 240    {
 241  789 String methodName = _parameter.getInitializeMethod();
 242   
 243  789 boolean allowMissing = HiveMind.isBlank(methodName);
 244   
 245  789 String searchMethodName = allowMissing ? "initializeService" : methodName;
 246   
 247  789 try
 248    {
 249  789 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  789 private void findAndInvokeInitializerMethod(Object service, String methodName,
 266    boolean allowMissing) throws IllegalAccessException, InvocationTargetException,
 267    NoSuchMethodException
 268    {
 269  789 Class serviceClass = service.getClass();
 270   
 271  789 try
 272    {
 273  789 Method m = serviceClass.getMethod(methodName, null);
 274   
 275  312 m.invoke(service, null);
 276    }
 277    catch (NoSuchMethodException ex)
 278    {
 279  477 if (allowMissing)
 280  476 return;
 281   
 282  1 throw ex;
 283    }
 284    }
 285   
 286  789 private void registerForEvents(Object result)
 287    {
 288  789 List eventRegistrations = _parameter.getEventRegistrations();
 289   
 290  789 if (eventRegistrations.isEmpty())
 291  786 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  789 private void setProperties(Object service)
 308    {
 309  789 List properties = _parameter.getProperties();
 310  789 int count = properties.size();
 311   
 312    // Track the writeable properties, removing names as they are wired or autowired.
 313   
 314  789 Set writeableProperties = new HashSet(PropertyUtils.getWriteableProperties(service));
 315   
 316  789 for (int i = 0; i < count; i++)
 317    {
 318  5114 BuilderFacet facet = (BuilderFacet) properties.get(i);
 319   
 320  5113 String propertyName = wireProperty(service, facet);
 321   
 322  5112 if (propertyName != null)
 323  1173 writeableProperties.remove(propertyName);
 324    }
 325   
 326  789 if (_parameter.getAutowireServices())
 327  781 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  5114 private String wireProperty(Object service, BuilderFacet facet)
 336    {
 337  5113 String propertyName = facet.getPropertyName();
 338   
 339  5113 try
 340    {
 341    // Autowire the property (if possible).
 342   
 343  5113 String autowirePropertyName = facet.autowire(service, _factoryParameters);
 344   
 345  5113 if (autowirePropertyName != null)
 346  744 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  4369 if (propertyName == null)
 353  3938 return null;
 354   
 355  431 Class targetType = PropertyUtils.getPropertyType(service, propertyName);
 356   
 357  430 Object value = facet.getFacetValue(_factoryParameters, targetType);
 358   
 359  429 PropertyUtils.write(service, propertyName, value);
 360   
 361  429 if (_log.isDebugEnabled())
 362  9 _log.debug("Set property " + propertyName + " to " + value);
 363   
 364  429 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  781 private void autowireServices(Object service, Collection propertyNames)
 375    {
 376  781 Iterator i = propertyNames.iterator();
 377  781 while (i.hasNext())
 378    {
 379  1060 String propertyName = (String) i.next();
 380   
 381  1060 autowireProperty(service, propertyName);
 382    }
 383    }
 384   
 385  1057 private void autowireProperty(Object service, String propertyName)
 386    {
 387  1060 Class propertyType = PropertyUtils.getPropertyType(service, propertyName);
 388   
 389  1060 try
 390    {
 391    // Ignore properties for which there are no corresponding
 392    // service points...
 393  1060 if( _contributingModule.containsService( propertyType ) )
 394    {
 395  910 Object collaboratingService = _contributingModule.getService(propertyType);
 396  910 PropertyUtils.write(service, propertyName, collaboratingService);
 397   
 398  910 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    }