KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > sapia > ubik > rmi > server > Hub


1 package org.sapia.ubik.rmi.server;
2
3 import java.io.IOException JavaDoc;
4 import java.lang.reflect.Proxy JavaDoc;
5 import java.rmi.RemoteException JavaDoc;
6 import java.util.ArrayList JavaDoc;
7 import java.util.List JavaDoc;
8 import java.util.Properties JavaDoc;
9
10 import javax.naming.Name JavaDoc;
11
12 import org.sapia.taskman.PeriodicTaskDescriptor;
13 import org.sapia.taskman.TaskManager;
14 import org.sapia.ubik.net.Connection;
15 import org.sapia.ubik.net.ServerAddress;
16 import org.sapia.ubik.net.TCPAddress;
17 import org.sapia.ubik.rmi.Consts;
18 import org.sapia.ubik.rmi.server.gc.CommandRefer;
19 import org.sapia.ubik.rmi.server.perf.PerfAnalyzer;
20 import org.sapia.ubik.rmi.server.transport.Connections;
21 import org.sapia.ubik.rmi.server.transport.TransportManager;
22
23
24 /**
25  * This class is the single-entry point into Ubik RMI's API.
26  *
27  * @author Yanick Duchesne
28  * <dl>
29  * <dt><b>Copyright:</b><dd>Copyright &#169; 2002-2003 <a HREF="http://www.sapia-oss.org">Sapia Open Source Software</a>. All Rights Reserved.</dd></dt>
30  * <dt><b>License:</b><dd>Read the license.txt file of the jar or visit the
31  * <a HREF="http://www.sapia-oss.org/license.html">license page</a> at the Sapia OSS web site</dd></dt>
32  * </dl>
33  */

