View Javadoc

1   /* (c) Copyright 2003 Caleigo AB, All rights reserved. 
2    * 
3    * This library is free software; you can redistribute it and/or
4    * modify it under the terms of the GNU Lesser General Public
5    * License as published by the Free Software Foundation; either
6    * version 2.1 of the License, or (at your option) any later version.
7    * 
8    * This library is distributed in the hope that it will be useful,
9    * but WITHOUT ANY WARRANTY; without even the implied warranty of
10   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11   * Lesser General Public License for more details.
12   * 
13   * You should have received a copy of the GNU Lesser General Public
14   * License along with this library; if not, write to the Free Software
15   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
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      // Static data members -----------------------------------------------------
44      protected static ServiceProviderServer sInstance;
45      
46      // Data members ------------------------------------------------------------
47      protected List mTunnelServers;
48      protected Hashtable mMessageConsumers;
49      
50      // Static methods ----------------------------------------------------------
51      public static ServiceProviderServer getInstance()
52      {
53          if (sInstance == null)
54              sInstance = new ServiceProviderServer();
55          return sInstance;
56      }
57      
58      // Constructors ------------------------------------------------------------
59      protected ServiceProviderServer()
60      {
61          mTunnelServers = new ArrayList();
62          mMessageConsumers = new Hashtable();
63      }
64      
65      // Access methods ----------------------------------------------------------
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      // ITunnelServerListener implementation ------------------------------------
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     // Nested classes ----------------------------------------------------------
105     protected class MessageConsumer implements IMessageConsumer
106     {
107         // Data members --------------------------------------------------------
108         protected ProxyHandler mProxyHandler;
109         
110         // Constructors --------------------------------------------------------
111         public MessageConsumer(ITunnel tunnel)
112         {
113             mProxyHandler = new ProxyHandler(tunnel);
114             tunnel.addMessageConsumer(this);
115         }
116         
117         // IMessageConsumer implementation -------------------------------------
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         // Action methods ------------------------------------------------------
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         // Help methods --------------------------------------------------------
178         protected void reconnect(IService service)
179         {
180         }
181         
182         protected void setServiceTunnel(ITunnel tunnel)
183         {
184         }
185         
186         // Nested classes ------------------------------------------------------
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             // Data members ----------------------------------------------------
196             protected IService mService;
197             
198             // Constructors ----------------------------------------------------
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             // IService implementation -----------------------------------------
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             /*public boolean isStateless()
294             {
295                 return mService.isStateless();
296             }*/
297             
298             // IProxyService implementation ------------------------------------
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 }