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: 197   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   
 45    private final ThreadEventNotifier _notifier;
 46   
 47    /**
 48    * Used to store the active service for the current thread.
 49    */
 50    private final ThreadLocal _activeService = new ThreadLocal();
 51   
 52    /** @since 1.1 */
 53   
 54    private Class _serviceInterface;
 55   
 56  24 public ThreadedServiceModel(ConstructableServicePoint servicePoint)
 57    {
 58  24 super(servicePoint);
 59   
 60  24 _serviceInterface = servicePoint.getServiceInterface();
 61   
 62  24 Module module = getServicePoint().getModule();
 63   
 64  24 _notifier = (ThreadEventNotifier) module.getService(
 65    HiveMind.THREAD_EVENT_NOTIFIER_SERVICE,
 66    ThreadEventNotifier.class);
 67   
 68  24 _serviceProxy = createServiceProxy();
 69    }
 70   
 71    class CleanupListener implements ThreadCleanupListener
 72    {
 73    // The core itself
 74    private final Object _core;
 75   
 76  12018 CleanupListener(Object core)
 77    {
 78  12004 _core = core;
 79    }
 80   
 81  12003 public void threadDidCleanup()
 82    {
 83  12003 unbindServiceFromCurrentThread();
 84   
 85  12003 if (_core instanceof Discardable)
 86    {
 87  1 Discardable d = (Discardable) _core;
 88   
 89  1 d.threadDidDiscardService();
 90    }
 91    }
 92    }
 93   
 94    /**
 95    * Always returns the service proxy.
 96    */
 97  24 public Object getService()
 98    {
 99    // In 1.1 and earlier, we would lazily create the _serviceProxy here; but that meant the
 100    // method had to be synchronized, which created a choke point.
 101   
 102    // The result is an interceptor stack, where the final (most deeply nested) object
 103    // is the serviceProxy. The serviceProxy obtains the instance for the current thread
 104    // and delegates to it. This is a little bit different than SingletonServiceModel, which
 105    // creates a pair of proxies so as to defer creation of the interceptors as well. In both
 106    // cases, the interceptors are only created once.
 107   
 108  24 return _serviceProxy;
 109    }
 110   
 111    /**
 112    * Creates a proxy instance for the service, and returns it, wrapped in any interceptors for the
 113    * service.
 114    */
 115  24 private Object createServiceProxy()
 116    {
 117  24 ConstructableServicePoint servicePoint = getServicePoint();
 118   
 119  24 if (_log.isDebugEnabled())
 120  1 _log.debug("Creating ThreadedProxy for service " + servicePoint.getExtensionPointId());
 121   
 122  24 Object proxy = ProxyUtils.createDelegatingProxy(
 123    "ThreadedProxy",
 124    this,
 125    "getServiceImplementationForCurrentThread",
 126    servicePoint);
 127   
 128  24 Object intercepted = addInterceptors(proxy);
 129   
 130  24 RegistryShutdownListener outerProxy = ProxyUtils
 131    .createOuterProxy(intercepted, servicePoint);
 132   
 133  24 servicePoint.addRegistryShutdownListener(outerProxy);
 134   
 135  24 return outerProxy;
 136    }
 137   
 138    /**
 139    * Invoked by the proxy to return the active service impl for this thread, constructing it as
 140    * necessary.
 141    */
 142  12025 public Object getServiceImplementationForCurrentThread()
 143    {
 144  11981 Object result = _activeService.get();
 145   
 146  12030 if (result == null)
 147  12016 result = constructInstanceForCurrentThread();
 148   
 149  12007 return result;
 150    }
 151   
 152  12016 private Object constructInstanceForCurrentThread()
 153    {
 154  12016 try
 155    {
 156  12016 Object core = constructCoreServiceImplementation();
 157   
 158  12014 if (core instanceof RegistryShutdownListener)
 159  2 _log.error(ServiceModelMessages.registryCleanupIgnored(getServicePoint()));
 160   
 161  12018 _notifier.addThreadCleanupListener(new CleanupListener(core));
 162   
 163    // Once more ... with bean services, its possible that
 164    // the factory generated bean does not implement the (synthetic) service
 165    // interface, so create a bridge to it.
 166   
 167  12013 if (!_serviceInterface.isInstance(core))
 168  2 core = constructBridgeProxy(core);
 169   
 170  12017 _activeService.set(core);
 171   
 172  12016 return core;
 173    }
 174    catch (Exception ex)
 175    {
 176  0 throw new ApplicationRuntimeException(ServiceModelMessages.unableToConstructService(
 177    getServicePoint(),
 178    ex), ex);
 179    }
 180    }
 181   
 182  12003 private void unbindServiceFromCurrentThread()
 183    {
 184  12003 _activeService.set(null);
 185    }
 186   
 187    /**
 188    * Invokes {@link #getServiceImplementationForCurrentThread()} to force the creation of the
 189    * service implementation.
 190    */
 191   
 192  1 public void instantiateService()
 193    {
 194  1 getServiceImplementationForCurrentThread();
 195    }
 196   
 197    }