1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.caleigo.service;
20
21
22 import java.lang.reflect.Proxy;
23 import java.util.*;
24
25 import org.caleigo.toolkit.log.*;
26 import org.caleigo.toolkit.tunnel.*;
27
28 /*** ServiceProviderServer is a singleton class that allows remote service providers
29 * to connect to the local ServiceProvider.
30 * <p>
31 *
32 * @author Mattias Hagstrand
33 * @version 1.00
34 *
35 *//*
36 *
37 * WHEN WHO WHY & WHAT
38 * -----------------------------------------------------------------------------
39 * 2002-07-29 Mattias Hagstrand Creation
40 */
41 public class ServiceProviderServer implements ITunnelServerListener
42 {
43
44 protected static ServiceProviderServer sInstance;
45
46
47 protected List mTunnelServers;
48 protected Hashtable mMessageConsumers;
49
50
51 public static ServiceProviderServer getInstance()
52 {
53 if (sInstance == null)
54 sInstance = new ServiceProviderServer();
55 return sInstance;
56 }
57
58
59 protected ServiceProviderServer()
60 {
61 mTunnelServers = new ArrayList();
62 mMessageConsumers = new Hashtable();
63 }
64
65
66
67 /*** Adds an ITunnelServer that should be used to receive connections to this
68 * ServiceProviderServer.
69 */
70 public void addTunnelServer(ITunnelServer tunnelServer)
71 {
72 mTunnelServers.add(tunnelServer);
73 tunnelServer.addTunnelServerListener(this);
74 }
75
76 /*** Removes an ITunnelServer and closes all connections that were set up
77 * with the use of the tunnel server.
78 * <p>Note that this will cause all services that were connected to this
79 * ServiceProviderServer through one of the closed connections to fail.
80 */
81 public void removeTunnelServer(ITunnelServer tunnelServer)
82 {
83 mTunnelServers.remove(tunnelServer);
84 tunnelServer.removeTunnelServerListener(this);
85
86 for (int i = 0; i < tunnelServer.getTunnelCount(); i++)
87 if (mMessageConsumers.get(tunnelServer.getTunnel(i)) != null)
88 ((MessageConsumer) mMessageConsumers.get(tunnelServer.getTunnel(i))).finalize();
89 }
90
91
92 public void tunnelAdded(TunnelServerEvent event)
93 {
94 mMessageConsumers.put(event.getTunnel(), new MessageConsumer(event.getTunnel()));
95 }
96
97 public void tunnelRemoved(TunnelServerEvent event)
98 {
99 if (mMessageConsumers.get(event.getTunnel()) != null)
100 ((MessageConsumer) mMessageConsumers.get(event.getTunnel())).finalize();
101 mMessageConsumers.remove(event.getTunnel());
102 }
103
104
105 protected class MessageConsumer implements IMessageConsumer
106 {
107
108 protected ProxyHandler mProxyHandler;
109
110
111 public MessageConsumer(ITunnel tunnel)
112 {
113 mProxyHandler = new ProxyHandler(tunnel);
114 tunnel.addMessageConsumer(this);
115 }
116
117
118
119 /***
120 * {@inheritdoc}
121 *
122 * <p>This message consumer only accepts messages of the class
123 * <code>ServiceProvider.IServiceProviderMessage</code>.</p>
124 */
125 public boolean acceptsMessage(Object message)
126 {
127 return (message instanceof ServiceProvider.IServiceProviderMessage);
128 }
129
130 /***
131 * This method does nothing.
132 */
133 public void consumeMessage(Object message)
134 {
135 }
136
137 /***
138 * Tells the IMessageConsumer to consume a message and returns a new message
139 * that will be delivered to the sender of the originial message.
140 */
141 public Object answerMessage(Object message)
142 {
143 if (message instanceof ServiceProvider.GetServiceMessage)
144 {
145 IService service = ServiceProvider.getInstance().getService(((ServiceProvider.GetServiceMessage) message).mServiceInterfaceClass,
146 ((ServiceProvider.GetServiceMessage) message).mServiceType,
147 ((ServiceProvider.GetServiceMessage) message).mServiceIdentity);
148
149 if (service != null)
150 {
151 if (service.hasCustomProxyService())
152 service = service.getCustomProxyService(mProxyHandler.getTunnel());
153 else
154 service = (IService) mProxyHandler.createProxy(new Class[] {service.getServiceInterfaceClass()}, service);
155 }
156
157 return service;
158 }
159
160 return null;
161 }
162
163
164 public void finalize()
165 {
166 try
167 {
168 if (mProxyHandler.getTunnel().isActive())
169 mProxyHandler.getTunnel().finalize();
170 }
171 catch (Exception e)
172 {
173 Log.printWarning(this, "Couldn't finalize tunnel", e);
174 }
175 }
176
177
178 protected void reconnect(IService service)
179 {
180 }
181
182 protected void setServiceTunnel(ITunnel tunnel)
183 {
184 }
185
186
187
188 /*** This class wrapps an IService and implements the methods in
189 * IProxyService. This class is used to provide IProxyService functionallity
190 * for a proxy that has been created for a IService that doesn't have
191 * a custom proxy service.
192 */
193 protected class ProxyService implements IProxyService, java.io.Serializable
194 {
195
196 protected IService mService;
197
198
199 public ProxyService(IService service)
200 {
201 if (!Proxy.isProxyClass(service.getClass()) ||
202 Proxy.getInvocationHandler(service) instanceof DynamicRemoteProxy)
203 throw new IllegalArgumentException("The service is not a proxy or uses a different invocation handler than DynamicRemoteProxy");
204
205 mService = service;
206 }
207
208
209
210 /*** This method is always called by the ServiceManager before any other
211 * method in the service is called.
212 */
213 public void initializeService()
214 {
215 mService.initializeService();
216 }
217
218 /*** This method is always called by the ServiceManager before the service
219 * is released. No other method calls will then be performed on this
220 * instance of the service.
221 */
222 public void finalizeService()
223 {
224 mService.finalizeService();
225 }
226
227 /*** Should return true if the service is online and reponding to calls.
228 * Note that initializeService() must be called prior to this method.
229 */
230 public boolean ping()
231 {
232 return mService.ping();
233 }
234
235 /*** Returns the service object that this service provides. This object
236 * should always implement the interface defined by the service interface
237 * class.
238 */
239 public Object getServiceInterface()
240 {
241 return mService.getServiceInterface();
242 }
243
244 /*** Returns the class object the defines the service interface that all
245 * services with the same type provides.
246 */
247 public Class getServiceInterfaceClass()
248 {
249 return mService.getServiceInterfaceClass();
250 }
251
252 /*** Returns a URI that defines the type of this service. Note that
253 * there can be multiple services implementing the same service type but
254 * implementations of a given type must implement the same service
255 * interface.
256 */
257 public Object getServiceType()
258 {
259 return mService.getServiceType();
260 }
261
262 /*** Returns the URI defining the a unique individual service.
263 */
264 public Object getServiceIdentity()
265 {
266 return mService.getServiceIdentity();
267 }
268
269 /*** If this method returns true then the method getCustomProxyService must
270 * not return <code>null</code>.
271 */
272 public boolean hasCustomProxyService()
273 {
274 return mService.hasCustomProxyService();
275 }
276
277 /*** Returns an IProxyService that is responsible for handling remote invokations
278 * of this service.
279 */
280 public IProxyService getCustomProxyService(ITunnel tunnel)
281 {
282 return mService.getCustomProxyService(tunnel);
283 }
284
285 /*** Returns true if this service is stateless, that is, it is possile to change
286 * the actual service instance that is used by an IProxyService for this service.
287 * This means that it is possible that two consecutive invokations of methods
288 * on an IProxyService for this service are handled by two different service
289 * instances.
290 * <p>If this method returns <code>null</code> then hasCustomProxyService must
291 * return <code>false</code>.
292 */
293
294
295
296
297
298
299
300 /*** Returns <code>true</code> if this IProxyService can be reconnected to
301 * an IService.
302 */
303 public boolean isReconnectable()
304 {
305 return false;
306 }
307
308 /*** Tries to reconnect to the provided service. If the reconnection fails
309 * or if this IProxyService doesn't support reconnection an exception is
310 * thrown.
311 */
312 public void reconnect(ITunnel tunnel) throws ServiceException
313 {
314 throw new ServiceException("Operation not supported");
315 }
316
317 /*** Sets the ITunnel that should be used by this IProxyService.
318 */
319 public void setServiceTunnel(ITunnel tunnel)
320 {
321 }
322 }
323 }
324 }