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: 256   Methods: 7
NCLOC: 149   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
BridgeBuilder.java 96.2% 98.7% 100% 98.1%
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.pipeline;
 16   
 17    import java.lang.reflect.Constructor;
 18    import java.lang.reflect.Modifier;
 19    import java.util.ArrayList;
 20    import java.util.Iterator;
 21    import java.util.List;
 22   
 23    import org.apache.hivemind.ApplicationRuntimeException;
 24    import org.apache.hivemind.ErrorLog;
 25    import org.apache.hivemind.service.BodyBuilder;
 26    import org.apache.hivemind.service.ClassFab;
 27    import org.apache.hivemind.service.ClassFabUtils;
 28    import org.apache.hivemind.service.ClassFactory;
 29    import org.apache.hivemind.service.MethodIterator;
 30    import org.apache.hivemind.service.MethodSignature;
 31   
 32    /**
 33    * Used by the {@link org.apache.hivemind.lib.pipeline.PipelineAssembler} class to create bridge
 34    * classes and to create instances of briddge classes.
 35    *
 36    * @author Howard Lewis Ship
 37    */
 38    class BridgeBuilder
 39    {
 40    private ErrorLog _errorLog;
 41   
 42    private String _serviceId;
 43   
 44    private Class _serviceInterface;
 45   
 46    private Class _filterInterface;
 47   
 48    private ClassFab _classFab;
 49   
 50    private FilterMethodAnalyzer _filterMethodAnalyzer;
 51   
 52    private Constructor _constructor;
 53   
 54  10 BridgeBuilder(ErrorLog errorLog, String serviceId, Class serviceInterface,
 55    Class filterInterface, ClassFactory classFactory)
 56    {
 57  10 _errorLog = errorLog;
 58  10 _serviceId = serviceId;
 59  10 _serviceInterface = serviceInterface;
 60  10 _filterInterface = filterInterface;
 61   
 62  10 String name = ClassFabUtils.generateClassName(_serviceInterface);
 63   
 64  10 _classFab = classFactory.newClass(name, Object.class);
 65   
 66  10 _filterMethodAnalyzer = new FilterMethodAnalyzer(serviceInterface);
 67    }
 68   
 69  10 private void createClass()
 70    {
 71  10 List serviceMethods = new ArrayList();
 72  10 List filterMethods = new ArrayList();
 73   
 74  10 createInfrastructure();
 75   
 76  10 MethodIterator mi = new MethodIterator(_serviceInterface);
 77   
 78  10 while (mi.hasNext())
 79    {
 80  9 serviceMethods.add(mi.next());
 81    }
 82   
 83  10 boolean toStringMethodExists = mi.getToString();
 84   
 85  10 mi = new MethodIterator(_filterInterface);
 86   
 87  10 while (mi.hasNext())
 88    {
 89  9 filterMethods.add(mi.next());
 90    }
 91   
 92  10 while (!serviceMethods.isEmpty())
 93    {
 94  9 MethodSignature ms = (MethodSignature) serviceMethods.remove(0);
 95   
 96  9 addBridgeMethod(ms, filterMethods);
 97    }
 98   
 99  10 reportExtraFilterMethods(filterMethods);
 100   
 101  10 if (!toStringMethodExists)
 102  9 ClassFabUtils.addToStringMethod(_classFab, PipelineMessages.bridgeInstanceDescription(
 103    _serviceId,
 104    _serviceInterface));
 105   
 106  10 Class bridgeClass = _classFab.createClass();
 107   
 108  10 _constructor = bridgeClass.getConstructors()[0];
 109    }
 110   
 111  10 private void createInfrastructure()
 112    {
 113  10 _classFab.addField("_next", _serviceInterface);
 114  10 _classFab.addField("_filter", _filterInterface);
 115   
 116  10 _classFab.addConstructor(new Class[]
 117    { _serviceInterface, _filterInterface }, null, "{ _next = $1; _filter = $2; }");
 118   
 119  10 _classFab.addInterface(_serviceInterface);
 120    }
 121   
 122    /**
 123    * Instantiates a bridge object.
 124    *
 125    * @param nextBridge
 126    * the next Bridge object in the pipeline, or the terminator service
 127    * @param filter
 128    * the filter object for this step of the pipeline
 129    */
 130  12 public Object instantiateBridge(Object nextBridge, Object filter)
 131    {
 132  12 if (_constructor == null)
 133  10 createClass();
 134   
 135  12 try
 136    {
 137  12 return _constructor.newInstance(new Object[]
 138    { nextBridge, filter });
 139    }
 140    catch (Exception ex)
 141    {
 142  0 throw new ApplicationRuntimeException(ex);
 143    }
 144    }
 145   
 146  10 private void reportExtraFilterMethods(List filterMethods)
 147    {
 148  10 Iterator i = filterMethods.iterator();
 149   
 150  10 while (i.hasNext())
 151    {
 152  1 MethodSignature ms = (MethodSignature) i.next();
 153   
 154  1 _errorLog.error(PipelineMessages.extraFilterMethod(
 155    ms,
 156    _filterInterface,
 157    _serviceInterface,
 158    _serviceId), null, null);
 159    }
 160    }
 161   
 162    /**
 163    * Finds a matching method in filterMethods for the given service method. A matching method has
 164    * the same signature as the service interface method, but with an additional parameter matching
 165    * the service interface itself.
 166    * <p>
 167    * The matching method signature from the list of filterMethods is removed and code generation
 168    * strategies for making the two methods call each other are added.
 169    */
 170  9 private void addBridgeMethod(MethodSignature ms, List filterMethods)
 171    {
 172  9 Iterator i = filterMethods.iterator();
 173   
 174  9 while (i.hasNext())
 175    {
 176  8 MethodSignature fms = (MethodSignature) i.next();
 177   
 178  8 int position = _filterMethodAnalyzer.findServiceInterfacePosition(ms, fms);
 179   
 180  8 if (position >= 0)
 181    {
 182  8 addBridgeMethod(position, ms, fms);
 183  8 i.remove();
 184  8 return;
 185    }
 186    }
 187   
 188  1 String message = PipelineMessages.unmatchedServiceMethod(ms, _filterInterface);
 189   
 190  1 _errorLog.error(message, null, null);
 191   
 192  1 BodyBuilder b = new BodyBuilder();
 193   
 194  1 b.add("throw new org.apache.hivemind.ApplicationRuntimeException(");
 195  1 b.addQuoted(message);
 196  1 b.addln(");");
 197   
 198  1 _classFab.addMethod(Modifier.PUBLIC, ms, b.toString());
 199    }
 200   
 201    /**
 202    * Adds a method to the class which bridges from the service method to the corresponding method
 203    * in the filter interface. The next service (either another Bridge, or the terminator at the
 204    * end of the pipeline) is passed to the filter).
 205    */
 206  8 private void addBridgeMethod(int position, MethodSignature ms, MethodSignature fms)
 207    {
 208  8 StringBuffer buffer = new StringBuffer(100);
 209   
 210  8 if (ms.getReturnType() != void.class)
 211  7 buffer.append("return ");
 212   
 213  8 buffer.append("_filter.");
 214  8 buffer.append(ms.getName());
 215  8 buffer.append("(");
 216   
 217  8 boolean comma = false;
 218  8 int filterParameterCount = fms.getParameterTypes().length;
 219   
 220  8 for (int i = 0; i < position; i++)
 221    {
 222  8 if (comma)
 223  1 buffer.append(", ");
 224   
 225  8 buffer.append("$");
 226    // Add one to the index to get the parameter symbol ($0 is the implicit
 227    // this parameter).
 228  8 buffer.append(i + 1);
 229   
 230  8 comma = true;
 231    }
 232   
 233  8 if (comma)
 234  7 buffer.append(", ");
 235   
 236    // _next is the variable in -this- Bridge that points to the -next- Bridge
 237    // or the terminator for the pipeline. The filter is expected to reinvoke the
 238    // method on the _next that's passed to it.
 239   
 240  8 buffer.append("_next");
 241   
 242  8 for (int i = position + 1; i < filterParameterCount; i++)
 243    {
 244  1 buffer.append(", $");
 245  1 buffer.append(i);
 246    }
 247   
 248  8 buffer.append(");");
 249   
 250    // This should work, unless the exception types turn out to not be compatble. We still
 251    // don't do a check on that, and not sure that Javassist does either!
 252   
 253  8 _classFab.addMethod(Modifier.PUBLIC, ms, buffer.toString());
 254    }
 255   
 256    }