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: 276   Methods: 7
NCLOC: 143   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
SingletonServiceModel.java 90% 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 supports
 31    * creation of a singleton service proxy (deferring the actual construction of the service until
 32    * 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  995 public SingletonServiceModel(ConstructableServicePoint servicePoint)
 50    {
 51  995 super(servicePoint);
 52    }
 53   
 54  996 public synchronized Object getService()
 55    {
 56  996 if (_serviceProxy == null)
 57  995 _serviceProxy = createSingletonProxy();
 58   
 59  996 return _serviceProxy;
 60    }
 61   
 62    /**
 63    * This is invoked by the proxy to create the actual implementation.
 64    */
 65  495 public synchronized Object getActualServiceImplementation()
 66    {
 67  495 if (_constructedService == null)
 68    {
 69  495 _constructedService = constructServiceImplementation();
 70  495 registerWithShutdownCoordinator(_constructedService);
 71    }
 72   
 73    // The inner proxy needs the service to implement the service interface.
 74    // For bean services (not interface services) with no interceptors,
 75    // the implementation may be the bean provided by the factory ... which
 76    // does not implement the service interface (which was created at runtime).
 77    // So we introduce a "bridge" between the two.
 78   
 79  495 Class serviceInterface = getServicePoint().getServiceInterface();
 80   
 81  495 if (!serviceInterface.isInstance(_constructedService))
 82  6 _constructedService = constructBridgeProxy(_constructedService);
 83   
 84  495 return _constructedService;
 85    }
 86   
 87    /**
 88    * Creates a proxy class for the service and then construct the class itself.
 89    */
 90  995 private Object createSingletonProxy()
 91    {
 92  995 if (_log.isDebugEnabled())
 93  4 _log.debug("Creating SingletonProxy for service "
 94    + getServicePoint().getExtensionPointId());
 95   
 96  995 try
 97    {
 98   
 99    // Create the outer proxy, the one visible to client code (including
 100    // other services). It is dependent on an inner proxy.
 101   
 102  995 Class proxyClass = createSingletonProxyClass();
 103   
 104    // Create the inner proxy, whose job is to replace itself
 105    // when the first service method is invoked.
 106   
 107  995 Class innerProxyClass = createInnerProxyClass(proxyClass);
 108   
 109    // Create the outer proxy.
 110   
 111  995 Object result = proxyClass.newInstance();
 112   
 113    // The inner proxy's construct invokes a method on the
 114    // outer proxy to connect the two.
 115   
 116  995 Constructor c = innerProxyClass.getConstructor(new Class[]
 117    { proxyClass, getClass() });
 118   
 119  995 _innerProxy = (SingletonInnerProxy) c.newInstance(new Object[]
 120    { result, this });
 121   
 122  995 RegistryShutdownListener asListener = (RegistryShutdownListener) result;
 123   
 124  995 getServicePoint().addRegistryShutdownListener(asListener);
 125   
 126  995 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  995 private Class createSingletonProxyClass()
 142    {
 143  995 ConstructableServicePoint servicePoint = getServicePoint();
 144   
 145  995 ProxyBuilder proxyBuilder = new ProxyBuilder("SingletonProxy", servicePoint, true);
 146   
 147  995 ClassFab classFab = proxyBuilder.getClassFab();
 148   
 149  995 Class serviceInterface = servicePoint.getServiceInterface();
 150   
 151    // This will initally be the inner proxy, then switch over to the
 152    // service implementation.
 153   
 154  995 classFab.addField("_inner", serviceInterface);
 155  995 classFab.addField("_shutdown", boolean.class);
 156  995 if (!RegistryShutdownListener.class.isAssignableFrom(serviceInterface))
 157    {
 158  994 classFab.addInterface(RegistryShutdownListener.class);
 159   
 160  994 classFab.addMethod(Modifier.PUBLIC | Modifier.FINAL, new MethodSignature(void.class,
 161    "registryDidShutdown", null, null), "{ _shutdown = true; }");
 162    }
 163  995 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  995 BodyBuilder builder = new BodyBuilder();
 170  995 builder.begin();
 171  995 builder.addln("if (_shutdown)");
 172  995 builder.begin();
 173  995 builder.addln("_inner = null;");
 174  995 builder.addln("throw org.apache.hivemind.HiveMind#createRegistryShutdownException();");
 175  995 builder.end();
 176   
 177  995 builder.addln("return _inner;");
 178  995 builder.end();
 179   
 180  995 classFab.addMethod(Modifier.PRIVATE, new MethodSignature(serviceInterface, "_getInner",
 181    null, null), builder.toString());
 182   
 183  995 proxyBuilder.addServiceMethods("_getInner()");
 184   
 185  995 return classFab.createClass();
 186    }
 187   
 188  995 private Class createInnerProxyClass(Class deferredProxyClass)
 189    {
 190  995 ServicePoint servicePoint = getServicePoint();
 191   
 192  995 Class serviceInterface = servicePoint.getServiceInterface();
 193  995 ProxyBuilder builder = new ProxyBuilder("InnerProxy", servicePoint);
 194   
 195  995 ClassFab classFab = builder.getClassFab();
 196   
 197  995 classFab.addField("_deferredProxy", deferredProxyClass);
 198  995 classFab.addField("_service", serviceInterface);
 199  995 classFab.addField("_serviceModel", getClass());
 200   
 201  995 BodyBuilder body = new BodyBuilder();
 202   
 203    // The constructor remembers the outer proxy and registers itself
 204    // with the outer proxy.
 205   
 206  995 body.begin();
 207   
 208  995 body.addln("super();");
 209  995 body.addln("_deferredProxy = $1;");
 210  995 body.addln("_serviceModel = $2;");
 211  995 body.addln("_deferredProxy._setInner(this);");
 212   
 213  995 body.end();
 214   
 215  995 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  995 body.clear();
 223  995 body.begin();
 224   
 225  995 body.add("if (_service == null)");
 226  995 body.begin();
 227   
 228  995 body.add("_service = (");
 229  995 body.add(serviceInterface.getName());
 230  995 body.addln(") _serviceModel.getActualServiceImplementation();");
 231   
 232  995 body.add("_deferredProxy._setInner(_service);");
 233   
 234  995 body.end();
 235   
 236  995 body.add("return _service;");
 237   
 238  995 body.end();
 239   
 240  995 classFab.addMethod(
 241    Modifier.PRIVATE | Modifier.FINAL | Modifier.SYNCHRONIZED,
 242    new MethodSignature(serviceInterface, "_service", null, null),
 243    body.toString());
 244   
 245  995 builder.addServiceMethods("_service()");
 246   
 247    // Build the implementation of interface SingletonInnerProxy
 248   
 249  995 body.clear();
 250  995 body.begin();
 251   
 252  995 body.add("_service();");
 253   
 254  995 body.end();
 255   
 256  995 classFab.addMethod(Modifier.PUBLIC | Modifier.FINAL, new MethodSignature(void.class,
 257    "_instantiateServiceImplementation", null, null), body.toString());
 258   
 259  995 classFab.addInterface(SingletonInnerProxy.class);
 260   
 261  995 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    }