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

For more information, please explore the Attic.

Clover coverage report - Code Coverage for hivemind-lib release 1.2.1
Coverage timestamp: Fri Feb 10 2006 16:34:07 PST
file stats: LOC: 195   Methods: 7
NCLOC: 115   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
StrategyFactory.java 90% 97.6% 100% 96.6%
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.lib.strategy;
 16   
 17    import java.lang.reflect.Constructor;
 18    import java.lang.reflect.Modifier;
 19    import java.util.Iterator;
 20    import java.util.List;
 21   
 22    import org.apache.hivemind.ApplicationRuntimeException;
 23    import org.apache.hivemind.HiveMind;
 24    import org.apache.hivemind.ServiceImplementationFactory;
 25    import org.apache.hivemind.ServiceImplementationFactoryParameters;
 26    import org.apache.hivemind.lib.util.StrategyRegistry;
 27    import org.apache.hivemind.lib.util.StrategyRegistryImpl;
 28    import org.apache.hivemind.service.ClassFab;
 29    import org.apache.hivemind.service.ClassFabUtils;
 30    import org.apache.hivemind.service.ClassFactory;
 31    import org.apache.hivemind.service.MethodIterator;
 32    import org.apache.hivemind.service.MethodSignature;
 33   
 34    /**
 35    * Implementation of the <code>hivemind.lib.StrategyFactory</code> service that constructs a
 36    * service where the first parameter of each method is used to selecte a strategy from an
 37    * {@link org.apache.hivemind.lib.util.StrategyRegistry}. The method invocation is then delegated
 38    * to the strategy instance.
 39    * <p>
 40    * The service factory parameter defines a configuration (of
 41    * {@link org.apache.hivemind.lib.strategy.StrategyContribution}s) that provide the mapping from
 42    * Java classes (or interfaces) to adapter instances.
 43    *
 44    * @author Howard M. Lewis Ship
 45    * @since 1.1
 46    */
 47    public class StrategyFactory implements ServiceImplementationFactory
 48    {
 49    private ClassFactory _classFactory;
 50   
 51  1 public Object createCoreServiceImplementation(
 52    ServiceImplementationFactoryParameters factoryParameters)
 53    {
 54  1 StrategyRegistry ar = new StrategyRegistryImpl();
 55   
 56  1 buildRegistry(factoryParameters, ar);
 57   
 58  1 Class implClass = buildImplementationClass(factoryParameters);
 59   
 60  1 try
 61    {
 62  1 Constructor c = implClass.getConstructors()[0];
 63   
 64  1 return c.newInstance(new Object[]
 65    { ar });
 66    }
 67    catch (Exception ex)
 68    {
 69  0 throw new ApplicationRuntimeException(ex.getMessage(), HiveMind
 70    .getLocation(factoryParameters.getFirstParameter()), ex);
 71    }
 72   
 73    }
 74   
 75    // package private for testing purposes
 76   
 77  3 void buildRegistry(ServiceImplementationFactoryParameters factoryParameters, StrategyRegistry ar)
 78    {
 79  3 Class serviceInterface = factoryParameters.getServiceInterface();
 80   
 81  3 StrategyParameter p = (StrategyParameter) factoryParameters.getFirstParameter();
 82   
 83  3 List contributions = p.getContributions();
 84   
 85  3 Iterator i = contributions.iterator();
 86   
 87  3 while (i.hasNext())
 88    {
 89  3 StrategyContribution c = (StrategyContribution) i.next();
 90   
 91  3 try
 92    {
 93  3 Object adapter = c.getStrategy();
 94   
 95  3 if (!serviceInterface.isAssignableFrom(adapter.getClass()))
 96  1 throw new ClassCastException(StrategyMessages.strategyWrongInterface(adapter, c
 97    .getRegisterClass(), serviceInterface));
 98   
 99  2 ar.register(c.getRegisterClass(), adapter);
 100    }
 101    catch (Exception ex)
 102    {
 103  1 factoryParameters.getErrorLog().error(ex.getMessage(), c.getLocation(), ex);
 104    }
 105   
 106    }
 107   
 108    }
 109   
 110    // package private for testing purposes
 111   
 112  1 private Class buildImplementationClass(ServiceImplementationFactoryParameters factoryParameters)
 113    {
 114  1 String name = ClassFabUtils.generateClassName(factoryParameters.getServiceInterface());
 115   
 116  1 return buildImplementationClass(factoryParameters, name);
 117    }
 118   
 119    // package private for testing purposes
 120   
 121  3 Class buildImplementationClass(ServiceImplementationFactoryParameters factoryParameters,
 122    String name)
 123    {
 124  3 Class serviceInterface = factoryParameters.getServiceInterface();
 125   
 126  3 ClassFab cf = _classFactory.newClass(name, Object.class);
 127   
 128  3 cf.addInterface(serviceInterface);
 129   
 130  3 cf.addField("_registry", StrategyRegistry.class);
 131   
 132  3 cf.addConstructor(new Class[]
 133    { StrategyRegistry.class }, null, "_registry = $1;");
 134   
 135    // TODO: Should we add a check for $1 == null?
 136   
 137  3 cf.addMethod(Modifier.PRIVATE, new MethodSignature(serviceInterface, "_getStrategy",
 138    new Class[]
 139    { Object.class }, null), "return (" + serviceInterface.getName()
 140    + ") _registry.getStrategy($1.getClass());");
 141   
 142  3 MethodIterator i = new MethodIterator(serviceInterface);
 143   
 144  3 while (i.hasNext())
 145    {
 146  3 MethodSignature sig = i.next();
 147   
 148  3 if (proper(sig))
 149    {
 150  2 addAdaptedMethod(cf, sig);
 151    }
 152    else
 153    {
 154  1 ClassFabUtils.addNoOpMethod(cf, sig);
 155   
 156  1 factoryParameters.getErrorLog().error(
 157    StrategyMessages.improperServiceMethod(sig),
 158    HiveMind.getLocation(factoryParameters.getFirstParameter()),
 159    null);
 160    }
 161   
 162    }
 163   
 164  3 if (!i.getToString())
 165  3 ClassFabUtils.addToStringMethod(cf, StrategyMessages.toString(factoryParameters
 166    .getServiceId(), serviceInterface));
 167   
 168  3 return cf.createClass();
 169    }
 170   
 171  2 private void addAdaptedMethod(ClassFab cf, MethodSignature sig)
 172    {
 173  2 String body = "return ($r) _getStrategy($1)." + sig.getName() + "($$);";
 174   
 175  2 cf.addMethod(Modifier.PUBLIC, sig, body);
 176    }
 177   
 178    /**
 179    * A "proper" method is one with at least one parameter and whose first parameter is an object
 180    * (not primitive) type.
 181    */
 182   
 183  3 private boolean proper(MethodSignature sig)
 184    {
 185  3 Class[] parameterTypes = sig.getParameterTypes();
 186   
 187  3 return parameterTypes != null && parameterTypes.length > 0
 188    && !parameterTypes[0].isPrimitive();
 189    }
 190   
 191  3 public void setClassFactory(ClassFactory classFactory)
 192    {
 193  3 _classFactory = classFactory;
 194    }
 195    }