Clover coverage report - Code Coverage for hivemind release 1.1-rc-1
Coverage timestamp: Fri Sep 23 2005 10:46:55 EDT
file stats: LOC: 276   Methods: 7
NCLOC: 144   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
SingletonServiceModel.java 91.7% 98.8% 100% 98%
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.impl.servicemodel;
 16   
 17    import java.lang.reflect.Constructor;
 18    import java.lang.reflect.Modifier;
 19   
 20    import org.apache.hivemind.ApplicationRuntimeException;
 21    import org.apache.hivemind.events.RegistryShutdownListener;
 22    import org.apache.hivemind.impl.ConstructableServicePoint;
 23    import org.apache.hivemind.impl.ProxyBuilder;
 24    import org.apache.hivemind.internal.ServicePoint;
 25    import org.apache.hivemind.service.BodyBuilder;
 26    import org.apache.hivemind.service.ClassFab;
 27    import org.apache.hivemind.service.MethodSignature;
 28   
 29    /**
 30    * Subclass of {@link org.apache.hivemind.impl.servicemodel.AbstractServiceModelImpl} which
 31    * supports creation of a singleton service proxy (deferring the actual construction of the service
 32    * until absolutely necessary). This is used with the singleton service type, which is the default.
 33    *
 34    * @author Howard Lewis Ship
 35    */
 36    public final class SingletonServiceModel extends AbstractServiceModelImpl
 37    {
 38    /**
 39    * Name of a method in the deferred proxy that is used to obtain the constructed service.
 40    */
 41    protected static final String SERVICE_ACCESSOR_METHOD_NAME = "_service";
 42   
 43    private Object _serviceProxy;
 44   
 45    private SingletonInnerProxy _innerProxy;
 46   
 47    private Object _constructedService;
 48   
 49  999 public SingletonServiceModel(ConstructableServicePoint servicePoint)
 50    {
 51  999 super(servicePoint);
 52    }
 53   
 54  1000 public synchronized Object getService()
 55    {
 56  1000 if (_serviceProxy == null)
 57  999 _serviceProxy = createSingletonProxy();
 58   
 59  1000 return _serviceProxy;
 60    }
 61   
 62    /**
 63    * This is invoked by the proxy to create the actual implementation.
 64    */
 65  499 public synchronized Object getActualServiceImplementation()
 66    {
 67  499 if (_constructedService == null)
 68  499 _constructedService = constructServiceImplementation();
 69   
 70  499 if( _constructedService instanceof RegistryShutdownListener )
 71    {
 72  4 getShutdownCoordinatorService().addRegistryShutdownListener( ( RegistryShutdownListener )_constructedService );
 73    }
 74    // The inner proxy needs the service to implement the service interface.
 75    // For bean services (not interface services) with no interceptors,
 76    // the implementation may be the bean provided by the factory ... which
 77    // does not implement the service interface (which was created at runtime).
 78    // So we introduce a "bridge" between the two.
 79   
 80  499 Class serviceInterface = getServicePoint().getServiceInterface();
 81   
 82  499 if (!serviceInterface.isInstance(_constructedService))
 83  6 _constructedService = constructBridgeProxy(_constructedService);
 84   
 85  499 return _constructedService;
 86    }
 87   
 88    /**
 89    * Creates a proxy class for the service and then construct the class itself.
 90    */
 91  999 private Object createSingletonProxy()
 92    {
 93  999 if (_log.isDebugEnabled())
 94  4 _log.debug("Creating SingletonProxy for service "
 95    + getServicePoint().getExtensionPointId());
 96   
 97  999 try
 98    {
 99   
 100    // Create the outer proxy, the one visible to client code (including
 101    // other services). It is dependent on an inner proxy.
 102   
 103  999 Class proxyClass = createSingletonProxyClass();
 104   
 105    // Create the inner proxy, whose job is to replace itself
 106    // when the first service method is invoked.
 107   
 108  999 Class innerProxyClass = createInnerProxyClass(proxyClass);
 109   
 110    // Create the outer proxy.
 111   
 112  999 Object result = proxyClass.newInstance();
 113   
 114    // The inner proxy's construct invokes a method on the
 115    // outer proxy to connect the two.
 116   
 117  999 Constructor c = innerProxyClass.getConstructor(new Class[]
 118    { proxyClass, getClass() });
 119   
 120  999 _innerProxy = (SingletonInnerProxy) c.newInstance(new Object[]
 121    { result, this });
 122   
 123  999 getServicePoint().getShutdownCoordinator().addRegistryShutdownListener(
 124    (RegistryShutdownListener) result);
 125   
 126  999 return result;
 127    }
 128    catch (Exception ex)
 129    {
 130  0 throw new ApplicationRuntimeException(ex);
 131    }
 132   
 133    }
 134   
 135    /**
 136    * Creates a class that implements the service interface. Implements a private synchronized
 137    * method, _service(), that constructs the service as needed, and has each service interface
 138    * method re-invoke on _service(). Adds a toString() method if the service interface does not
 139    * define toString().
 140    */
 141  999 private Class createSingletonProxyClass()
 142    {
 143  999 ConstructableServicePoint servicePoint = getServicePoint();
 144   
 145  999 ProxyBuilder proxyBuilder = new ProxyBuilder("SingletonProxy", servicePoint, true);
 146   
 147  999 ClassFab classFab = proxyBuilder.getClassFab();
 148   
 149  999 Class serviceInterface = servicePoint.getServiceInterface();
 150   
 151    // This will initally be the inner proxy, then switch over to the
 152    // service implementation.
 153   
 154  999 classFab.addField("_inner", serviceInterface);
 155  999 classFab.addField("_shutdown", boolean.class);
 156  999 if( !RegistryShutdownListener.class.isAssignableFrom( serviceInterface ) )
 157    {
 158  998 classFab.addInterface(RegistryShutdownListener.class);
 159   
 160  998 classFab.addMethod(Modifier.PUBLIC | Modifier.FINAL, new MethodSignature(void.class,
 161    "registryDidShutdown", null, null), "{ _shutdown = true; }");
 162    }
 163  999 classFab.addMethod(
 164    Modifier.PUBLIC | Modifier.SYNCHRONIZED | Modifier.FINAL,
 165    new MethodSignature(void.class, "_setInner", new Class[]
 166    { serviceInterface }, null),
 167    "{ _inner = $1; }");
 168   
 169  999 BodyBuilder builder = new BodyBuilder();
 170  999 builder.begin();
 171  999 builder.addln("if (_shutdown)");
 172  999 builder.begin();
 173  999 builder.addln("_inner = null;");
 174  999 builder.addln("throw org.apache.hivemind.HiveMind#createRegistryShutdownException();");
 175  999 builder.end();
 176   
 177  999 builder.addln("return _inner;");
 178  999 builder.end();
 179   
 180  999 classFab.addMethod(Modifier.PRIVATE, new MethodSignature(serviceInterface, "_getInner",
 181    null, null), builder.toString());
 182   
 183  999 proxyBuilder.addServiceMethods("_getInner()");
 184   
 185  999 return classFab.createClass();
 186    }
 187   
 188  999 private Class createInnerProxyClass(Class deferredProxyClass)
 189    {
 190  999 ServicePoint servicePoint = getServicePoint();
 191   
 192  999 Class serviceInterface = servicePoint.getServiceInterface();
 193  999 ProxyBuilder builder = new ProxyBuilder("InnerProxy", servicePoint);
 194   
 195  999 ClassFab classFab = builder.getClassFab();
 196   
 197  999 classFab.addField("_deferredProxy", deferredProxyClass);
 198  999 classFab.addField("_service", serviceInterface);
 199  999 classFab.addField("_serviceModel", getClass());
 200   
 201  999 BodyBuilder body = new BodyBuilder();
 202   
 203    // The constructor remembers the outer proxy and registers itself
 204    // with the outer proxy.
 205   
 206  999 body.begin();
 207   
 208  999 body.addln("super();");
 209  999 body.addln("_deferredProxy = $1;");
 210  999 body.addln("_serviceModel = $2;");
 211  999 body.addln("_deferredProxy._setInner(this);");
 212   
 213  999 body.end();
 214   
 215  999 classFab.addConstructor(new Class[]
 216    { deferredProxyClass, getClass() }, null, body.toString());
 217   
 218    // Method _service() will look up the service implementation,
 219    // then update the deferred proxy to go directly to the
 220    // service implementation, bypassing itself!
 221   
 222  999 body.clear();
 223  999 body.begin();
 224   
 225  999 body.add("if (_service == null)");
 226  999 body.begin();
 227   
 228  999 body.add("_service = (");
 229  999 body.add(serviceInterface.getName());
 230  999 body.addln(") _serviceModel.getActualServiceImplementation();");
 231   
 232  999 body.add("_deferredProxy._setInner(_service);");
 233   
 234  999 body.end();
 235   
 236  999 body.add("return _service;");
 237   
 238  999 body.end();
 239   
 240  999 classFab.addMethod(
 241    Modifier.PRIVATE | Modifier.FINAL | Modifier.SYNCHRONIZED,
 242    new MethodSignature(serviceInterface, "_service", null, null),
 243    body.toString());
 244   
 245  999 builder.addServiceMethods("_service()");
 246   
 247    // Build the implementation of interface SingletonInnerProxy
 248   
 249  999 body.clear();
 250  999 body.begin();
 251   
 252  999 body.add("_service();");
 253   
 254  999 body.end();
 255   
 256  999 classFab.addMethod(Modifier.PUBLIC | Modifier.FINAL, new MethodSignature(void.class,
 257    "_instantiateServiceImplementation", null, null), body.toString());
 258   
 259  999 classFab.addInterface(SingletonInnerProxy.class);
 260   
 261  999 return classFab.createClass();
 262    }
 263   
 264  1 public void instantiateService()
 265    {
 266    // Ensure that the outer and inner proxies have been created
 267   
 268  1 getService();
 269   
 270    // Force the inner proxy to resolve the service and install the result into
 271    // the outer proxy.
 272   
 273  1 _innerProxy._instantiateServiceImplementation();
 274    }
 275   
 276    }