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