Clover coverage report - Code Coverage for hivemind release 1.1-beta-2
Coverage timestamp: Tue Jun 28 2005 10:28:23 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  992 public SingletonServiceModel(ConstructableServicePoint servicePoint)
 50    {
 51  992 super(servicePoint);
 52    }
 53   
 54  993 public synchronized Object getService()
 55    {
 56  993 if (_serviceProxy == null)
 57  992 _serviceProxy = createSingletonProxy();
 58   
 59  993 return _serviceProxy;
 60    }
 61   
 62    /**
 63    * This is invoked by the proxy to create the actual implementation.
 64    */
 65  496 public synchronized Object getActualServiceImplementation()
 66    {
 67  496 if (_constructedService == null)
 68  496 _constructedService = constructServiceImplementation();
 69   
 70  496 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  496 Class serviceInterface = getServicePoint().getServiceInterface();
 81   
 82  496 if (!serviceInterface.isInstance(_constructedService))
 83  6 _constructedService = constructBridgeProxy(_constructedService);
 84   
 85  496 return _constructedService;
 86    }
 87   
 88    /**
 89    * Creates a proxy class for the service and then construct the class itself.
 90    */
 91  992 private Object createSingletonProxy()
 92    {
 93  992 if (_log.isDebugEnabled())
 94  4 _log.debug("Creating SingletonProxy for service "
 95    + getServicePoint().getExtensionPointId());
 96   
 97  992 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  992 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  992 Class innerProxyClass = createInnerProxyClass(proxyClass);
 109   
 110    // Create the outer proxy.
 111   
 112  992 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  992 Constructor c = innerProxyClass.getConstructor(new Class[]
 118    { proxyClass, getClass() });
 119   
 120  992 _innerProxy = (SingletonInnerProxy) c.newInstance(new Object[]
 121    { result, this });
 122   
 123  992 getServicePoint().getShutdownCoordinator().addRegistryShutdownListener(
 124    (RegistryShutdownListener) result);
 125   
 126  992 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  992 private Class createSingletonProxyClass()
 142    {
 143  992 ConstructableServicePoint servicePoint = getServicePoint();
 144   
 145  992 ProxyBuilder proxyBuilder = new ProxyBuilder("SingletonProxy", servicePoint, true);
 146   
 147  992 ClassFab classFab = proxyBuilder.getClassFab();
 148   
 149  992 Class serviceInterface = servicePoint.getServiceInterface();
 150   
 151    // This will initally be the inner proxy, then switch over to the
 152    // service implementation.
 153   
 154  992 classFab.addField("_inner", serviceInterface);
 155  992 classFab.addField("_shutdown", boolean.class);
 156  992 if( !RegistryShutdownListener.class.isAssignableFrom( serviceInterface ) )
 157    {
 158  991 classFab.addInterface(RegistryShutdownListener.class);
 159   
 160  991 classFab.addMethod(Modifier.PUBLIC | Modifier.FINAL, new MethodSignature(void.class,
 161    "registryDidShutdown", null, null), "{ _shutdown = true; }");
 162    }
 163  992 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  992 BodyBuilder builder = new BodyBuilder();
 170  992 builder.begin();
 171  992 builder.addln("if (_shutdown)");
 172  992 builder.begin();
 173  992 builder.addln("_inner = null;");
 174  992 builder.addln("throw org.apache.hivemind.HiveMind#createRegistryShutdownException();");
 175  992 builder.end();
 176   
 177  992 builder.addln("return _inner;");
 178  992 builder.end();
 179   
 180  992 classFab.addMethod(Modifier.PRIVATE, new MethodSignature(serviceInterface, "_getInner",
 181    null, null), builder.toString());
 182   
 183  992 proxyBuilder.addServiceMethods("_getInner()");
 184   
 185  992 return classFab.createClass();
 186    }
 187   
 188  992 private Class createInnerProxyClass(Class deferredProxyClass)
 189    {
 190  992 ServicePoint servicePoint = getServicePoint();
 191   
 192  992 Class serviceInterface = servicePoint.getServiceInterface();
 193  992 ProxyBuilder builder = new ProxyBuilder("InnerProxy", servicePoint);
 194   
 195  992 ClassFab classFab = builder.getClassFab();
 196   
 197  992 classFab.addField("_deferredProxy", deferredProxyClass);
 198  992 classFab.addField("_service", serviceInterface);
 199  992 classFab.addField("_serviceModel", getClass());
 200   
 201  992 BodyBuilder body = new BodyBuilder();
 202   
 203    // The constructor remembers the outer proxy and registers itself
 204    // with the outer proxy.
 205   
 206  992 body.begin();
 207   
 208  992 body.addln("super();");
 209  992 body.addln("_deferredProxy = $1;");
 210  992 body.addln("_serviceModel = $2;");
 211  992 body.addln("_deferredProxy._setInner(this);");
 212   
 213  992 body.end();
 214   
 215  992 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  992 body.clear();
 223  992 body.begin();
 224   
 225  992 body.add("if (_service == null)");
 226  992 body.begin();
 227   
 228  992 body.add("_service = (");
 229  992 body.add(serviceInterface.getName());
 230  992 body.addln(") _serviceModel.getActualServiceImplementation();");
 231   
 232  992 body.add("_deferredProxy._setInner(_service);");
 233   
 234  992 body.end();
 235   
 236  992 body.add("return _service;");
 237   
 238  992 body.end();
 239   
 240  992 classFab.addMethod(
 241    Modifier.PRIVATE | Modifier.FINAL | Modifier.SYNCHRONIZED,
 242    new MethodSignature(serviceInterface, "_service", null, null),
 243    body.toString());
 244   
 245  992 builder.addServiceMethods("_service()");
 246   
 247    // Build the implementation of interface SingletonInnerProxy
 248   
 249  992 body.clear();
 250  992 body.begin();
 251   
 252  992 body.add("_service();");
 253   
 254  992 body.end();
 255   
 256  992 classFab.addMethod(Modifier.PUBLIC | Modifier.FINAL, new MethodSignature(void.class,
 257    "_instantiateServiceImplementation", null, null), body.toString());
 258   
 259  992 classFab.addInterface(SingletonInnerProxy.class);
 260   
 261  992 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    }