34 public class Hub {
35   /** The hub's task manager */
36   public static final TaskManager taskMan = new UbikTaskManager();
37
38   /** The object implementing client-side behavior */
39   public static final ClientRuntime clientRuntime = new ClientRuntime(taskMan);
40
41   /** The object implementing server-side behavior */
42   public static final ServerRuntime serverRuntime = new ServerRuntime(taskMan);
43   static final PerfAnalyzer _perf;
44   static boolean _callback;
45   static boolean _shutdown;
46
47   static {
48     List JavaDoc tasks = new ArrayList JavaDoc();
49     tasks.add(new PeriodicTaskDescriptor("Perf. Analyzer", 25000,
50         _perf = PerfAnalyzer.getInstance()));
51
52     taskMan.addTaskDescriptors(tasks);
53
54     _callback = (System.getProperty(Consts.CALLBACK_ENABLED) != null) &&
55       System.getProperty(Consts.CALLBACK_ENABLED).equalsIgnoreCase("true");
56   }
57
58   /**
59    * Generates the stub for the object passed in and returns it.
60    *
61    * @return an <code>Object</code> which is the stub of the instance passed in.
62    * @throws RemoteException if a problem occurs performing the connection.
63    */

64   public static Object JavaDoc toStub(Object JavaDoc o) throws RemoteException JavaDoc {
65     if (o instanceof Stub) {
66       return o;
67     }
68
69     if (!serverRuntime.server.isInit(ServerTable.DEFAULT_TRANSPORT_TYPE)) {
70       serverRuntime.server.init(o, ServerTable.DEFAULT_TRANSPORT_TYPE);
71
72       ServerRef ref = serverRuntime.server.getServerRef(ServerTable.DEFAULT_TRANSPORT_TYPE);
73
74       return ref.stub;
75     } else {
76       return getStubFor(serverRuntime.server.initStub(o,
77           ServerTable.DEFAULT_TRANSPORT_TYPE), o);
78     }
79   }
80
81   /**
82    * Returns a "reliable" stub for the given passed in stub; the dynamically generated
83    * proxy (created with Java's reflection API) wraps an <code>InvocationHandler</code>
84    * of the <code>StubHandlerReliable</code> class.
85    * <p>
86    * The object passed as a parameter is expected to be a stub whose invocation handler
87    * is assumed to be of the <code>StubHandlerBasic</code> type. This method thus performs
88    * a stub substitution.
89    *
90    * @see RemoteRefReliable
91    * @see RemoteRefEx
92    *
93    * @return a "reliable" stub for the given stub.
94    */

95   public static Object JavaDoc toReliableStub(Object JavaDoc obj) {
96     if (obj instanceof Stub && Proxy.isProxyClass(obj.getClass())) {
97       RemoteRef handler = (RemoteRef) Proxy.getInvocationHandler(obj);
98
99       RemoteRefReliable rmiHandler = new RemoteRefReliable(handler.getOid(),
100           handler.getServerAddress());
101       rmiHandler.setCallBack(handler.isCallBack());
102
103       ObjectTable.Ref ref = (ObjectTable.Ref) serverRuntime.objectTable.getRefs()
104                                                                        .get(handler.getOid());
105
106       if (ref == null) {
107         throw new NullPointerException JavaDoc("no object for: " + handler.getOid());
108       }
109
110       Object JavaDoc proxy = Proxy.newProxyInstance(Thread.currentThread()
111                                                   .getContextClassLoader(),
112           ServerTable.getInterfacesFor(ref._obj.getClass()), rmiHandler);
113
114       return proxy;
115     } else {
116       return obj;
117     }
118   }
119
120   /**
121    * Returns a stateless stub for the given object.
122    *
123    * @param name the name of the object for which a stateless stub should be returned.
124    * @param domain the name of the domain to which the object "belongs".
125    * @param obj
126    * @return a <code>Stateless</code> stub.
127    *
128    * @see Stateless
129    */

130   public static Object JavaDoc toStatelessStub(Name JavaDoc name, String JavaDoc domain, Object JavaDoc obj) {
131     if (obj instanceof Stub && Proxy.isProxyClass(obj.getClass())) {
132       RemoteRef handler = (RemoteRef) Proxy.getInvocationHandler(obj);
133
134       RemoteRefStateless rmiHandler;
135       List JavaDoc lst = new ArrayList JavaDoc(1);
136       lst.add(handler);
137       rmiHandler = RemoteRefStateless.fromRemoteRefs(name, domain, lst);
138
139       ObjectTable.Ref ref = (ObjectTable.Ref) serverRuntime.objectTable.getRefs()
140                                                                        .get(handler.getOid());
141
142       if (ref == null) {
143         throw new NullPointerException JavaDoc("no object for: " + handler.getOid());
144       }
145
146       Object JavaDoc proxy = Proxy.newProxyInstance(Thread.currentThread()
147                                                   .getContextClassLoader(),
148           ServerTable.getInterfacesFor(ref._obj.getClass()), rmiHandler);
149
150       return proxy;
151     } else {
152       return obj;
153     }
154   }
155
156   /**
157    * "Exports" the passed in object as a remote RMI server: this method
158    * internally starts an RMI server that listens on a random port and implements
159    * the interfaces of the passed in object. The stub is returned and can be bound
160    * to the JNDI.
161    *
162    * @see #exportObject(Object, int)
163    * @see #connect(String, int)
164    * @return the stub corresponding to the exported object.
165    * @throws RemoteException if a problem occurs performing the connection.
166    */

167   public static Object JavaDoc exportObject(Object JavaDoc o) throws RemoteException JavaDoc {
168     if (!serverRuntime.server.isInit(ServerTable.DEFAULT_TRANSPORT_TYPE)) {
169       serverRuntime.server.init(o, ServerTable.DEFAULT_TRANSPORT_TYPE);
170
171       ServerRef ref = serverRuntime.server.getServerRef(ServerTable.DEFAULT_TRANSPORT_TYPE);
172
173       return ref.stub;
174     } else {
175       return getStubFor(serverRuntime.server.initStub(o,
176           ServerTable.DEFAULT_TRANSPORT_TYPE), o);
177     }
178   }
179
180   /**
181    * This method creates a server listening on the specified port.
182    *
183    * @see #exportObject(Object)
184    * @throws RemoteException if a problem occurs performing the connection.
185    * @return the stub for the given exported object.
186    */

187   public static Object JavaDoc exportObject(Object JavaDoc o, int port)
188     throws RemoteException JavaDoc {
189     if (!serverRuntime.server.isInit(ServerTable.DEFAULT_TRANSPORT_TYPE)) {
190       serverRuntime.server.init(o, port);
191
192       ServerRef ref = serverRuntime.server.getServerRef(ServerTable.DEFAULT_TRANSPORT_TYPE);
193
194       return ref.stub;
195     } else {
196       return getStubFor(serverRuntime.server.initStub(o,
197           ServerTable.DEFAULT_TRANSPORT_TYPE), o);
198     }
199   }
200
201   /**
202    * Exports the given object as a server (and creates a remote reference). The properties
203    * passed in must contain the property identifying the desired "transport type"
204    * (ubik.rmi.transport.type).
205    * <p>
206    * The method returns the stub for the given object.
207    *
208    * @return the stub of the exported server.
209    * @see TransportManager
210    * @see TransportManager#getProviderFor(String)
211    * @see org.sapia.ubik.rmi.server.transport.TransportProvider
212    */

213   public static Object JavaDoc exportObject(Object JavaDoc o, Properties JavaDoc props)
214     throws RemoteException JavaDoc {
215     String JavaDoc transportType = props.getProperty(Consts.TRANSPORT_TYPE);
216
217     if (transportType == null) {
218       transportType = System.getProperty(Consts.TRANSPORT_TYPE);
219     }
220
221     if (transportType == null) {
222       throw new RemoteException JavaDoc(Consts.TRANSPORT_TYPE +
223         " property not specified");
224     }
225
226     if (!serverRuntime.server.isInit(transportType)) {
227       serverRuntime.server.init(o, transportType, props);
228
229       ServerRef ref = serverRuntime.server.getServerRef(transportType);
230
231       return ref.stub;
232     } else {
233       return getStubFor(serverRuntime.server.initStub(o, transportType), o);
234     }
235   }
236
237   /**
238    * Exports the given object as a remote object that will receive request through a server
239    * that must already have been exported for the given transport type.
240    * <p>
241    * The method returns the stub for the given object.
242
243    * @param o an <code>Object</code> to export.
244    * @param transportType the identifier of the transport layer to which the given object
245    * will be exported.
246    * @return a stub.
247    * @throws RemoteException if the object could not be exported.
248    */

249   public static Object JavaDoc exportObject(Object JavaDoc o, String JavaDoc transportType)
250     throws RemoteException JavaDoc {
251     if (!serverRuntime.server.isInit(transportType)) {
252       throw new RemoteException JavaDoc("No server was exported for transport: " +
253         transportType);
254     } else {
255       return getStubFor(serverRuntime.server.initStub(o, transportType), o);
256     }
257   }
258
259   /**
260    * This method "unexports" an object that was exported through one of this
261    * class' <code>export()</code> methods. The unexported object will not receive
262    * remote method calls anymore.
263    * <p>
264    * NOTE: this method does not stop the server through which the exported instance
265    * is receiving remote method calls. To stop the servers that have been started by
266    * the <code>Hub</code>, call the latter's <code>shutdown()</code> method.
267    *
268    * @see #shutdown(long)
269    *
270    * @param o the exported object that is to be unexported.
271    */

272   public static void unexport(Object JavaDoc o) {
273     serverRuntime.objectTable.remove(o);
274   }
275
276   /**
277    * This method "unexports" all objects whose class was loaded by the given <code>ClassLoader</code>.
278    * <p>
279    * This method can be useful in hot-deploy scenarios.
280    * <p>
281    * NOTE: this method does not stop the server through which the exported instances (that
282    * correspond to the given classloader) are receiving remote method calls. To stop the servers that have been started by
283    * the <code>Hub</code>, call the latter's <code>shutdown()</code> method.
284    *
285    * @see #shutdown(long)
286    *
287    * @param loader
288    */

289   public static void unexport(ClassLoader JavaDoc loader) {
290     serverRuntime.objectTable.remove(loader);
291   }
292
293   /**
294    * This method allows connecting to a RMI server listening to the given host
295    * and port.
296    *
297    * @throws RemoteException if a problem occurs performing the connection.
298    */

299   public static Object JavaDoc connect(String JavaDoc host, int port) throws RemoteException JavaDoc {
300     return connect(new TCPAddress(host, port));
301   }
302
303   /**
304    * This method allows connecting to a RMI server listening on the given address.
305    *
306    * @param address the <code>ServerAddress</code> corresponding to the target server's
307    * physical endpoint.
308    *
309    * @throws RemoteException if a problem occurs performing the connection.
310    */

311   public static Object JavaDoc connect(ServerAddress address) throws RemoteException JavaDoc {
312     Connection conn = null;
313     Object JavaDoc toReturn;
314
315     try {
316       conn = TransportManager.getConnectionsFor(address).acquire();
317
318       try {
319         conn.send(new CommandConnect(address.getTransportType()));
320       } catch (RemoteException JavaDoc e) {
321         Connections conns = TransportManager.getConnectionsFor(address);
322         conns.clear();
323         conn = conns.acquire();
324         conn.send(new CommandConnect(address.getTransportType()));
325       }
326
327       toReturn = conn.receive();
328     } catch (IOException JavaDoc e) {
329       throw new RemoteException JavaDoc("error connecting to remote server", e);
330     } catch (ClassNotFoundException JavaDoc e) {
331       throw new RemoteException JavaDoc("could not find class", e);
332     } finally {
333       if (conn != null) {
334         TransportManager.getConnectionsFor(address).release(conn);
335       }
336     }
337
338     if (toReturn instanceof Throwable JavaDoc) {
339       if (toReturn instanceof RuntimeException JavaDoc) {
340         throw (RuntimeException JavaDoc) toReturn;
341       } else {
342         throw new RemoteException JavaDoc("problem connecting to remote server",
343           (Throwable JavaDoc) toReturn);
344       }
345     }
346
347     return toReturn;
348   }
349
350   /**
351    * Returns the address of the server for the given transport type.
352    * @param transportType the logical identifier of a "transport type".
353    * @return a <code>ServerAddress</code>,
354    */

355   public static ServerAddress getServerAddressFor(String JavaDoc transportType) {
356     return serverRuntime.server.getServerAddress(transportType);
357   }
358
359   /**
360    * Returns a stub for the given object. This method is usually
361    * not called by client application. It is meant for use by the different
362    * transport layers.
363    *
364    * @param o an object.
365    * @param caller the VM identifier of the client that triggered the creation
366    * of the returned remote reference.
367    * @param transportType the "transport type" for which to return a remote reference.
368    * @return a stub.
369    * @throws RemoteException
370    *
371    * @see #asRemoteRef(Object, VmId, String)
372    */

373   public static Object JavaDoc asRemote(Object JavaDoc o, VmId caller, String JavaDoc transportType)
374     throws RemoteException JavaDoc {
375     if (o instanceof Stub) {
376       return o;
377     }
378
379     return getStubFor(asRemoteRef(o, caller, transportType), o);
380   }
381
382   /**
383    * Returns a remote reference for the given object. This method is usually
384    * not called by client application. It is meant for use by the different
385    * transport layers.
386    *
387    * @param o an object.
388    * @param caller the VM identifier of the client that triggered the creation
389    * of the returned remote reference.
390    * @param transportType the "transport type" for which to return a remote reference.
391    * @return a <code>RemoteRef</code>.
392    * @throws RemoteException
393    */

394   public static RemoteRef asRemoteRef(Object JavaDoc o, VmId caller,
395     String JavaDoc transportType) throws RemoteException JavaDoc {
396     if (_perf.isEnabled()) {
397       _perf.getTopic(Hub.class.getName() + ".CreateRemoteRef").start();
398     }
399
400     if (!serverRuntime.server.isInit(transportType)) {
401       serverRuntime.server.init(transportType);
402     }
403
404     OID oid = ServerTable.generateOID();
405
406     if (_perf.isEnabled()) {
407       _perf.getTopic(Hub.class.getName() + ".RegisterRemoteRef").start();
408     }
409
410     serverRuntime.gc.registerRef(caller, oid, o);
411
412     if (_perf.isEnabled()) {
413       _perf.getTopic(Hub.class.getName() + ".RegisterRemoteRef").end();
414     }
415
416     RemoteRef rmiHandler;
417
418     if (_perf.isEnabled()) {
419       _perf.getTopic(Hub.class.getName() + ".InstantiateRemoteRef").start();
420     }
421
422     rmiHandler = new RemoteRefEx(oid,
423         serverRuntime.server.getServerRef(transportType).server.getServerAddress());
424
425     rmiHandler.setCallBack(_callback);
426
427     if (_perf.isEnabled()) {
428       _perf.getTopic(Hub.class.getName() + ".InstantiateRemoteRef").end();
429     }
430
431     if (_perf.isEnabled()) {
432       _perf.getTopic(Hub.class.getName() + ".CreateRemoteRef").end();
433     }
434
435     return rmiHandler;
436   }
437
438   /**
439    * Returns true if the Hub is shut down.
440    *
441    * @return <code>true</code> if the Hub is shut down.
442    */

443   public static boolean isShutdown() {
444     return _shutdown;
445   }
446
447   /**
448    * Shuts down this instance; some part of the shutdown can be asynchronous.
449    * A timeout must be given in order not to risk the shutdown to last for too long.
450    *
451    * @param timeout a shutdown "timeout", in millis.
452    * @throws InterruptedException
453    */

454   public static synchronized void shutdown(long timeout)
455     throws InterruptedException JavaDoc {
456     if (_shutdown) {
457       return;
458     }
459
460     Log.warning(Hub.class, "Shutting down task manager");
461     taskMan.shutdown();
462     Log.warning(Hub.class, "Shutting down client runtime");
463     clientRuntime.shutdown(timeout);
464     Log.warning(Hub.class, "Shutting down server runtime");
465     serverRuntime.shutdown(timeout);
466     Log.warning(Hub.class, "Shutting down event channels");
467     EventChannelSingleton.shutdown();
468     Log.warning(Hub.class, "Shutting down transport manager");
469     TransportManager.shutdown();
470     Log.warning(Hub.class, "Shut down completed");
471     _shutdown = true;
472   }
473
474   public static Object JavaDoc getStubFor(RemoteRef ref, Object JavaDoc remote) {
475     Class JavaDoc[] cachedInterfaces = ServerTable.getInterfacesFor(remote.getClass());
476
477     if (_perf.isEnabled()) {
478       _perf.getTopic(Hub.class.getName() + ".CreateStub").start();
479     }
480
481     Object JavaDoc proxy = Proxy.newProxyInstance(Thread.currentThread()
482                                                 .getContextClassLoader(),
483         cachedInterfaces, ref);
484
485     if (_perf.isEnabled()) {
486       _perf.getTopic(Hub.class.getName() + ".CreateStub").end();
487     }
488
489     return proxy;
490   }
491
492   static void createReference(ServerAddress address, OID oid)
493     throws RemoteException JavaDoc {
494     Connections conns = TransportManager.getConnectionsFor(address);
495
496     try {
497       doSend(conns, oid);
498     } catch (ClassNotFoundException JavaDoc e) {
499       throw new RemoteException JavaDoc("could refer to object: " + oid + "@" +
500         address, e);
501     } catch (RemoteException JavaDoc e) {
502       conns.clear();
503
504       try {
505         doSend(conns, oid);
506       } catch (Exception JavaDoc e2) {
507         throw new RemoteException JavaDoc("could refer to object: " + oid + "@" +
508           address, e2);
509       }
510     } catch (IOException JavaDoc e) {
511       throw new RemoteException JavaDoc("could refer to object: " + oid + "@" +
512         address, e);
513     }
514   }
515
516   private static void doSend(Connections conns, OID oid)
517     throws RemoteException JavaDoc, IOException JavaDoc, ClassNotFoundException JavaDoc {
518     Connection conn = null;
519
520     try {
521       conn = conns.acquire();
522       conn.send(new CommandRefer(oid));
523       conn.receive();
524     } finally {
525       if (conn != null) {
526         conns.release(conn);
527       }
528     }
529   }
530 }
531
Popular Tags