1 /*
   2  * Copyright 1997-2005 Sun Microsystems, Inc.  All Rights Reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Sun designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Sun in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  22  * CA 95054 USA or visit www.sun.com if you need additional information or
  23  * have any questions.
  24  */
  25 
  26 package java.rmi.activation;
  27 
  28 import java.rmi.MarshalledObject;
  29 import java.rmi.NoSuchObjectException;
  30 import java.rmi.Remote;
  31 import java.rmi.RemoteException;
  32 import java.rmi.activation.UnknownGroupException;
  33 import java.rmi.activation.UnknownObjectException;
  34 import java.rmi.server.RMIClientSocketFactory;
  35 import java.rmi.server.RMIServerSocketFactory;
  36 import java.rmi.server.RemoteServer;
  37 import sun.rmi.server.ActivatableServerRef;
  38 
  39 /**
  40  * The <code>Activatable</code> class provides support for remote
  41  * objects that require persistent access over time and that
  42  * can be activated by the system.
  43  *
  44  * <p>For the constructors and static <code>exportObject</code> methods,
  45  * the stub for a remote object being exported is obtained as described in
  46  * {@link java.rmi.server.UnicastRemoteObject}.
  47  *
  48  * <p>An attempt to serialize explicitly an instance of this class will
  49  * fail.
  50  *
  51  * @author      Ann Wollrath
  52  * @since       1.2
  53  * @serial      exclude
  54  */
  55 public abstract class Activatable extends RemoteServer {
  56 
  57     private ActivationID id;
  58     /** indicate compatibility with the Java 2 SDK v1.2 version of class */
  59     private static final long serialVersionUID = -3120617863591563455L;
  60 
  61     /**
  62      * Constructs an activatable remote object by registering
  63      * an activation descriptor (with the specified location, data, and
  64      * restart mode) for this object, and exporting the object with the
  65      * specified port.
  66      *
  67      * <p><strong>Note:</strong> Using the <code>Activatable</code>
  68      * constructors that both register and export an activatable remote
  69      * object is strongly discouraged because the actions of registering
  70      * and exporting the remote object are <i>not</i> guaranteed to be
  71      * atomic.  Instead, an application should register an activation
  72      * descriptor and export a remote object separately, so that exceptions
  73      * can be handled properly.
  74      *
  75      * <p>This method invokes the {@link
  76      * exportObject(Remote,String,MarshalledObject,boolean,port)
  77      * exportObject} method with this object, and the specified location,
  78      * data, restart mode, and port.  Subsequent calls to {@link #getID}
  79      * will return the activation identifier returned from the call to
  80      * <code>exportObject</code>.
  81      *
  82      * @param location the location for classes for this object
  83      * @param data the object's initialization data
  84      * @param port the port on which the object is exported (an anonymous
  85      * port is used if port=0)
  86      * @param restart if true, the object is restarted (reactivated) when
  87      * either the activator is restarted or the object's activation group
  88      * is restarted after an unexpected crash; if false, the object is only
  89      * activated on demand.  Specifying <code>restart</code> to be
  90      * <code>true</code> does not force an initial immediate activation of
  91      * a newly registered object;  initial activation is lazy.
  92      * @exception ActivationException if object registration fails.
  93      * @exception RemoteException if either of the following fails:
  94      * a) registering the object with the activation system or b) exporting
  95      * the object to the RMI runtime.
  96      * @since 1.2
  97      **/
  98     protected Activatable(String location,
  99                           MarshalledObject<?> data,
 100                           boolean restart,
 101                           int port)
 102         throws ActivationException, RemoteException
 103     {
 104         super();
 105         id = exportObject(this, location, data, restart, port);
 106     }
 107 
 108     /**
 109      * Constructs an activatable remote object by registering
 110      * an activation descriptor (with the specified location, data, and
 111      * restart mode) for this object, and exporting the object with the
 112      * specified port, and specified client and server socket factories.
 113      *
 114      * <p><strong>Note:</strong> Using the <code>Activatable</code>
 115      * constructors that both register and export an activatable remote
 116      * object is strongly discouraged because the actions of registering
 117      * and exporting the remote object are <i>not</i> guaranteed to be
 118      * atomic.  Instead, an application should register an activation
 119      * descriptor and export a remote object separately, so that exceptions
 120      * can be handled properly.
 121      *
 122      * <p>This method invokes the {@link
 123      * exportObject(Remote,String,MarshalledObject,boolean,port,RMIClientSocketFactory,RMIServerSocketFactory)
 124      * exportObject} method with this object, and the specified location,
 125      * data, restart mode, port, and client and server socket factories.
 126      * Subsequent calls to {@link #getID} will return the activation
 127      * identifier returned from the call to <code>exportObject</code>.
 128      *
 129      * @param location the location for classes for this object
 130      * @param data the object's initialization data
 131      * @param restart if true, the object is restarted (reactivated) when
 132      * either the activator is restarted or the object's activation group
 133      * is restarted after an unexpected crash; if false, the object is only
 134      * activated on demand.  Specifying <code>restart</code> to be
 135      * <code>true</code> does not force an initial immediate activation of
 136      * a newly registered object;  initial activation is lazy.
 137      * @param port the port on which the object is exported (an anonymous
 138      * port is used if port=0)
 139      * @param csf the client-side socket factory for making calls to the
 140      * remote object
 141      * @param ssf the server-side socket factory for receiving remote calls
 142      * @exception ActivationException if object registration fails.
 143      * @exception RemoteException if either of the following fails:
 144      * a) registering the object with the activation system or b) exporting
 145      * the object to the RMI runtime.
 146      * @since 1.2
 147      **/
 148     protected Activatable(String location,
 149                           MarshalledObject<?> data,
 150                           boolean restart,
 151                           int port,
 152                           RMIClientSocketFactory csf,
 153                           RMIServerSocketFactory ssf)
 154         throws ActivationException, RemoteException
 155     {
 156         super();
 157         id = exportObject(this, location, data, restart, port, csf, ssf);
 158     }
 159 
 160     /**
 161      * Constructor used to activate/export the object on a specified
 162      * port. An "activatable" remote object must have a constructor that
 163      * takes two arguments: <ul>
 164      * <li>the object's activation identifier (<code>ActivationID</code>), and
 165      * <li>the object's initialization data (a <code>MarshalledObject</code>).
 166      * </ul><p>
 167      *
 168      * A concrete subclass of this class must call this constructor when it is
 169      * <i>activated</i> via the two parameter constructor described above. As
 170      * a side-effect of construction, the remote object is "exported"
 171      * to the RMI runtime (on the specified <code>port</code>) and is
 172      * available to accept incoming calls from clients.
 173      *
 174      * @param id activation identifier for the object
 175      * @param port the port number on which the object is exported
 176      * @exception RemoteException if exporting the object to the RMI
 177      * runtime fails
 178      * @since 1.2
 179      */
 180     protected Activatable(ActivationID id, int port)
 181         throws RemoteException
 182     {
 183         super();
 184         this.id = id;
 185         exportObject(this, id, port);
 186     }
 187 
 188     /**
 189      * Constructor used to activate/export the object on a specified
 190      * port. An "activatable" remote object must have a constructor that
 191      * takes two arguments: <ul>
 192      * <li>the object's activation identifier (<code>ActivationID</code>), and
 193      * <li>the object's initialization data (a <code>MarshalledObject</code>).
 194      * </ul><p>
 195      *
 196      * A concrete subclass of this class must call this constructor when it is
 197      * <i>activated</i> via the two parameter constructor described above. As
 198      * a side-effect of construction, the remote object is "exported"
 199      * to the RMI runtime (on the specified <code>port</code>) and is
 200      * available to accept incoming calls from clients.
 201      *
 202      * @param id activation identifier for the object
 203      * @param port the port number on which the object is exported
 204      * @param csf the client-side socket factory for making calls to the
 205      * remote object
 206      * @param ssf the server-side socket factory for receiving remote calls
 207      * @exception RemoteException if exporting the object to the RMI
 208      * runtime fails
 209      * @since 1.2
 210      */
 211     protected Activatable(ActivationID id, int port,
 212                           RMIClientSocketFactory csf,
 213                           RMIServerSocketFactory ssf)
 214         throws RemoteException
 215     {
 216         super();
 217         this.id = id;
 218         exportObject(this, id, port, csf, ssf);
 219     }
 220 
 221     /**
 222      * Returns the object's activation identifier.  The method is
 223      * protected so that only subclasses can obtain an object's
 224      * identifier.
 225      * @return the object's activation identifier
 226      * @since 1.2
 227      */
 228     protected ActivationID getID() {
 229         return id;
 230     }
 231 
 232     /**
 233      * Register an object descriptor for an activatable remote
 234      * object so that is can be activated on demand.
 235      *
 236      * @param desc  the object's descriptor
 237      * @return the stub for the activatable remote object
 238      * @exception UnknownGroupException if group id in <code>desc</code>
 239      * is not registered with the activation system
 240      * @exception ActivationException if activation system is not running
 241      * @exception RemoteException if remote call fails
 242      * @since 1.2
 243      */
 244     public static Remote register(ActivationDesc desc)
 245         throws UnknownGroupException, ActivationException, RemoteException
 246     {
 247         // register object with activator.
 248         ActivationID id =
 249             ActivationGroup.getSystem().registerObject(desc);
 250         return sun.rmi.server.ActivatableRef.getStub(desc, id);
 251     }
 252 
 253     /**
 254      * Informs the system that the object with the corresponding activation
 255      * <code>id</code> is currently inactive. If the object is currently
 256      * active, the object is "unexported" from the RMI runtime (only if
 257      * there are no pending or in-progress calls)
 258      * so the that it can no longer receive incoming calls. This call
 259      * informs this VM's ActivationGroup that the object is inactive,
 260      * that, in turn, informs its ActivationMonitor. If this call
 261      * completes successfully, a subsequent activate request to the activator
 262      * will cause the object to reactivate. The operation may still
 263      * succeed if the object is considered active but has already
 264      * unexported itself.
 265      *
 266      * @param id the object's activation identifier
 267      * @return true if the operation succeeds (the operation will
 268      * succeed if the object in currently known to be active and is
 269      * either already unexported or is currently exported and has no
 270      * pending/executing calls); false is returned if the object has
 271      * pending/executing calls in which case it cannot be deactivated
 272      * @exception UnknownObjectException if object is not known (it may
 273      * already be inactive)
 274      * @exception ActivationException if group is not active
 275      * @exception RemoteException if call informing monitor fails
 276      * @since 1.2
 277      */
 278     public static boolean inactive(ActivationID id)
 279         throws UnknownObjectException, ActivationException, RemoteException
 280     {
 281         return ActivationGroup.currentGroup().inactiveObject(id);
 282     }
 283 
 284     /**
 285      * Revokes previous registration for the activation descriptor
 286      * associated with <code>id</code>. An object can no longer be
 287      * activated via that <code>id</code>.
 288      *
 289      * @param id the object's activation identifier
 290      * @exception UnknownObjectException if object (<code>id</code>) is unknown
 291      * @exception ActivationException if activation system is not running
 292      * @exception RemoteException if remote call to activation system fails
 293      * @since 1.2
 294      */
 295     public static void unregister(ActivationID id)
 296         throws UnknownObjectException, ActivationException, RemoteException
 297     {
 298         ActivationGroup.getSystem().unregisterObject(id);
 299     }
 300 
 301     /**
 302      * Registers an activation descriptor (with the specified location,
 303      * data, and restart mode) for the specified object, and exports that
 304      * object with the specified port.
 305      *
 306      * <p><strong>Note:</strong> Using this method (as well as the
 307      * <code>Activatable</code> constructors that both register and export
 308      * an activatable remote object) is strongly discouraged because the
 309      * actions of registering and exporting the remote object are
 310      * <i>not</i> guaranteed to be atomic.  Instead, an application should
 311      * register an activation descriptor and export a remote object
 312      * separately, so that exceptions can be handled properly.
 313      *
 314      * <p>This method invokes the {@link
 315      * exportObject(Remote,String,MarshalledObject,boolean,port,RMIClientSocketFactory,RMIServerSocketFactory)
 316      * exportObject} method with the specified object, location, data,
 317      * restart mode, and port, and <code>null</code> for both client and
 318      * server socket factories, and then returns the resulting activation
 319      * identifier.
 320      *
 321      * @param obj the object being exported
 322      * @param location the object's code location
 323      * @param data the object's bootstrapping data
 324      * @param restart if true, the object is restarted (reactivated) when
 325      * either the activator is restarted or the object's activation group
 326      * is restarted after an unexpected crash; if false, the object is only
 327      * activated on demand.  Specifying <code>restart</code> to be
 328      * <code>true</code> does not force an initial immediate activation of
 329      * a newly registered object;  initial activation is lazy.
 330      * @param port the port on which the object is exported (an anonymous
 331      * port is used if port=0)
 332      * @return the activation identifier obtained from registering the
 333      * descriptor, <code>desc</code>, with the activation system
 334      * the wrong group
 335      * @exception ActivationException if activation group is not active
 336      * @exception RemoteException if object registration or export fails
 337      * @since 1.2
 338      **/
 339     public static ActivationID exportObject(Remote obj,
 340                                             String location,
 341                                             MarshalledObject<?> data,
 342                                             boolean restart,
 343                                             int port)
 344         throws ActivationException, RemoteException
 345     {
 346         return exportObject(obj, location, data, restart, port, null, null);
 347     }
 348 
 349     /**
 350      * Registers an activation descriptor (with the specified location,
 351      * data, and restart mode) for the specified object, and exports that
 352      * object with the specified port, and the specified client and server
 353      * socket factories.
 354      *
 355      * <p><strong>Note:</strong> Using this method (as well as the
 356      * <code>Activatable</code> constructors that both register and export
 357      * an activatable remote object) is strongly discouraged because the
 358      * actions of registering and exporting the remote object are
 359      * <i>not</i> guaranteed to be atomic.  Instead, an application should
 360      * register an activation descriptor and export a remote object
 361      * separately, so that exceptions can be handled properly.
 362      *
 363      * <p>This method first registers an activation descriptor for the
 364      * specified object as follows. It obtains the activation system by
 365      * invoking the method {@link ActivationGroup#getSystem
 366      * ActivationGroup.getSystem}.  This method then obtains an {@link
 367      * ActivationID} for the object by invoking the activation system's
 368      * {@link ActivationSystem#registerObject registerObject} method with
 369      * an {@link ActivationDesc} constructed with the specified object's
 370      * class name, and the specified location, data, and restart mode.  If
 371      * an exception occurs obtaining the activation system or registering
 372      * the activation descriptor, that exception is thrown to the caller.
 373      *
 374      * <p>Next, this method exports the object by invoking the {@link
 375      * #exportObject(Remote,ActivationID,int,RMIClientSocketFactory,RMIServerSocketFactory)
 376      * exportObject} method with the specified remote object, the
 377      * activation identifier obtained from registration, the specified
 378      * port, and the specified client and server socket factories.  If an
 379      * exception occurs exporting the object, this method attempts to
 380      * unregister the activation identifier (obtained from registration) by
 381      * invoking the activation system's {@link
 382      * ActivationSystem#unregisterObject unregisterObject} method with the
 383      * activation identifier.  If an exception occurs unregistering the
 384      * identifier, that exception is ignored, and the original exception
 385      * that occurred exporting the object is thrown to the caller.
 386      *
 387      * <p>Finally, this method invokes the {@link
 388      * ActivationGroup#activeObject activeObject} method on the activation
 389      * group in this VM with the activation identifier and the specified
 390      * remote object, and returns the activation identifier to the caller.
 391      *
 392      * @param obj the object being exported
 393      * @param location the object's code location
 394      * @param data the object's bootstrapping data
 395      * @param restart if true, the object is restarted (reactivated) when
 396      * either the activator is restarted or the object's activation group
 397      * is restarted after an unexpected crash; if false, the object is only
 398      * activated on demand.  Specifying <code>restart</code> to be
 399      * <code>true</code> does not force an initial immediate activation of
 400      * a newly registered object;  initial activation is lazy.
 401      * @param port the port on which the object is exported (an anonymous
 402      * port is used if port=0)
 403      * @param csf the client-side socket factory for making calls to the
 404      * remote object
 405      * @param ssf the server-side socket factory for receiving remote calls
 406      * @return the activation identifier obtained from registering the
 407      * descriptor with the activation system
 408      * @exception ActivationException if activation group is not active
 409      * @exception RemoteException if object registration or export fails
 410      * @since 1.2
 411      **/
 412     public static ActivationID exportObject(Remote obj,
 413                                             String location,
 414                                             MarshalledObject<?> data,
 415                                             boolean restart,
 416                                             int port,
 417                                             RMIClientSocketFactory csf,
 418                                             RMIServerSocketFactory ssf)
 419         throws ActivationException, RemoteException
 420     {
 421         ActivationDesc desc = new ActivationDesc(obj.getClass().getName(),
 422                                                  location, data, restart);
 423         /*
 424          * Register descriptor.
 425          */
 426         ActivationSystem system =  ActivationGroup.getSystem();
 427         ActivationID id = system.registerObject(desc);
 428 
 429         /*
 430          * Export object.
 431          */
 432         try {
 433             exportObject(obj, id, port, csf, ssf);
 434         } catch (RemoteException e) {
 435             /*
 436              * Attempt to unregister activation descriptor because export
 437              * failed and register/export should be atomic (see 4323621).
 438              */
 439             try {
 440                 system.unregisterObject(id);
 441             } catch (Exception ex) {
 442             }
 443             /*
 444              * Report original exception.
 445              */
 446             throw e;
 447         }
 448 
 449         /*
 450          * This call can't fail (it is a local call, and the only possible
 451          * exception, thrown if the group is inactive, will not be thrown
 452          * because the group is not inactive).
 453          */
 454         ActivationGroup.currentGroup().activeObject(id, obj);
 455 
 456         return id;
 457     }
 458 
 459     /**
 460      * Export the activatable remote object to the RMI runtime to make
 461      * the object available to receive incoming calls. The object is
 462      * exported on an anonymous port, if <code>port</code> is zero. <p>
 463      *
 464      * During activation, this <code>exportObject</code> method should
 465      * be invoked explicitly by an "activatable" object, that does not
 466      * extend the <code>Activatable</code> class. There is no need for objects
 467      * that do extend the <code>Activatable</code> class to invoke this
 468      * method directly because the object is exported during construction.
 469      *
 470      * @return the stub for the activatable remote object
 471      * @param obj the remote object implementation
 472      * @param id the object's  activation identifier
 473      * @param port the port on which the object is exported (an anonymous
 474      * port is used if port=0)
 475      * @exception RemoteException if object export fails
 476      * @since 1.2
 477      */
 478     public static Remote exportObject(Remote obj,
 479                                       ActivationID id,
 480                                       int port)
 481         throws RemoteException
 482     {
 483         return exportObject(obj, new ActivatableServerRef(id, port));
 484     }
 485 
 486     /**
 487      * Export the activatable remote object to the RMI runtime to make
 488      * the object available to receive incoming calls. The object is
 489      * exported on an anonymous port, if <code>port</code> is zero. <p>
 490      *
 491      * During activation, this <code>exportObject</code> method should
 492      * be invoked explicitly by an "activatable" object, that does not
 493      * extend the <code>Activatable</code> class. There is no need for objects
 494      * that do extend the <code>Activatable</code> class to invoke this
 495      * method directly because the object is exported during construction.
 496      *
 497      * @return the stub for the activatable remote object
 498      * @param obj the remote object implementation
 499      * @param id the object's  activation identifier
 500      * @param port the port on which the object is exported (an anonymous
 501      * port is used if port=0)
 502      * @param csf the client-side socket factory for making calls to the
 503      * remote object
 504      * @param ssf the server-side socket factory for receiving remote calls
 505      * @exception RemoteException if object export fails
 506      * @since 1.2
 507      */
 508     public static Remote exportObject(Remote obj,
 509                                       ActivationID id,
 510                                       int port,
 511                                       RMIClientSocketFactory csf,
 512                                       RMIServerSocketFactory ssf)
 513         throws RemoteException
 514     {
 515         return exportObject(obj, new ActivatableServerRef(id, port, csf, ssf));
 516     }
 517 
 518     /**
 519      * Remove the remote object, obj, from the RMI runtime. If
 520      * successful, the object can no longer accept incoming RMI calls.
 521      * If the force parameter is true, the object is forcibly unexported
 522      * even if there are pending calls to the remote object or the
 523      * remote object still has calls in progress.  If the force
 524      * parameter is false, the object is only unexported if there are
 525      * no pending or in progress calls to the object.
 526      *
 527      * @param obj the remote object to be unexported
 528      * @param force if true, unexports the object even if there are
 529      * pending or in-progress calls; if false, only unexports the object
 530      * if there are no pending or in-progress calls
 531      * @return true if operation is successful, false otherwise
 532      * @exception NoSuchObjectException if the remote object is not
 533      * currently exported
 534      * @since 1.2
 535      */
 536     public static boolean unexportObject(Remote obj, boolean force)
 537         throws NoSuchObjectException
 538     {
 539         return sun.rmi.transport.ObjectTable.unexportObject(obj, force);
 540     }
 541 
 542     /**
 543      * Exports the specified object using the specified server ref.
 544      */
 545     private static Remote exportObject(Remote obj, ActivatableServerRef sref)
 546         throws RemoteException
 547     {
 548         // if obj extends Activatable, set its ref.
 549         if (obj instanceof Activatable) {
 550             ((Activatable) obj).ref = sref;
 551 
 552         }
 553         return sref.exportObject(obj, null, false);
 554     }
 555 }