OSDN Git Service

libjava/ChangeLog:
[pf3gnuchains/gcc-fork.git] / libjava / classpath / java / rmi / activation / Activatable.java
1 /* Activatable.java -- A common ancestor for the activatable objects.
2    Copyright (c) 1996, 1997, 1998, 1999, 2004, 2006
3    Free Software Foundation, Inc.
4
5 This file is part of GNU Classpath.
6
7 GNU Classpath is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11  
12 GNU Classpath is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU Classpath; see the file COPYING.  If not, write to the
19 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 02110-1301 USA.
21
22 Linking this library statically or dynamically with other modules is
23 making a combined work based on this library.  Thus, the terms and
24 conditions of the GNU General Public License cover the whole
25 combination.
26
27 As a special exception, the copyright holders of this library give you
28 permission to link this library with independent modules to produce an
29 executable, regardless of the license terms of these independent
30 modules, and to copy and distribute the resulting executable under
31 terms of your choice, provided that you also meet, for each linked
32 independent module, the terms and conditions of the license of that
33 module.  An independent module is a module which is not derived from
34 or based on this library.  If you modify this library, you may extend
35 this exception to your version of the library, but you are not
36 obligated to do so.  If you do not wish to do so, delete this
37 exception statement from your version. */
38
39
40 package java.rmi.activation;
41
42 import gnu.java.rmi.server.ActivatableServerRef;
43 import gnu.java.rmi.server.UnicastServer;
44 import gnu.java.rmi.server.UnicastServerRef;
45
46 import java.lang.reflect.Field;
47 import java.rmi.MarshalledObject;
48 import java.rmi.NoSuchObjectException;
49 import java.rmi.Remote;
50 import java.rmi.RemoteException;
51 import java.rmi.server.ObjID;
52 import java.rmi.server.RMIClientSocketFactory;
53 import java.rmi.server.RMIServerSocketFactory;
54 import java.rmi.server.RemoteObject;
55 import java.rmi.server.RemoteServer;
56 import java.rmi.server.UnicastRemoteObject;
57
58 /**
59  * A common ancestor for the implementations of the activatable objects. Such
60  * objects require persistent access over time and can be activated by the
61  * system. The derived classes also implements the needed interface of some
62  * remote object and usually have the two parameter constructor, the first
63  * parameter being the {@link ActivationID} and the second the
64  * {@link MarshalledObject}. Activatable is the main class that developers need
65  * to use to implement and manage activatable objects. It also contains methods
66  * for making activatable remote objects that are not derived from the 
67  * Activatable class.
68  * 
69  * @author Audrius Meskauskas (audriusa@bioinformatics.org) (from stub) 
70  */
71 public abstract class Activatable
72     extends RemoteServer
73 {
74
75   /**
76    * Use SVUID for interoperability.
77    */
78   static final long serialVersionUID = - 3120617863591563455L;
79   
80   /**
81    * The object activation id.
82    */
83   final ActivationID id;
84   
85   /**
86    * This constructor is used to register export the object on the given port. A
87    * subclass of the Activatable class calls this constructor to register and
88    * export the object during initial construction. As a side-effect of
89    * activatable object construction, the remote object is both "registered"
90    * with the activation system and "exported" (on an anonymous port, if port is
91    * zero) to the RMI runtime so that it is available to accept incoming calls
92    * from clients.
93    * 
94    * @param codebase the object code base url
95    * @param data the data, needed to activate the object.
96    * @param restart specifies reactivation mode after crash. If true, the object
97    *          is activated when activator is restarted or the activation group
98    *          is restarted. If false, the object is only activated on demand.
99    *          This flag does has no effect during the normal operation (the
100    *          object is normally activated on demand).
101    * @param port the port, on which the object will become available. The value
102    *          0 means anonymous port.
103    * @throws ActivationException if the activation failed
104    * @throws RemoteException if the remote call failed.
105    */
106   protected Activatable(String codebase, MarshalledObject<?> data,
107                         boolean restart, int port) throws ActivationException,
108       RemoteException
109   {
110     ActivationDesc descriptor = new ActivationDesc(getClass().getName(),
111                                                    codebase, data, restart);
112     id = obtainId(descriptor);
113     exportObject(this, id, port);
114   }
115
116   /**
117    * This constructor is used to register export the object on the given port,
118    * additionally specifying the socket factories. A subclass of the Activatable
119    * class calls this constructor to register and export the object during
120    * initial construction.
121    * 
122    * @param codebase the object code base url
123    * @param data the data, needed to activate the object.
124    * @param restart specifies reactivation mode after crash. If true, the object
125    *          is activated when activator is restarted or the activation group
126    *          is restarted. If false, the object is only activated on demand.
127    *          This flag does has no effect during the normal operation (the
128    *          object is normally activated on demand).
129    * @param port the port, on which the object will become available. The value
130    *          0 means anonymous port.
131    * @param csf the client socket factory
132    * @param ssf the server socket factory
133    * @throws ActivationException if the activation failed
134    * @throws RemoteException if the remote call failed.
135    */
136   protected Activatable(String codebase, MarshalledObject<?> data,
137                         boolean restart, int port, RMIClientSocketFactory csf,
138                         RMIServerSocketFactory ssf) throws ActivationException,
139       RemoteException
140   {
141     ActivationDesc descriptor = new ActivationDesc(getClass().getName(),
142                                                    codebase, data, restart);
143     id = obtainId(descriptor);
144     exportObject(this, id, port);
145   }
146
147   /**
148    * Creates the new instance of activatable with the given activation id and is
149    * listening at the given port. A subclass of the Activatable class calls this
150    * constructor when the object itself is activated via its special
151    * "activation" constructor with the two parameters ({@link ActivationID},
152    * {@link MarshalledObject}). As a side effect, the object is exported and is
153    * available to accept incomming calls.
154    * 
155    * @param anId the activation id
156    * @param port the port, on which the activatable will be listening
157    * @throws RemoteException if the activation failed.
158    */
159   protected Activatable(ActivationID anId, int port) throws RemoteException
160   {
161     id = anId;
162     try
163       {
164         exportObject(this, anId, port);
165       }
166     catch (Exception e)
167       {
168         e.printStackTrace();
169         RemoteException acex = 
170           new RemoteException("cannot export Activatable", e);
171         throw acex;
172       }
173   }
174
175   /**
176    * Creates the new instance of activatable with the given activation id and is
177    * listening at the given port, using the specified client and server sockets
178    * factories. A subclass of the Activatable class calls this
179    * constructor when the object itself is activated via its special
180    * "activation" constructor with the two parameters ({@link ActivationID},
181    * {@link MarshalledObject}). As a side effect, the object is exported and is
182    * available to accept incomming calls.
183    * 
184    * @param anId the activation id
185    * @param port the port, on which the activatable will be listening
186    * @param csf the client socket factory
187    * @param ssf the server socket factory
188    * 
189    * @throws RemoteException if the remote call failed
190    */
191   protected Activatable(ActivationID anId, int port, RMIClientSocketFactory csf,
192                         RMIServerSocketFactory ssf) throws RemoteException
193   {
194     id = anId;
195     try
196       {
197         exportObject(this, anId, port, csf, ssf);
198       }
199     catch (Exception e)
200       {
201         RemoteException acex = new RemoteException();
202         acex.initCause(e);
203         throw acex;
204       }
205   }
206   
207   /**
208    * Get the objects activation identifier.
209    * 
210    * @return the object activation identifier
211    */
212   protected ActivationID getID()
213   {
214     return id;
215   }
216   
217   /**
218    * Obtain the activation Id from the activation descriptor by registering
219    * within the current group.
220    */
221   static ActivationID obtainId(ActivationDesc descriptor)
222       throws RemoteException, UnknownGroupException, ActivationException
223   {
224     ActivationGroupID id = descriptor.getGroupID();
225     ActivationSystem system;
226
227     if (id != null)
228       system = id.getSystem();
229     else
230       system = ActivationGroup.currentGroupID().getSystem();
231     return system.registerObject(descriptor);
232   }
233   
234   /**
235    * This method registers an activatable object. The object is expected to be
236    * on the anonymous port (null client and server socket factories).
237    * 
238    * @param desc the object description.
239    * @return the remote stub for the activatable object (the first call on this
240    *         stub will activate the object).
241    * @throws UnknownGroupException if the object group identifier is unknown
242    * @throws ActivationException if the activation system is not running
243    * @throws RemoteException if the remote call fails
244    */
245   public static Remote register(ActivationDesc desc)
246       throws UnknownGroupException, ActivationException, RemoteException
247   {
248     ActivationID id = obtainId(desc);
249     try
250       {
251         return toStub(
252                       id,
253                       Thread.currentThread().getContextClassLoader().loadClass(
254                         desc.getClassName()));
255       }
256     catch (ClassNotFoundException e)
257       {
258         throw new ActivationException("Class not found: "+desc.getClassName());
259       }
260   }
261   
262   /**
263    * Inactivates and unexports the object. The subsequent calls will activate
264    * the object again. The object is not inactivated if it is currently
265    * executing calls.
266    * 
267    * @param id the id of the object being inactivated
268    * @return true if the object has been inactivated, false if it has not been
269    *         inactivated because of the running or pending calls.
270    * @throws UnknownObjectException if the object is unknown.
271    * @throws ActivationException if the object group is not active
272    * @throws RemoteException if the remote call fails
273    */
274   public static boolean inactive(ActivationID id)
275       throws UnknownObjectException, ActivationException, RemoteException
276   {
277     if (id.group!=null)
278       id.group.inactiveObject(id);
279     return UnicastRemoteObject.unexportObject(id.activate(false), false);
280   }
281   
282   /**
283    * Unregister the object (the object will no longer be activable with that id)
284    * 
285    * @param id the object id
286    * @throws UnknownObjectException if the id is unknown
287    * @throws ActivationException if the activation system is not running
288    * @throws RemoteException if the remote call fails.
289    */
290   public static void unregister(ActivationID id) throws UnknownObjectException,
291       ActivationException, RemoteException
292   {
293     ActivationGroup.currentGroupId.getSystem().unregisterObject(id);
294     UnicastServer.unregisterActivatable(id);
295   }
296   
297   /**
298    * Register and export the object that activatable object that is not derived
299    * from the Activatable super class. It creates and registers the object
300    * activation descriptor. There is no need to call this method if the object
301    * extends Activable, as its work is done in the constructor
302    * {@link #Activatable(String, MarshalledObject, boolean, int)}.
303    * 
304    * @param obj the object, that is exported, becoming available at the given
305    *          port.
306    * @param location the object code location (codebase).
307    * @param data the data, needed to activate the object
308    * @param restart the restart mode
309    * @param port the port, where the object will be available
310    * 
311    * @return the created object activation ID.
312    * 
313    * @throws ActivationException if the activation group is not active
314    * @throws RemoteException if the registration or export fails
315    */
316   public static ActivationID exportObject(Remote obj, String location,
317                                           MarshalledObject<?> data,
318                                           boolean restart, int port)
319       throws ActivationException, RemoteException
320   {
321     ActivationDesc descriptor = new ActivationDesc(obj.getClass().getName(),
322                                                    location, data, restart);
323     ActivationID id = obtainId(descriptor);
324     Remote stub = exportObject(obj, id, port);    
325     return id;
326   }
327
328   /**
329    * Register and export the object that activatable object that is not derived
330    * from the Activatable super class. It creates and registers the object
331    * activation descriptor. There is no need to call this method if the object
332    * extends Activable, as its work is done in the constructor
333    * {@link #Activatable(String, MarshalledObject, boolean, int, RMIClientSocketFactory, RMIServerSocketFactory)}
334    * 
335    * @param obj the object, that is exported, becoming available at the given
336    *          port.
337    * @param location the object code location (codebase).
338    * @param data the data, needed to activate the object
339    * @param restart the restart mode
340    * @param port the port, where the object will be available
341    * @param csf the client socket factory
342    * @param ssf the server socket factory
343    * 
344    * @return the created object activation ID.
345    * 
346    * @throws ActivationException if the activation group is not active
347    * @throws RemoteException if the registration or export fails
348    */
349   public static ActivationID exportObject(Remote obj, String location,
350                                           MarshalledObject data,
351                                           boolean restart, int port,
352                                           RMIClientSocketFactory csf,
353                                           RMIServerSocketFactory ssf)
354       throws ActivationException, RemoteException
355   {
356     ActivationDesc descriptor = new ActivationDesc(obj.getClass().getName(),
357                                                    location, data, restart);
358     ActivationID id = obtainId(descriptor);
359     Remote stub = exportObject(obj, id, port, csf, ssf);    
360     return id;
361
362   }
363
364   /**
365    * During activation, this exportObject method should be invoked explicitly by
366    * the activatable object, that does is not derived from the Activatable
367    * class. There is no need to call this method if the object extends
368    * Activable, as its work is done in the constructor
369    * {@link #Activatable(ActivationID, int)}
370    * 
371    * @param obj the object
372    * @param id the known activation id
373    * @param port the object port
374    *  
375    * @return the remote stub of the activatable object
376    * 
377    * @throws RemoteException if the object export fails
378    */
379   public static Remote exportObject(Remote obj, ActivationID id, int port)
380       throws RemoteException
381   {
382     Remote stub = export(id, obj, port, null);
383     return stub;
384   }
385
386   /**
387    * During activation, this exportObject method should be invoked explicitly by
388    * the activatable object, that does is not derived from the Activatable
389    * class. There is no need to call this method if the object extends
390    * Activable, as its work is done in the constructor
391    * {@link #Activatable(ActivationID, int)}
392    * 
393    * @param obj the object
394    * @param id the known activation id
395    * @param port the object port
396    * @param csf the client socket factory
397    * @param ssf the server socket factory
398    *  
399    * @return the remote stub of the activatable object
400    * 
401    * @throws RemoteException if the object export fails
402    */
403   public static Remote exportObject(Remote obj, ActivationID id, int port,
404                                     RMIClientSocketFactory csf,
405                                     RMIServerSocketFactory ssf)
406       throws RemoteException
407   {
408     Remote stub = export(id, obj, port, ssf); 
409     return stub;
410
411   }
412
413   /**
414    * Make the remote object unavailable for incoming calls. This method also
415    * unregisters the object, so it cannot be activated again by incomming call
416    * (unless registered).
417    * 
418    * @param obj the object to unexport
419    * @param force if true, cancel all pending or running calls to that object
420    *          (if false, the object with such calls is not unexported and false
421    *          is returned by this method).
422    * @return if the object was successfully unexported, false otherwise
423    * @throws NoSuchObjectException if such object is not known
424    */
425   public static boolean unexportObject(Remote obj, boolean force)
426       throws NoSuchObjectException
427   {
428     Object aref = UnicastServer.getExportedRef(obj);
429     
430     // Unregister it also (otherwise will be activated during the subsequent
431     // call.
432     if (aref instanceof ActivatableServerRef)
433       {
434         ActivatableServerRef aar = (ActivatableServerRef) aref;
435         UnicastServer.unregisterActivatable(aar.actId);
436       }
437     return UnicastRemoteObject.unexportObject(obj, force);
438   }
439   
440   static Remote exportObject(Remote obj, int port, 
441                              RMIServerSocketFactory serverSocketFactory) 
442     throws RemoteException
443   {
444     UnicastServerRef sref = null;
445     if (obj instanceof RemoteObject)
446       sref = (UnicastServerRef) ((RemoteObject) obj).getRef();
447
448     if (sref == null)
449       sref = new UnicastServerRef(new ObjID(), port, serverSocketFactory);
450
451     Remote stub = sref.exportObject(obj);
452     // addStub(obj, stub); 
453     // TODO Need to change the place of the stub repository
454     return stub;
455   }
456   
457   /**
458    * Create and export the new remote object, making it available at the given
459    * port, using sockets, produced by the specified factories.
460    * 
461    * @param port the port, on that the object should become available. Zero
462    *          means anonymous port.
463    * @param serverSocketFactory the server socket factory
464    */
465   private static Remote export(ActivationID id, Remote obj, int port,
466                                RMIServerSocketFactory serverSocketFactory)
467       throws RemoteException
468   {
469     ActivatableServerRef sref = null;
470     sref = new ActivatableServerRef(makeId(id), id, port, serverSocketFactory);
471     return sref.exportObject(obj);
472   }  
473   
474   /**
475    * Make the object ID from the activation ID. The same activation ID always
476    * produces the identical object id.
477    * 
478    * @param aid the activation id
479    * 
480    * @return the object id
481    */
482   private static ObjID makeId(ActivationID aid)
483   {
484     ObjID id = new ObjID(0);
485     
486     // The fields of both ObjID and ActivationID must be package private,
487     // so we need to use the reflection to access them anyway.
488     // Probably other implementations use some very different approach.
489     
490     try
491       {
492         Field idUid =  ObjID.class.getDeclaredField("space");
493         Field aidUid = ActivationID.class.getDeclaredField("uid");
494         
495         aidUid.setAccessible(true);
496         idUid.setAccessible(true);
497         
498         idUid.set(id, aidUid.get(aid));
499       }
500     catch (Exception e)
501       {
502         InternalError ierr = new InternalError("Unable to set UID field");
503         ierr.initCause(e);
504         throw ierr;
505       }
506     
507     return id;
508   }  
509   
510   /**
511    * Connect the object to the UnicastServer (export), but not activate it.
512    * The object will be activated on the first call.
513    */
514   static Remote toStub(ActivationID anId, Class stubFor)
515   {
516     try
517       {
518         ActivatableServerRef asr = 
519           new ActivatableServerRef(makeId(anId), anId, 0, null);
520         UnicastServer.exportActivatableObject(asr);
521         return asr.exportClass(stubFor);
522       }
523     catch (RemoteException e)
524       {
525         InternalError ierr = new InternalError(
526           "Failed to obtain activatable stub");
527         ierr.initCause(e);
528         throw ierr;
529       }
530   }
531 }