OSDN Git Service

libjava/ChangeLog:
[pf3gnuchains/gcc-fork.git] / libjava / classpath / java / rmi / activation / Activatable.java
index b4c38bf..eb51100 100644 (file)
@@ -1,5 +1,6 @@
-/* Activatable.java --
-   Copyright (c) 1996, 1997, 1998, 1999, 2004  Free Software Foundation, Inc.
+/* Activatable.java -- A common ancestor for the activatable objects.
+   Copyright (c) 1996, 1997, 1998, 1999, 2004, 2006
+   Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
 
@@ -38,68 +39,493 @@ exception statement from your version. */
 
 package java.rmi.activation;
 
+import gnu.java.rmi.server.ActivatableServerRef;
+import gnu.java.rmi.server.UnicastServer;
+import gnu.java.rmi.server.UnicastServerRef;
+
+import java.lang.reflect.Field;
 import java.rmi.MarshalledObject;
 import java.rmi.NoSuchObjectException;
 import java.rmi.Remote;
 import java.rmi.RemoteException;
+import java.rmi.server.ObjID;
 import java.rmi.server.RMIClientSocketFactory;
 import java.rmi.server.RMIServerSocketFactory;
+import java.rmi.server.RemoteObject;
 import java.rmi.server.RemoteServer;
+import java.rmi.server.UnicastRemoteObject;
 
