| /* 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. |
| |
| GNU Classpath is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2, or (at your option) |
| any later version. |
| |
| GNU Classpath is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GNU Classpath; see the file COPYING. If not, write to the |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
| 02110-1301 USA. |
| |
| Linking this library statically or dynamically with other modules is |
| making a combined work based on this library. Thus, the terms and |
| conditions of the GNU General Public License cover the whole |
| combination. |
| |
| As a special exception, the copyright holders of this library give you |
| permission to link this library with independent modules to produce an |
| executable, regardless of the license terms of these independent |
| modules, and to copy and distribute the resulting executable under |
| terms of your choice, provided that you also meet, for each linked |
| independent module, the terms and conditions of the license of that |
| module. An independent module is a module which is not derived from |
| or based on this library. If you modify this library, you may extend |
| this exception to your version of the library, but you are not |
| obligated to do so. If you do not wish to do so, delete this |
| 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; |
| |
| /** |
| * 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 |
| { |
| |
| /** |
| * 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); |
| } |
| |
| /** |
| * 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); |
| } |
| |
| /** |
| * 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; |
| } |
| } |
| |
| /** |
| * 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; |
| |
| 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; |
| } |
| |
| /** |
| * 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; |
| |
| } |
| |
| /** |
| * 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; |
| } |
| |
| /** |
| * 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; |
| |
| } |
| |
| /** |
| * 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(); |
| |
| 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 |
| */ |
| public 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 |
| */ |
| public 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; |
| } |
| } |
| } |