KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > hivemind > impl > servicemodel > ThreadedServiceModel


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 JavaDoc SERVICE_ACCESSOR_METHOD_NAME = "_service";
41
42     private final Object JavaDoc _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 JavaDoc _activeService = new ThreadLocal JavaDoc();
51
52     /** @since 1.1 */
53
54     private Class JavaDoc _serviceInterface;
55
56     public ThreadedServiceModel(ConstructableServicePoint servicePoint)
57     {
58         super(servicePoint);
59
60         _serviceInterface = servicePoint.getServiceInterface();
61
62         Module module = getServicePoint().getModule();
63
64         _notifier = (ThreadEventNotifier) module.getService(
65                 HiveMind.THREAD_EVENT_NOTIFIER_SERVICE,
66                 ThreadEventNotifier.class);
67
68         _serviceProxy = createServiceProxy();
69     }
70
71     class CleanupListener implements ThreadCleanupListener
72     {
73         // The core itself
74
private final Object JavaDoc _core;
75
76         CleanupListener(Object JavaDoc core)
77         {
78             _core = core;
79         }
80
81         public void threadDidCleanup()
82         {
83             unbindServiceFromCurrentThread();
84
85             if (_core instanceof Discardable)
86             {
87                 Discardable d = (Discardable) _core;
88
89                 d.threadDidDiscardService();
90             }
91         }
92     }
93
94     /**
95      * Always returns the service proxy.
96      */

97     public Object JavaDoc 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         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     private Object JavaDoc createServiceProxy()
116     {
117         ConstructableServicePoint servicePoint = getServicePoint();
118
119         if (_log.isDebugEnabled())
120             _log.debug("Creating ThreadedProxy for service " + servicePoint.getExtensionPointId());
121
122         Object JavaDoc proxy = ProxyUtils.createDelegatingProxy(
123                 "ThreadedProxy",
124                 this,
125                 "getServiceImplementationForCurrentThread",
126                 servicePoint);
127
128         Object JavaDoc intercepted = addInterceptors(proxy);
129
130         RegistryShutdownListener outerProxy = ProxyUtils
131                 .createOuterProxy(intercepted, servicePoint);
132
133         servicePoint.addRegistryShutdownListener(outerProxy);
134
135         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     public Object JavaDoc getServiceImplementationForCurrentThread()
143     {
144         Object JavaDoc result = _activeService.get();
145
146         if (result == null)
147             result = constructInstanceForCurrentThread();
148
149         return result;
150     }
151
152     private Object JavaDoc constructInstanceForCurrentThread()
153     {
154         try
155         {
156             Object JavaDoc core = constructCoreServiceImplementation();
157
158             if (core instanceof RegistryShutdownListener)
159                 _log.error(ServiceModelMessages.registryCleanupIgnored(getServicePoint()));
160
161             _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             if (!_serviceInterface.isInstance(core))
168                 core = constructBridgeProxy(core);
169
170             _activeService.set(core);
171
172             return core;
173         }
174         catch (Exception JavaDoc ex)
175         {
176             throw new ApplicationRuntimeException(ServiceModelMessages.unableToConstructService(
177                     getServicePoint(),
178                     ex), ex);
179         }
180     }
181
182     private void unbindServiceFromCurrentThread()
183     {
184         _activeService.set(null);
185     }
186
187     /**
188      * Invokes {@link #getServiceImplementationForCurrentThread()} to force the creation of the
189      * service implementation.
190      */

191
192     public void instantiateService()
193     {
194         getServiceImplementationForCurrentThread();
195     }
196
197 }
Popular Tags