-public abstract class Activatable extends RemoteServer
+/**
+ * A common ancestor for the implementations of the activatable objects. Such
+ * objects require persistent access over time and can be activated by the
+ * system. The derived classes also implements the needed interface of some
+ * remote object and usually have the two parameter constructor, the first
+ * parameter being the {@link ActivationID} and the second the
+ * {@link MarshalledObject}. Activatable is the main class that developers need
+ * to use to implement and manage activatable objects. It also contains methods
+ * for making activatable remote objects that are not derived from the 
+ * Activatable class.
+ * 
+ * @author Audrius Meskauskas (audriusa@bioinformatics.org) (from stub) 
+ */
+public abstract class Activatable
+    extends RemoteServer
 {
-static final long serialVersionUID = -3120617863591563455L;
 
-protected Activatable(String location, MarshalledObject data, boolean restart, int port) throws ActivationException, RemoteException {
-       throw new Error("Not implemented");
-}
+  /**
+   * Use SVUID for interoperability.
+   */
+  static final long serialVersionUID = - 3120617863591563455L;
+  
+  /**
+   * The object activation id.
+   */
+  final ActivationID id;
+  
+  /**
+   * This constructor is used to register export the object on the given port. A
+   * subclass of the Activatable class calls this constructor to register and
+   * export the object during initial construction. As a side-effect of
+   * activatable object construction, the remote object is both "registered"
+   * with the activation system and "exported" (on an anonymous port, if port is
+   * zero) to the RMI runtime so that it is available to accept incoming calls
+   * from clients.
+   * 
+   * @param codebase the object code base url
+   * @param data the data, needed to activate the object.
+   * @param restart specifies reactivation mode after crash. If true, the object
+   *          is activated when activator is restarted or the activation group
+   *          is restarted. If false, the object is only activated on demand.
+   *          This flag does has no effect during the normal operation (the
+   *          object is normally activated on demand).
+   * @param port the port, on which the object will become available. The value
+   *          0 means anonymous port.
+   * @throws ActivationException if the activation failed
+   * @throws RemoteException if the remote call failed.
+   */
+  protected Activatable(String codebase, MarshalledObject<?> data,
+                        boolean restart, int port) throws ActivationException,
+      RemoteException
+  {
+    ActivationDesc descriptor = new ActivationDesc(getClass().getName(),
+                                                   codebase, data, restart);
+    id = obtainId(descriptor);
+    exportObject(this, id, port);
+  }
 
-protected Activatable(String location, MarshalledObject data, boolean restart, int port, RMIClientSocketFactory csf, RMIServerSocketFactory ssf) throws ActivationException, RemoteException {
-       throw new Error("Not implemented");
-}
+  /**
+   * This constructor is used to register export the object on the given port,
+   * additionally specifying the socket factories. A subclass of the Activatable
+   * class calls this constructor to register and export the object during
+   * initial construction.
+   * 
+   * @param codebase the object code base url
+   * @param data the data, needed to activate the object.
+   * @param restart specifies reactivation mode after crash. If true, the object
+   *          is activated when activator is restarted or the activation group
+   *          is restarted. If false, the object is only activated on demand.
+   *          This flag does has no effect during the normal operation (the
+   *          object is normally activated on demand).
+   * @param port the port, on which the object will become available. The value
+   *          0 means anonymous port.
+   * @param csf the client socket factory
+   * @param ssf the server socket factory
+   * @throws ActivationException if the activation failed
+   * @throws RemoteException if the remote call failed.
+   */
+  protected Activatable(String codebase, MarshalledObject<?> data,
+                        boolean restart, int port, RMIClientSocketFactory csf,
+                        RMIServerSocketFactory ssf) throws ActivationException,
+      RemoteException
+  {
+    ActivationDesc descriptor = new ActivationDesc(getClass().getName(),
+                                                   codebase, data, restart);
+    id = obtainId(descriptor);
+    exportObject(this, id, port);
+  }
 
-protected Activatable(ActivationID id, int port) throws RemoteException {
-       throw new Error("Not implemented");
-}
+  /**
+   * Creates the new instance of activatable with the given activation id and is
+   * listening at the given port. A subclass of the Activatable class calls this
+   * constructor when the object itself is activated via its special
+   * "activation" constructor with the two parameters ({@link ActivationID},
+   * {@link MarshalledObject}). As a side effect, the object is exported and is
+   * available to accept incomming calls.
+   * 
+   * @param anId the activation id
+   * @param port the port, on which the activatable will be listening
+   * @throws RemoteException if the activation failed.
+   */
+  protected Activatable(ActivationID anId, int port) throws RemoteException
+  {
+    id = anId;
+    try
+      {
+        exportObject(this, anId, port);
+      }
+    catch (Exception e)
+      {
+        e.printStackTrace();
+        RemoteException acex = 
+          new RemoteException("cannot export Activatable", e);
+        throw acex;
+      }
+  }
 
-protected Activatable(ActivationID id, int port, RMIClientSocketFactory csf, RMIServerSocketFactory ssf) throws RemoteException {
-       throw new Error("Not implemented");
-}
+  /**
+   * Creates the new instance of activatable with the given activation id and is
+   * listening at the given port, using the specified client and server sockets
+   * factories. A subclass of the Activatable class calls this
+   * constructor when the object itself is activated via its special
+   * "activation" constructor with the two parameters ({@link ActivationID},
+   * {@link MarshalledObject}). As a side effect, the object is exported and is
+   * available to accept incomming calls.
+   * 
+   * @param anId the activation id
+   * @param port the port, on which the activatable will be listening
+   * @param csf the client socket factory
+   * @param ssf the server socket factory
+   * 
+   * @throws RemoteException if the remote call failed
+   */
+  protected Activatable(ActivationID anId, int port, RMIClientSocketFactory csf,
+                        RMIServerSocketFactory ssf) throws RemoteException
+  {
+    id = anId;
+    try
+      {
+        exportObject(this, anId, port, csf, ssf);
+      }
+    catch (Exception e)
+      {
+        RemoteException acex = new RemoteException();
+        acex.initCause(e);
+        throw acex;
+      }
+  }
+  
+  /**
+   * Get the objects activation identifier.
+   * 
+   * @return the object activation identifier
+   */
+  protected ActivationID getID()
+  {
+    return id;
+  }
+  
+  /**
+   * Obtain the activation Id from the activation descriptor by registering
+   * within the current group.
+   */
+  static ActivationID obtainId(ActivationDesc descriptor)
+      throws RemoteException, UnknownGroupException, ActivationException
+  {
+    ActivationGroupID id = descriptor.getGroupID();
+    ActivationSystem system;
 
-protected ActivationID getID() {
-       throw new Error("Not implemented");
-}
+    if (id != null)
+      system = id.getSystem();
+    else
+      system = ActivationGroup.currentGroupID().getSystem();
+    return system.registerObject(descriptor);
+  }
+  
+  /**
+   * This method registers an activatable object. The object is expected to be
+   * on the anonymous port (null client and server socket factories).
+   * 
+   * @param desc the object description.
+   * @return the remote stub for the activatable object (the first call on this
+   *         stub will activate the object).
+   * @throws UnknownGroupException if the object group identifier is unknown
+   * @throws ActivationException if the activation system is not running
+   * @throws RemoteException if the remote call fails
+   */
+  public static Remote register(ActivationDesc desc)
+      throws UnknownGroupException, ActivationException, RemoteException
+  {
+    ActivationID id = obtainId(desc);
+    try
+      {
+        return toStub(
+                      id,
+                      Thread.currentThread().getContextClassLoader().loadClass(
+                        desc.getClassName()));
+      }
+    catch (ClassNotFoundException e)
+      {
+        throw new ActivationException("Class not found: "+desc.getClassName());
+      }
+  }
+  
+  /**
+   * Inactivates and unexports the object. The subsequent calls will activate
+   * the object again. The object is not inactivated if it is currently
+   * executing calls.
+   * 
+   * @param id the id of the object being inactivated
+   * @return true if the object has been inactivated, false if it has not been
+   *         inactivated because of the running or pending calls.
+   * @throws UnknownObjectException if the object is unknown.
+   * @throws ActivationException if the object group is not active
+   * @throws RemoteException if the remote call fails
+   */
+  public static boolean inactive(ActivationID id)
+      throws UnknownObjectException, ActivationException, RemoteException
+  {
+    if (id.group!=null)
+      id.group.inactiveObject(id);
+    return UnicastRemoteObject.unexportObject(id.activate(false), false);
+  }
+  
+  /**
+   * Unregister the object (the object will no longer be activable with that id)
+   * 
+   * @param id the object id
+   * @throws UnknownObjectException if the id is unknown
+   * @throws ActivationException if the activation system is not running
+   * @throws RemoteException if the remote call fails.
+   */
+  public static void unregister(ActivationID id) throws UnknownObjectException,
+      ActivationException, RemoteException
+  {
+    ActivationGroup.currentGroupId.getSystem().unregisterObject(id);
+    UnicastServer.unregisterActivatable(id);
+  }
+  
+  /**
+   * Register and export the object that activatable object that is not derived
+   * from the Activatable super class. It creates and registers the object
+   * activation descriptor. There is no need to call this method if the object
+   * extends Activable, as its work is done in the constructor
+   * {@link #Activatable(String, MarshalledObject, boolean, int)}.
+   * 
+   * @param obj the object, that is exported, becoming available at the given
+   *          port.
+   * @param location the object code location (codebase).
+   * @param data the data, needed to activate the object
+   * @param restart the restart mode
+   * @param port the port, where the object will be available
+   * 
+   * @return the created object activation ID.
+   * 
+   * @throws ActivationException if the activation group is not active
+   * @throws RemoteException if the registration or export fails
+   */
+  public static ActivationID exportObject(Remote obj, String location,
+                                          MarshalledObject<?> data,
+                                          boolean restart, int port)
+      throws ActivationException, RemoteException
+  {
+    ActivationDesc descriptor = new ActivationDesc(obj.getClass().getName(),
+                                                   location, data, restart);
+    ActivationID id = obtainId(descriptor);
+    Remote stub = exportObject(obj, id, port);    
+    return id;
+  }
 
-public static Remote register(ActivationDesc desc) throws UnknownGroupException, ActivationException, RemoteException {
-       throw new Error("Not implemented");
-}
+  /**
+   * Register and export the object that activatable object that is not derived
+   * from the Activatable super class. It creates and registers the object
+   * activation descriptor. There is no need to call this method if the object
+   * extends Activable, as its work is done in the constructor
+   * {@link #Activatable(String, MarshalledObject, boolean, int, RMIClientSocketFactory, RMIServerSocketFactory)}
+   * 
+   * @param obj the object, that is exported, becoming available at the given
+   *          port.
+   * @param location the object code location (codebase).
+   * @param data the data, needed to activate the object
+   * @param restart the restart mode
+   * @param port the port, where the object will be available
+   * @param csf the client socket factory
+   * @param ssf the server socket factory
+   * 
+   * @return the created object activation ID.
+   * 
+   * @throws ActivationException if the activation group is not active
+   * @throws RemoteException if the registration or export fails
+   */
+  public static ActivationID exportObject(Remote obj, String location,
+                                          MarshalledObject data,
+                                          boolean restart, int port,
+                                          RMIClientSocketFactory csf,
+                                          RMIServerSocketFactory ssf)
+      throws ActivationException, RemoteException
+  {
+    ActivationDesc descriptor = new ActivationDesc(obj.getClass().getName(),
+                                                   location, data, restart);
+    ActivationID id = obtainId(descriptor);
+    Remote stub = exportObject(obj, id, port, csf, ssf);    
+    return id;
 
-public static boolean inactive(ActivationID id) throws UnknownObjectException, ActivationException, RemoteException {
-       throw new Error("Not implemented");
-}
+  }
 
-public static void unregister(ActivationID id) throws UnknownObjectException, ActivationException, RemoteException {
-       throw new Error("Not implemented");
-}
+  /**
+   * During activation, this exportObject method should be invoked explicitly by
+   * the activatable object, that does is not derived from the Activatable
+   * class. There is no need to call this method if the object extends
+   * Activable, as its work is done in the constructor
+   * {@link #Activatable(ActivationID, int)}
+   * 
+   * @param obj the object
+   * @param id the known activation id
+   * @param port the object port
+   *  
+   * @return the remote stub of the activatable object
+   * 
+   * @throws RemoteException if the object export fails
+   */
+  public static Remote exportObject(Remote obj, ActivationID id, int port)
+      throws RemoteException
+  {
+    Remote stub = export(id, obj, port, null);
+    return stub;
+  }
 
-public static ActivationID exportObject(Remote obj, String location, MarshalledObject data, boolean restart, int port) throws ActivationException, RemoteException {
-       throw new Error("Not implemented");
-}
+  /**
+   * During activation, this exportObject method should be invoked explicitly by
+   * the activatable object, that does is not derived from the Activatable
+   * class. There is no need to call this method if the object extends
+   * Activable, as its work is done in the constructor
+   * {@link #Activatable(ActivationID, int)}
+   * 
+   * @param obj the object
+   * @param id the known activation id
+   * @param port the object port
+   * @param csf the client socket factory
+   * @param ssf the server socket factory
+   *  
+   * @return the remote stub of the activatable object
+   * 
+   * @throws RemoteException if the object export fails
+   */
+  public static Remote exportObject(Remote obj, ActivationID id, int port,
+                                    RMIClientSocketFactory csf,
+                                    RMIServerSocketFactory ssf)
+      throws RemoteException
+  {
+    Remote stub = export(id, obj, port, ssf); 
+    return stub;
 
-public static ActivationID exportObject(Remote obj, String location, MarshalledObject data, boolean restart, int port, RMIClientSocketFactory csf, RMIServerSocketFactory ssf) throws ActivationException, RemoteException {
-       throw new Error("Not implemented");
-}
+  }
 
-public static Remote exportObject(Remote obj, ActivationID id, int port) throws RemoteException {
-       throw new Error("Not implemented");
-}
+  /**
+   * Make the remote object unavailable for incoming calls. This method also
+   * unregisters the object, so it cannot be activated again by incomming call
+   * (unless registered).
+   * 
+   * @param obj the object to unexport
+   * @param force if true, cancel all pending or running calls to that object
+   *          (if false, the object with such calls is not unexported and false
+   *          is returned by this method).
+   * @return if the object was successfully unexported, false otherwise
+   * @throws NoSuchObjectException if such object is not known
+   */
+  public static boolean unexportObject(Remote obj, boolean force)
+      throws NoSuchObjectException
+  {
+    Object aref = UnicastServer.getExportedRef(obj);
+    
+    // Unregister it also (otherwise will be activated during the subsequent
+    // call.
+    if (aref instanceof ActivatableServerRef)
+      {
+        ActivatableServerRef aar = (ActivatableServerRef) aref;
+        UnicastServer.unregisterActivatable(aar.actId);
+      }
+    return UnicastRemoteObject.unexportObject(obj, force);
+  }
+  
+  static Remote exportObject(Remote obj, int port, 
+                             RMIServerSocketFactory serverSocketFactory) 
+    throws RemoteException
+  {
+    UnicastServerRef sref = null;
+    if (obj instanceof RemoteObject)
+      sref = (UnicastServerRef) ((RemoteObject) obj).getRef();
 
-public static Remote exportObject(Remote obj, ActivationID id, int port, RMIClientSocketFactory csf, RMIServerSocketFactory ssf) throws RemoteException {
-       throw new Error("Not implemented");
-}
-
-public static boolean unexportObject(Remote obj, boolean force) throws NoSuchObjectException {
-       throw new Error("Not implemented");
-}
+    if (sref == null)
+      sref = new UnicastServerRef(new ObjID(), port, serverSocketFactory);
 
+    Remote stub = sref.exportObject(obj);
+    // addStub(obj, stub); 
+    // TODO Need to change the place of the stub repository
+    return stub;
+  }
+  
+  /**
+   * Create and export the new remote object, making it available at the given
+   * port, using sockets, produced by the specified factories.
+   * 
+   * @param port the port, on that the object should become available. Zero
+   *          means anonymous port.
+   * @param serverSocketFactory the server socket factory
+   */
+  private static Remote export(ActivationID id, Remote obj, int port,
+                              RMIServerSocketFactory serverSocketFactory)
+      throws RemoteException
+  {
+    ActivatableServerRef sref = null;
+    sref = new ActivatableServerRef(makeId(id), id, port, serverSocketFactory);
+    return sref.exportObject(obj);
+  }  
+  
+  /**
+   * Make the object ID from the activation ID. The same activation ID always
+   * produces the identical object id.
+   * 
+   * @param aid the activation id
+   * 
+   * @return the object id
+   */
+  private static ObjID makeId(ActivationID aid)
+  {
+    ObjID id = new ObjID(0);
+    
+    // The fields of both ObjID and ActivationID must be package private,
+    // so we need to use the reflection to access them anyway.
+    // Probably other implementations use some very different approach.
+    
+    try
+      {
+        Field idUid =  ObjID.class.getDeclaredField("space");
+        Field aidUid = ActivationID.class.getDeclaredField("uid");
+        
+        aidUid.setAccessible(true);
+        idUid.setAccessible(true);
+        
+        idUid.set(id, aidUid.get(aid));
+      }
+    catch (Exception e)
+      {
+        InternalError ierr = new InternalError("Unable to set UID field");
+        ierr.initCause(e);
+        throw ierr;
+      }
+    
+    return id;
+  }  
+  
+  /**
+   * Connect the object to the UnicastServer (export), but not activate it.
+   * The object will be activated on the first call.
+   */
+  static Remote toStub(ActivationID anId, Class stubFor)
+  {
+    try
+      {
+        ActivatableServerRef asr = 
+          new ActivatableServerRef(makeId(anId), anId, 0, null);
+        UnicastServer.exportActivatableObject(asr);
+        return asr.exportClass(stubFor);
+      }
+    catch (RemoteException e)
+      {
+        InternalError ierr = new InternalError(
+          "Failed to obtain activatable stub");
+        ierr.initCause(e);
+        throw ierr;
+      }
+  }
 }