Clover coverage report - Code Coverage for hivemind release 1.1.1
Coverage timestamp: Sat Jan 28 2006 10:19:31 PST
file stats: LOC: 196   Methods: 9
NCLOC: 99   Classes: 2
 
 Source file Conditionals Statements Methods TOTAL
ThreadedServiceModel.java 100% 97.1% 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.impl.servicemodel;
 16   
 17    import org.apache.hivemind.ApplicationRuntimeException;
 18    import org.apache.hivemind.Discardable;
 19    import org.apache.hivemind.HiveMind;
 20    import org.apache.hivemind.events.RegistryShutdownListener;
 21    import org.apache.hivemind.impl.ConstructableServicePoint;
 22    import org.apache.hivemind.impl.ProxyUtils;
 23    import org.apache.hivemind.internal.Module;
 24    import org.apache.hivemind.service.ThreadCleanupListener;
 25    import org.apache.hivemind.service.ThreadEventNotifier;
 26   
 27    /**
 28    * Like {@link org.apache.hivemind.impl.servicemodel.SingletonServiceModel}, this method returns a
 29    * proxy (implementing the service interface); unlike SingletonServiceModel, it <em>always</em>
 30    * returns the proxy. Invoking a service method on the proxy constructs a service implementation and
 31    * binds it to the current thread.
 32    *
 33    * @author Howard Lewis Ship
 34    */
 35    public final class ThreadedServiceModel extends AbstractServiceModelImpl
 36    {
 37    /**
 38    * Name of a method in the deferred proxy that is used to obtain the constructed service.
 39    */
 40    protected static final String SERVICE_ACCESSOR_METHOD_NAME = "_service";
 41   
 42    private final Object _serviceProxy;
 43   
 44    private final ThreadEventNotifier _notifier;
 45   
 46    /**
 47    * Used to store the active service for the current thread.
 48    */
 49    private final ThreadLocal _activeService = new ThreadLocal();
 50   
 51    /** @since 1.1 */
 52   
 53    private Class _serviceInterface;
 54   
 55  24 public ThreadedServiceModel(ConstructableServicePoint servicePoint)
 56    {
 57  24 super(servicePoint);
 58   
 59  24 _serviceInterface = servicePoint.getServiceInterface();
 60   
 61  24 Module module = getServicePoint().getModule();
 62   
 63  24 _notifier = (ThreadEventNotifier) module.getService(
 64    HiveMind.THREAD_EVENT_NOTIFIER_SERVICE,
 65    ThreadEventNotifier.class);
 66   
 67  24 _serviceProxy = createServiceProxy();
 68    }
 69   
 70    class CleanupListener implements ThreadCleanupListener
 71    {
 72    // The core itself
 73    private final Object _core;
 74   
 75  12003 CleanupListener(Object core)
 76    {
 77  12009 _core = core;
 78    }
 79   
 80  12003 public void threadDidCleanup()
 81    {
 82  12003 unbindServiceFromCurrentThread();
 83   
 84  12003 if (_core instanceof Discardable)
 85    {
 86  1 Discardable d = (Discardable) _core;
 87   
 88  1 d.threadDidDiscardService();
 89    }
 90    }
 91    }
 92   
 93    /**
 94    * Always returns the service proxy.
 95    */
 96  24 public Object getService()
 97    {
 98    // In 1.1 and earlier, we would lazily create the _serviceProxy here; but that meant the
 99    // method had to be synchronized, which created a choke point.
 100   
 101    // The result is an interceptor stack, where the final (most deeply nested) object
 102    // is the serviceProxy. The serviceProxy obtains the instance for the current thread
 103    // and delegates to it. This is a little bit different than SingletonServiceModel, which
 104    // creates a pair of proxies so as to defer creation of the interceptors as well. In both
 105    // cases, the interceptors are only created once.
 106   
 107  24 return _serviceProxy;
 108    }
 109   
 110    /**
 111    * Creates a proxy instance for the service, and returns it, wrapped in any interceptors for the
 112    * service.
 113    */
 114  24 private Object createServiceProxy()
 115    {
 116  24 ConstructableServicePoint servicePoint = getServicePoint();
 117   
 118  24 if (_log.isDebugEnabled())
 119  1 _log.debug("Creating ThreadedProxy for service " + servicePoint.getExtensionPointId());
 120   
 121  24 Object proxy = ProxyUtils.createDelegatingProxy(
 122    "ThreadedProxy",
 123    this,
 124    "getServiceImplementationForCurrentThread",
 125    servicePoint);
 126   
 127  24 Object intercepted = addInterceptors(proxy);
 128   
 129  24 RegistryShutdownListener outerProxy = ProxyUtils
 130    .createOuterProxy(intercepted, servicePoint);
 131   
 132  24 servicePoint.addRegistryShutdownListener(outerProxy);
 133   
 134  24 return outerProxy;
 135    }
 136   
 137    /**
 138    * Invoked by the proxy to return the active service impl for this thread, constructing it as
 139    * necessary.
 140    */
 141  12025 public Object getServiceImplementationForCurrentThread()
 142    {
 143  12025 Object result = _activeService.get();
 144   
 145  12013 if (result == null)
 146  12015 result = constructInstanceForCurrentThread();
 147   
 148  12026 return result;
 149    }
 150   
 151  12016 private Object constructInstanceForCurrentThread()
 152    {
 153  12012 try
 154    {
 155  12016 Object core = constructCoreServiceImplementation();
 156   
 157  12001 if (core instanceof RegistryShutdownListener)
 158  2 _log.error(ServiceModelMessages.registryCleanupIgnored(getServicePoint()));
 159   
 160  12018 _notifier.addThreadCleanupListener(new CleanupListener(core));
 161   
 162    // Once more ... with bean services, its possible that
 163    // the factory generated bean does not implement the (synthetic) service
 164    // interface, so create a bridge to it.
 165   
 166  12017 if (!_serviceInterface.isInstance(core))
 167  2 core = constructBridgeProxy(core);
 168   
 169  12013 _activeService.set(core);
 170   
 171  12018 return core;
 172    }
 173    catch (Exception ex)
 174    {
 175  0 throw new ApplicationRuntimeException(ServiceModelMessages.unableToConstructService(
 176    getServicePoint(),
 177    ex), ex);
 178    }
 179    }
 180   
 181  12003 private void unbindServiceFromCurrentThread()
 182    {
 183  12003 _activeService.set(null);
 184    }
 185   
 186    /**
 187    * Invokes {@link #getServiceImplementationForCurrentThread()} to force the creation of the
 188    * service implementation.
 189    */
 190   
 191  1 public void instantiateService()
 192    {
 193  1 getServiceImplementationForCurrentThread();
 194    }
 195   
 196    }