1 /*
   2  * Copyright (c) 1997, 2013, Oracle and/or its affiliates. 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.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.rmi.activation;
  27 
  28 import java.lang.reflect.Constructor;
  29 import java.lang.reflect.InvocationTargetException;
  30 import java.rmi.MarshalledObject;
  31 import java.rmi.Naming;
  32 import java.rmi.Remote;
  33 import java.rmi.RemoteException;
  34 import java.rmi.activation.UnknownGroupException;
  35 import java.rmi.activation.UnknownObjectException;
  36 import java.rmi.server.RMIClassLoader;
  37 import java.rmi.server.UnicastRemoteObject;
  38 import java.security.AccessController;
  39 import java.security.PrivilegedAction;
  40 
  41 /**
  42  * An <code>ActivationGroup</code> is responsible for creating new
  43  * instances of "activatable" objects in its group, informing its
  44  * <code>ActivationMonitor</code> when either: its object's become
  45  * active or inactive, or the group as a whole becomes inactive. <p>
  46  *
  47  * An <code>ActivationGroup</code> is <i>initially</i> created in one
  48  * of several ways: <ul>
  49  * <li>as a side-effect of creating an <code>ActivationDesc</code>
  50  *     without an explicit <code>ActivationGroupID</code> for the
  51  *     first activatable object in the group, or
  52  * <li>via the <code>ActivationGroup.createGroup</code> method
  53  * <li>as a side-effect of activating the first object in a group
  54  *     whose <code>ActivationGroupDesc</code> was only registered.</ul><p>
  55  *
  56  * Only the activator can <i>recreate</i> an
  57  * <code>ActivationGroup</code>.  The activator spawns, as needed, a
  58  * separate VM (as a child process, for example) for each registered
  59  * activation group and directs activation requests to the appropriate
  60  * group. It is implementation specific how VMs are spawned. An
  61  * activation group is created via the
  62  * <code>ActivationGroup.createGroup</code> static method. The
  63  * <code>createGroup</code> method has two requirements on the group
  64  * to be created: 1) the group must be a concrete subclass of
  65  * <code>ActivationGroup</code>, and 2) the group must have a
  66  * constructor that takes two arguments:
  67  *
  68  * <ul>
  69  * <li> the group's <code>ActivationGroupID</code>, and
  70  * <li> the group's initialization data (in a
  71  *      <code>java.rmi.MarshalledObject</code>)</ul><p>
  72  *
  73  * When created, the default implementation of
  74  * <code>ActivationGroup</code> will override the system properties
  75  * with the properties requested when its
  76  * <code>ActivationGroupDesc</code> was created, and will set a
  77  * {@link SecurityManager} as the default system
  78  * security manager.  If your application requires specific properties
  79  * to be set when objects are activated in the group, the application
  80  * should create a special <code>Properties</code> object containing
  81  * these properties, then create an <code>ActivationGroupDesc</code>
  82  * with the <code>Properties</code> object, and use
  83  * <code>ActivationGroup.createGroup</code> before creating any
  84  * <code>ActivationDesc</code>s (before the default
  85  * <code>ActivationGroupDesc</code> is created).  If your application
  86  * requires the use of a security manager other than
  87  * {@link SecurityManager}, in the
  88  * ActivativationGroupDescriptor properties list you can set
  89  * <code>java.security.manager</code> property to the name of the security
  90  * manager you would like to install.
  91  *
  92  * @author      Ann Wollrath
  93  * @see         ActivationInstantiator
  94  * @see         ActivationGroupDesc
  95  * @see         ActivationGroupID
  96  * @since       1.2
  97  */
  98 public abstract class ActivationGroup
  99         extends UnicastRemoteObject
 100         implements ActivationInstantiator
 101 {
 102     /**
 103      * @serial the group's identifier
 104      */
 105     private ActivationGroupID groupID;
 106 
 107     /**
 108      * @serial the group's monitor
 109      */
 110     private ActivationMonitor monitor;
 111 
 112     /**
 113      * @serial the group's incarnation number
 114      */
 115     private long incarnation;
 116 
 117     /** the current activation group for this VM */
 118     private static ActivationGroup currGroup;
 119     /** the current group's identifier */
 120     private static ActivationGroupID currGroupID;
 121     /** the current group's activation system */
 122     private static ActivationSystem currSystem;
 123     /** used to control a group being created only once */
 124     private static boolean canCreate = true;
 125 
 126     /** indicate compatibility with the Java 2 SDK v1.2 version of class */
 127     private static final long serialVersionUID = -7696947875314805420L;
 128 
 129     /**
 130      * Constructs an activation group with the given activation group
 131      * identifier.  The group is exported as a
 132      * <code>java.rmi.server.UnicastRemoteObject</code>.
 133      *
 134      * @param   groupID the group's identifier
 135      * @throws  RemoteException if this group could not be exported
 136      * @throws  UnsupportedOperationException if and only if activation is
 137      *          not supported by this implementation
 138      * @since   1.2
 139      */
 140     protected ActivationGroup(ActivationGroupID groupID)
 141         throws RemoteException
 142     {
 143         // call super constructor to export the object
 144         super();
 145         this.groupID = groupID;
 146     }
 147 
 148     /**
 149      * The group's <code>inactiveObject</code> method is called
 150      * indirectly via a call to the <code>Activatable.inactive</code>
 151      * method. A remote object implementation must call
 152      * <code>Activatable</code>'s <code>inactive</code> method when
 153      * that object deactivates (the object deems that it is no longer
 154      * active). If the object does not call
 155      * <code>Activatable.inactive</code> when it deactivates, the
 156      * object will never be garbage collected since the group keeps
 157      * strong references to the objects it creates.
 158      *
 159      * <p>The group's <code>inactiveObject</code> method unexports the
 160      * remote object from the RMI runtime so that the object can no
 161      * longer receive incoming RMI calls. An object will only be unexported
 162      * if the object has no pending or executing calls.
 163      * The subclass of <code>ActivationGroup</code> must override this
 164      * method and unexport the object.
 165      *
 166      * <p>After removing the object from the RMI runtime, the group
 167      * must inform its <code>ActivationMonitor</code> (via the monitor's
 168      * <code>inactiveObject</code> method) that the remote object is
 169      * not currently active so that the remote object will be
 170      * re-activated by the activator upon a subsequent activation
 171      * request.
 172      *
 173      * <p>This method simply informs the group's monitor that the object
 174      * is inactive.  It is up to the concrete subclass of ActivationGroup
 175      * to fulfill the additional requirement of unexporting the object. <p>
 176      *
 177      * @param id the object's activation identifier
 178      * @return true if the object was successfully deactivated; otherwise
 179      *         returns false.
 180      * @exception UnknownObjectException if object is unknown (may already
 181      * be inactive)
 182      * @exception RemoteException if call informing monitor fails
 183      * @exception ActivationException if group is inactive
 184      * @since 1.2
 185      */
 186     public boolean inactiveObject(ActivationID id)
 187         throws ActivationException, UnknownObjectException, RemoteException
 188     {
 189         getMonitor().inactiveObject(id);
 190         return true;
 191     }
 192 
 193     /**
 194      * The group's <code>activeObject</code> method is called when an
 195      * object is exported (either by <code>Activatable</code> object
 196      * construction or an explicit call to
 197      * <code>Activatable.exportObject</code>. The group must inform its
 198      * <code>ActivationMonitor</code> that the object is active (via
 199      * the monitor's <code>activeObject</code> method) if the group
 200      * hasn't already done so.
 201      *
 202      * @param id the object's identifier
 203      * @param obj the remote object implementation
 204      * @exception UnknownObjectException if object is not registered
 205      * @exception RemoteException if call informing monitor fails
 206      * @exception ActivationException if group is inactive
 207      * @since 1.2
 208      */
 209     public abstract void activeObject(ActivationID id, Remote obj)
 210         throws ActivationException, UnknownObjectException, RemoteException;
 211 
 212     /**
 213      * Create and set the activation group for the current VM.  The
 214      * activation group can only be set if it is not currently set.
 215      * An activation group is set using the <code>createGroup</code>
 216      * method when the <code>Activator</code> initiates the
 217      * re-creation of an activation group in order to carry out
 218      * incoming <code>activate</code> requests. A group must first be
 219      * registered with the <code>ActivationSystem</code> before it can
 220      * be created via this method.
 221      *
 222      * <p>The group class specified by the
 223      * <code>ActivationGroupDesc</code> must be a concrete subclass of
 224      * <code>ActivationGroup</code> and have a public constructor that
 225      * takes two arguments: the <code>ActivationGroupID</code> for the
 226      * group and the <code>MarshalledObject</code> containing the
 227      * group's initialization data (obtained from the
 228      * <code>ActivationGroupDesc</code>.
 229      *
 230      * <p>If the group class name specified in the
 231      * <code>ActivationGroupDesc</code> is <code>null</code>, then
 232      * this method will behave as if the group descriptor contained
 233      * the name of the default activation group implementation class.
 234      *
 235      * <p>Note that if your application creates its own custom
 236      * activation group, a security manager must be set for that
 237      * group.  Otherwise objects cannot be activated in the group.
 238      * {@link SecurityManager} is set by default.
 239      *
 240      * <p>If a security manager is already set in the group VM, this
 241      * method first calls the security manager's
 242      * <code>checkSetFactory</code> method.  This could result in a
 243      * <code>SecurityException</code>. If your application needs to
 244      * set a different security manager, you must ensure that the
 245      * policy file specified by the group's
 246      * <code>ActivationGroupDesc</code> grants the group the necessary
 247      * permissions to set a new security manager.  (Note: This will be
 248      * necessary if your group downloads and sets a security manager).
 249      *
 250      * <p>After the group is created, the
 251      * <code>ActivationSystem</code> is informed that the group is
 252      * active by calling the <code>activeGroup</code> method which
 253      * returns the <code>ActivationMonitor</code> for the group. The
 254      * application need not call <code>activeGroup</code>
 255      * independently since it is taken care of by this method.
 256      *
 257      * <p>Once a group is created, subsequent calls to the
 258      * <code>currentGroupID</code> method will return the identifier
 259      * for this group until the group becomes inactive.
 260      *
 261      * @param id the activation group's identifier
 262      * @param desc the activation group's descriptor
 263      * @param incarnation the group's incarnation number (zero on group's
 264      * initial creation)
 265      * @return the activation group for the VM
 266      * @exception ActivationException if group already exists or if error
 267      * occurs during group creation
 268      * @exception SecurityException if permission to create group is denied.
 269      * (Note: The default implementation of the security manager
 270      * <code>checkSetFactory</code>
 271      * method requires the RuntimePermission "setFactory")
 272      * @exception UnsupportedOperationException if and only if activation is
 273      * not supported by this implementation
 274      * @see SecurityManager#checkSetFactory
 275      * @since 1.2
 276      */
 277     public static synchronized
 278         ActivationGroup createGroup(ActivationGroupID id,
 279                                     final ActivationGroupDesc desc,
 280                                     long incarnation)
 281         throws ActivationException
 282     {
 283         SecurityManager security = System.getSecurityManager();
 284         if (security != null)
 285             security.checkSetFactory();
 286 
 287         if (currGroup != null)
 288             throw new ActivationException("group already exists");
 289 
 290         if (canCreate == false)
 291             throw new ActivationException("group deactivated and " +
 292                                           "cannot be recreated");
 293 
 294         try {
 295             // load group's class
 296             String groupClassName = desc.getClassName();
 297             Class<? extends ActivationGroup> cl;
 298             Class<? extends ActivationGroup> defaultGroupClass =
 299                 sun.rmi.server.ActivationGroupImpl.class;
 300             if (groupClassName == null ||       // see 4252236
 301                 groupClassName.equals(defaultGroupClass.getName()))
 302             {
 303                 cl = defaultGroupClass;
 304             } else {
 305                 Class<?> cl0;
 306                 try {
 307                     cl0 = RMIClassLoader.loadClass(desc.getLocation(),
 308                                                    groupClassName);
 309                 } catch (Exception ex) {
 310                     throw new ActivationException(
 311                         "Could not load group implementation class", ex);
 312                 }
 313                 if (ActivationGroup.class.isAssignableFrom(cl0)) {
 314                     cl = cl0.asSubclass(ActivationGroup.class);
 315                 } else {
 316                     throw new ActivationException("group not correct class: " +
 317                                                   cl0.getName());
 318                 }
 319             }
 320 
 321             // create group
 322             Constructor<? extends ActivationGroup> constructor =
 323                 cl.getConstructor(ActivationGroupID.class,
 324                                   MarshalledObject.class);
 325             ActivationGroup newGroup =
 326                 constructor.newInstance(id, desc.getData());
 327             currSystem = id.getSystem();
 328             newGroup.incarnation = incarnation;
 329             newGroup.monitor =
 330                 currSystem.activeGroup(id, newGroup, incarnation);
 331             currGroup = newGroup;
 332             currGroupID = id;
 333             canCreate = false;
 334         } catch (InvocationTargetException e) {
 335                 e.getTargetException().printStackTrace();
 336                 throw new ActivationException("exception in group constructor",
 337                                               e.getTargetException());
 338 
 339         } catch (ActivationException e) {
 340             throw e;
 341 
 342         } catch (Exception e) {
 343             throw new ActivationException("exception creating group", e);
 344         }
 345 
 346         return currGroup;
 347     }
 348 
 349     /**
 350      * Returns the current activation group's identifier.  Returns null
 351      * if no group is currently active for this VM.
 352      * @exception UnsupportedOperationException if and only if activation is
 353      * not supported by this implementation
 354      * @return the activation group's identifier
 355      * @since 1.2
 356      */
 357     public static synchronized ActivationGroupID currentGroupID() {
 358         return currGroupID;
 359     }
 360 
 361     /**
 362      * Returns the activation group identifier for the VM.  If an
 363      * activation group does not exist for this VM, a default
 364      * activation group is created. A group can be created only once,
 365      * so if a group has already become active and deactivated.
 366      *
 367      * @return the activation group identifier
 368      * @exception ActivationException if error occurs during group
 369      * creation, if security manager is not set, or if the group
 370      * has already been created and deactivated.
 371      */
 372     static synchronized ActivationGroupID internalCurrentGroupID()
 373         throws ActivationException
 374     {
 375         if (currGroupID == null)
 376             throw new ActivationException("nonexistent group");
 377 
 378         return currGroupID;
 379     }
 380 
 381     /**
 382      * Set the activation system for the VM.  The activation system can
 383      * only be set it if no group is currently active. If the activation
 384      * system is not set via this call, then the <code>getSystem</code>
 385      * method attempts to obtain a reference to the
 386      * <code>ActivationSystem</code> by looking up the name
 387      * "java.rmi.activation.ActivationSystem" in the Activator's
 388      * registry. By default, the port number used to look up the
 389      * activation system is defined by
 390      * <code>ActivationSystem.SYSTEM_PORT</code>. This port can be overridden
 391      * by setting the property <code>java.rmi.activation.port</code>.
 392      *
 393      * <p>If there is a security manager, this method first
 394      * calls the security manager's <code>checkSetFactory</code> method.
 395      * This could result in a SecurityException.
 396      *
 397      * @param system remote reference to the <code>ActivationSystem</code>
 398      * @exception ActivationException if activation system is already set
 399      * @exception SecurityException if permission to set the activation system is denied.
 400      * (Note: The default implementation of the security manager
 401      * <code>checkSetFactory</code>
 402      * method requires the RuntimePermission "setFactory")
 403      * @exception UnsupportedOperationException if and only if activation is
 404      * not supported by this implementation
 405      * @see #getSystem
 406      * @see SecurityManager#checkSetFactory
 407      * @since 1.2
 408      */
 409     public static synchronized void setSystem(ActivationSystem system)
 410         throws ActivationException
 411     {
 412         SecurityManager security = System.getSecurityManager();
 413         if (security != null)
 414             security.checkSetFactory();
 415 
 416         if (currSystem != null)
 417             throw new ActivationException("activation system already set");
 418 
 419         currSystem = system;
 420     }
 421 
 422     /**
 423      * Returns the activation system for the VM. The activation system
 424      * may be set by the <code>setSystem</code> method. If the
 425      * activation system is not set via the <code>setSystem</code>
 426      * method, then the <code>getSystem</code> method attempts to
 427      * obtain a reference to the <code>ActivationSystem</code> by
 428      * looking up the name "java.rmi.activation.ActivationSystem" in
 429      * the Activator's registry. By default, the port number used to
 430      * look up the activation system is defined by
 431      * <code>ActivationSystem.SYSTEM_PORT</code>. This port can be
 432      * overridden by setting the property
 433      * <code>java.rmi.activation.port</code>.
 434      *
 435      * @return the activation system for the VM/group
 436      * @exception ActivationException if activation system cannot be
 437      *  obtained or is not bound
 438      * (means that it is not running)
 439      * @exception UnsupportedOperationException if and only if activation is
 440      * not supported by this implementation
 441      * @see #setSystem
 442      * @since 1.2
 443      */
 444     public static synchronized ActivationSystem getSystem()
 445         throws ActivationException
 446     {
 447         if (currSystem == null) {
 448             try {
 449                 int port = AccessController.doPrivileged((PrivilegedAction<Integer>) () -> 
 450                     Integer.getInteger("java.rmi.activation.port", ActivationSystem.SYSTEM_PORT));
 451                 currSystem = (ActivationSystem)
 452                     Naming.lookup("//:" + port +
 453                                   "/java.rmi.activation.ActivationSystem");
 454             } catch (Exception e) {
 455                 throw new ActivationException(
 456                     "unable to obtain ActivationSystem", e);
 457             }
 458         }
 459         return currSystem;
 460     }
 461 
 462     /**
 463      * This protected method is necessary for subclasses to
 464      * make the <code>activeObject</code> callback to the group's
 465      * monitor. The call is simply forwarded to the group's
 466      * <code>ActivationMonitor</code>.
 467      *
 468      * @param id the object's identifier
 469      * @param mobj a marshalled object containing the remote object's stub
 470      * @exception UnknownObjectException if object is not registered
 471      * @exception RemoteException if call informing monitor fails
 472      * @exception ActivationException if an activation error occurs
 473      * @since 1.2
 474      */
 475     protected void activeObject(ActivationID id,
 476                                 MarshalledObject<? extends Remote> mobj)
 477         throws ActivationException, UnknownObjectException, RemoteException
 478     {
 479         getMonitor().activeObject(id, mobj);
 480     }
 481 
 482     /**
 483      * This protected method is necessary for subclasses to
 484      * make the <code>inactiveGroup</code> callback to the group's
 485      * monitor. The call is simply forwarded to the group's
 486      * <code>ActivationMonitor</code>. Also, the current group
 487      * for the VM is set to null.
 488      *
 489      * @exception UnknownGroupException if group is not registered
 490      * @exception RemoteException if call informing monitor fails
 491      * @since 1.2
 492      */
 493     protected void inactiveGroup()
 494         throws UnknownGroupException, RemoteException
 495     {
 496         try {
 497             getMonitor().inactiveGroup(groupID, incarnation);
 498         } finally {
 499             destroyGroup();
 500         }
 501     }
 502 
 503     /**
 504      * Returns the monitor for the activation group.
 505      */
 506     private ActivationMonitor getMonitor() throws RemoteException {
 507         synchronized (ActivationGroup.class) {
 508             if (monitor != null) {
 509                 return monitor;
 510             }
 511         }
 512         throw new RemoteException("monitor not received");
 513     }
 514 
 515     /**
 516      * Destroys the current group.
 517      */
 518     private static synchronized void destroyGroup() {
 519         currGroup = null;
 520         currGroupID = null;
 521         // NOTE: don't set currSystem to null since it may be needed
 522     }
 523 
 524     /**
 525      * Returns the current group for the VM.
 526      * @exception ActivationException if current group is null (not active)
 527      */
 528     static synchronized ActivationGroup currentGroup()
 529         throws ActivationException
 530     {
 531         if (currGroup == null) {
 532             throw new ActivationException("group is not active");
 533         }
 534         return currGroup;
 535     }
 536 
 537 }