/* * Copyright (c) 1997, 2005, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code 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 * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package java.rmi.activation; import java.rmi.MarshalledObject; import java.rmi.NoSuchObjectException; import java.rmi.Remote; import java.rmi.RemoteException; import java.rmi.activation.UnknownGroupException; import java.rmi.activation.UnknownObjectException; import java.rmi.server.RMIClientSocketFactory; import java.rmi.server.RMIServerSocketFactory; import java.rmi.server.RemoteServer; import sun.rmi.server.ActivatableServerRef; /** * The <code>Activatable</code> class provides support for remote * objects that require persistent access over time and that * can be activated by the system. * * <p>For the constructors and static <code>exportObject</code> methods, * the stub for a remote object being exported is obtained as described in * {@link java.rmi.server.UnicastRemoteObject}. * * <p>An attempt to serialize explicitly an instance of this class will * fail. * * @author Ann Wollrath * @since 1.2 * @serial exclude */ public abstract class Activatable extends RemoteServer { private ActivationID id; /** indicate compatibility with the Java 2 SDK v1.2 version of class */ private static final long serialVersionUID = -3120617863591563455L; /** * Constructs an activatable remote object by registering * an activation descriptor (with the specified location, data, and * restart mode) for this object, and exporting the object with the * specified port. * * <p><strong>Note:</strong> Using the <code>Activatable</code> * constructors that both register and export an activatable remote * object is strongly discouraged because the actions of registering * and exporting the remote object are <i>not</i> guaranteed to be * atomic. Instead, an application should register an activation * descriptor and export a remote object separately, so that exceptions * can be handled properly. * * <p>This method invokes the {@link * #exportObject(Remote,String,MarshalledObject,boolean,int) * exportObject} method with this object, and the specified location, * data, restart mode, and port. Subsequent calls to {@link #getID} * will return the activation identifier returned from the call to * <code>exportObject</code>. * * @param location the location for classes for this object * @param data the object's initialization data * @param port the port on which the object is exported (an anonymous * port is used if port=0) * @param restart if true, the object is restarted (reactivated) when * either the activator is restarted or the object's activation group * is restarted after an unexpected crash; if false, the object is only * activated on demand. Specifying <code>restart</code> to be * <code>true</code> does not force an initial immediate activation of * a newly registered object; initial activation is lazy. * @exception ActivationException if object registration fails. * @exception RemoteException if either of the following fails: * a) registering the object with the activation system or b) exporting * the object to the RMI runtime. * @since 1.2 **/ protected Activatable(String location, MarshalledObject<?> data, boolean restart, int port) throws ActivationException, RemoteException { super(); id = exportObject(this, location, data, restart, port); } /** * Constructs an activatable remote object by registering * an activation descriptor (with the specified location, data, and * restart mode) for this object, and exporting the object with the * specified port, and specified client and server socket factories. * * <p><strong>Note:</strong> Using the <code>Activatable</code> * constructors that both register and export an activatable remote * object is strongly discouraged because the actions of registering * and exporting the remote object are <i>not</i> guaranteed to be * atomic. Instead, an application should register an activation * descriptor and export a remote object separately, so that exceptions * can be handled properly. * * <p>This method invokes the {@link * #exportObject(Remote,String,MarshalledObject,boolean,int,RMIClientSocketFactory,RMIServerSocketFactory) * exportObject} method with this object, and the specified location, * data, restart mode, port, and client and server socket factories. * Subsequent calls to {@link #getID} will return the activation * identifier returned from the call to <code>exportObject</code>. * * @param location the location for classes for this object * @param data the object's initialization data * @param restart if true, the object is restarted (reactivated) when * either the activator is restarted or the object's activation group * is restarted after an unexpected crash; if false, the object is only * activated on demand. Specifying <code>restart</code> to be * <code>true</code> does not force an initial immediate activation of * a newly registered object; initial activation is lazy. * @param port the port on which the object is exported (an anonymous * port is used if port=0) * @param csf the client-side socket factory for making calls to the * remote object * @param ssf the server-side socket factory for receiving remote calls * @exception ActivationException if object registration fails. * @exception RemoteException if either of the following fails: * a) registering the object with the activation system or b) exporting * the object to the RMI runtime. * @since 1.2 **/ protected Activatable(String location, MarshalledObject<?> data, boolean restart, int port, RMIClientSocketFactory csf, RMIServerSocketFactory ssf) throws ActivationException, RemoteException { super(); id = exportObject(this, location, data, restart, port, csf, ssf); } /** * Constructor used to activate/export the object on a specified * port. An "activatable" remote object must have a constructor that * takes two arguments: <ul> * <li>the object's activation identifier (<code>ActivationID</code>), and * <li>the object's initialization data (a <code>MarshalledObject</code>). * </ul><p> * * A concrete subclass of this class must call this constructor when it is * <i>activated</i> via the two parameter constructor described above. As * a side-effect of construction, the remote object is "exported" * to the RMI runtime (on the specified <code>port</code>) and is * available to accept incoming calls from clients. * * @param id activation identifier for the object * @param port the port number on which the object is exported * @exception RemoteException if exporting the object to the RMI * runtime fails * @since 1.2 */ protected Activatable(ActivationID id, int port) throws RemoteException { super(); this.id = id; exportObject(this, id, port); } /** * Constructor used to activate/export the object on a specified * port. An "activatable" remote object must have a constructor that * takes two arguments: <ul> * <li>the object's activation identifier (<code>ActivationID</code>), and * <li>the object's initialization data (a <code>MarshalledObject</code>). * </ul><p> * * A concrete subclass of this class must call this constructor when it is * <i>activated</i> via the two parameter constructor described above. As * a side-effect of construction, the remote object is "exported" * to the RMI runtime (on the specified <code>port</code>) and is * available to accept incoming calls from clients. * * @param id activation identifier for the object * @param port the port number on which the object is exported * @param csf the client-side socket factory for making calls to the * remote object * @param ssf the server-side socket factory for receiving remote calls * @exception RemoteException if exporting the object to the RMI * runtime fails * @since 1.2 */ protected Activatable(ActivationID id, int port, RMIClientSocketFactory csf, RMIServerSocketFactory ssf) throws RemoteException { super(); this.id = id; exportObject(this, id, port, csf, ssf); } /** * Returns the object's activation identifier. The method is * protected so that only subclasses can obtain an object's * identifier. * @return the object's activation identifier * @since 1.2 */ protected ActivationID getID() { return id; } /** * Register an object descriptor for an activatable remote * object so that is can be activated on demand. * * @param desc the object's descriptor * @return the stub for the activatable remote object * @exception UnknownGroupException if group id in <code>desc</code> * is not registered with the activation system * @exception ActivationException if activation system is not running * @exception RemoteException if remote call fails * @since 1.2 */ public static Remote register(ActivationDesc desc) throws UnknownGroupException, ActivationException, RemoteException { // register object with activator. ActivationID id = ActivationGroup.getSystem().registerObject(desc); return sun.rmi.server.ActivatableRef.getStub(desc, id); } /** * Informs the system that the object with the corresponding activation * <code>id</code> is currently inactive. If the object is currently * active, the object is "unexported" from the RMI runtime (only if * there are no pending or in-progress calls) * so the that it can no longer receive incoming calls. This call * informs this VM's ActivationGroup that the object is inactive, * that, in turn, informs its ActivationMonitor. If this call * completes successfully, a subsequent activate request to the activator * will cause the object to reactivate. The operation may still * succeed if the object is considered active but has already * unexported itself. * * @param id the object's activation identifier * @return true if the operation succeeds (the operation will * succeed if the object in currently known to be active and is * either already unexported or is currently exported and has no * pending/executing calls); false is returned if the object has * pending/executing calls in which case it cannot be deactivated * @exception UnknownObjectException if object is not known (it may * already be inactive) * @exception ActivationException if group is not active * @exception RemoteException if call informing monitor fails * @since 1.2 */ public static boolean inactive(ActivationID id) throws UnknownObjectException, ActivationException, RemoteException { return ActivationGroup.currentGroup().inactiveObject(id); } /** * Revokes previous registration for the activation descriptor * associated with <code>id</code>. An object can no longer be * activated via that <code>id</code>. * * @param id the object's activation identifier * @exception UnknownObjectException if object (<code>id</code>) is unknown * @exception ActivationException if activation system is not running * @exception RemoteException if remote call to activation system fails * @since 1.2 */ public static void unregister(ActivationID id) throws UnknownObjectException, ActivationException, RemoteException { ActivationGroup.getSystem().unregisterObject(id); } /** * Registers an activation descriptor (with the specified location, * data, and restart mode) for the specified object, and exports that * object with the specified port. * * <p><strong>Note:</strong> Using this method (as well as the * <code>Activatable</code> constructors that both register and export * an activatable remote object) is strongly discouraged because the * actions of registering and exporting the remote object are * <i>not</i> guaranteed to be atomic. Instead, an application should * register an activation descriptor and export a remote object * separately, so that exceptions can be handled properly. * * <p>This method invokes the {@link * #exportObject(Remote,String,MarshalledObject,boolean,int,RMIClientSocketFactory,RMIServerSocketFactory) * exportObject} method with the specified object, location, data, * restart mode, and port, and <code>null</code> for both client and * server socket factories, and then returns the resulting activation * identifier. * * @param obj the object being exported * @param location the object's code location * @param data the object's bootstrapping data * @param restart if true, the object is restarted (reactivated) when * either the activator is restarted or the object's activation group * is restarted after an unexpected crash; if false, the object is only * activated on demand. Specifying <code>restart</code> to be * <code>true</code> does not force an initial immediate activation of * a newly registered object; initial activation is lazy. * @param port the port on which the object is exported (an anonymous * port is used if port=0) * @return the activation identifier obtained from registering the * descriptor, <code>desc</code>, with the activation system * the wrong group * @exception ActivationException if activation group is not active * @exception RemoteException if object registration or export fails * @since 1.2 **/ public static ActivationID exportObject(Remote obj, String location, MarshalledObject<?> data, boolean restart, int port) throws ActivationException, RemoteException { return exportObject(obj, location, data, restart, port, null, null); } /** * Registers an activation descriptor (with the specified location, * data, and restart mode) for the specified object, and exports that * object with the specified port, and the specified client and server * socket factories. * * <p><strong>Note:</strong> Using this method (as well as the * <code>Activatable</code> constructors that both register and export * an activatable remote object) is strongly discouraged because the * actions of registering and exporting the remote object are * <i>not</i> guaranteed to be atomic. Instead, an application should * register an activation descriptor and export a remote object * separately, so that exceptions can be handled properly. * * <p>This method first registers an activation descriptor for the * specified object as follows. It obtains the activation system by * invoking the method {@link ActivationGroup#getSystem * ActivationGroup.getSystem}. This method then obtains an {@link * ActivationID} for the object by invoking the activation system's * {@link ActivationSystem#registerObject registerObject} method with * an {@link ActivationDesc} constructed with the specified object's * class name, and the specified location, data, and restart mode. If * an exception occurs obtaining the activation system or registering * the activation descriptor, that exception is thrown to the caller. * * <p>Next, this method exports the object by invoking the {@link * #exportObject(Remote,ActivationID,int,RMIClientSocketFactory,RMIServerSocketFactory) * exportObject} method with the specified remote object, the * activation identifier obtained from registration, the specified * port, and the specified client and server socket factories. If an * exception occurs exporting the object, this method attempts to * unregister the activation identifier (obtained from registration) by * invoking the activation system's {@link * ActivationSystem#unregisterObject unregisterObject} method with the * activation identifier. If an exception occurs unregistering the * identifier, that exception is ignored, and the original exception * that occurred exporting the object is thrown to the caller. * * <p>Finally, this method invokes the {@link * ActivationGroup#activeObject activeObject} method on the activation * group in this VM with the activation identifier and the specified * remote object, and returns the activation identifier to the caller. * * @param obj the object being exported * @param location the object's code location * @param data the object's bootstrapping data * @param restart if true, the object is restarted (reactivated) when * either the activator is restarted or the object's activation group * is restarted after an unexpected crash; if false, the object is only * activated on demand. Specifying <code>restart</code> to be * <code>true</code> does not force an initial immediate activation of * a newly registered object; initial activation is lazy. * @param port the port on which the object is exported (an anonymous * port is used if port=0) * @param csf the client-side socket factory for making calls to the * remote object * @param ssf the server-side socket factory for receiving remote calls * @return the activation identifier obtained from registering the * descriptor with the activation system * @exception ActivationException if activation group is not active * @exception RemoteException if object registration or export fails * @since 1.2 **/ public static ActivationID exportObject(Remote obj, String location, MarshalledObject<?> data, boolean restart, int port, RMIClientSocketFactory csf, RMIServerSocketFactory ssf) throws ActivationException, RemoteException { ActivationDesc desc = new ActivationDesc(obj.getClass().getName(), location, data, restart); /* * Register descriptor. */ ActivationSystem system = ActivationGroup.getSystem(); ActivationID id = system.registerObject(desc); /* * Export object. */ try { exportObject(obj, id, port, csf, ssf); } catch (RemoteException e) { /* * Attempt to unregister activation descriptor because export * failed and register/export should be atomic (see 4323621). */ try { system.unregisterObject(id); } catch (Exception ex) { } /* * Report original exception. */ throw e; } /* * This call can't fail (it is a local call, and the only possible * exception, thrown if the group is inactive, will not be thrown * because the group is not inactive). */ ActivationGroup.currentGroup().activeObject(id, obj); return id; } /** * Export the activatable remote object to the RMI runtime to make * the object available to receive incoming calls. The object is * exported on an anonymous port, if <code>port</code> is zero. <p> * * During activation, this <code>exportObject</code> method should * be invoked explicitly by an "activatable" object, that does not * extend the <code>Activatable</code> class. There is no need for objects * that do extend the <code>Activatable</code> class to invoke this * method directly because the object is exported during construction. * * @return the stub for the activatable remote object * @param obj the remote object implementation * @param id the object's activation identifier * @param port the port on which the object is exported (an anonymous * port is used if port=0) * @exception RemoteException if object export fails * @since 1.2 */ public static Remote exportObject(Remote obj, ActivationID id, int port) throws RemoteException { return exportObject(obj, new ActivatableServerRef(id, port)); } /** * Export the activatable remote object to the RMI runtime to make * the object available to receive incoming calls. The object is * exported on an anonymous port, if <code>port</code> is zero. <p> * * During activation, this <code>exportObject</code> method should * be invoked explicitly by an "activatable" object, that does not * extend the <code>Activatable</code> class. There is no need for objects * that do extend the <code>Activatable</code> class to invoke this * method directly because the object is exported during construction. * * @return the stub for the activatable remote object * @param obj the remote object implementation * @param id the object's activation identifier * @param port the port on which the object is exported (an anonymous * port is used if port=0) * @param csf the client-side socket factory for making calls to the * remote object * @param ssf the server-side socket factory for receiving remote calls * @exception RemoteException if object export fails * @since 1.2 */ public static Remote exportObject(Remote obj, ActivationID id, int port, RMIClientSocketFactory csf, RMIServerSocketFactory ssf) throws RemoteException { return exportObject(obj, new ActivatableServerRef(id, port, csf, ssf)); } /** * Remove the remote object, obj, from the RMI runtime. If * successful, the object can no longer accept incoming RMI calls. * If the force parameter is true, the object is forcibly unexported * even if there are pending calls to the remote object or the * remote object still has calls in progress. If the force * parameter is false, the object is only unexported if there are * no pending or in progress calls to the object. * * @param obj the remote object to be unexported * @param force if true, unexports the object even if there are * pending or in-progress calls; if false, only unexports the object * if there are no pending or in-progress calls * @return true if operation is successful, false otherwise * @exception NoSuchObjectException if the remote object is not * currently exported * @since 1.2 */ public static boolean unexportObject(Remote obj, boolean force) throws NoSuchObjectException { return sun.rmi.transport.ObjectTable.unexportObject(obj, force); } /** * Exports the specified object using the specified server ref. */ private static Remote exportObject(Remote obj, ActivatableServerRef sref) throws RemoteException { // if obj extends Activatable, set its ref. if (obj instanceof Activatable) { ((Activatable) obj).ref = sref; } return sref.exportObject(obj, null, false); } }