0N/A/*
2362N/A * Copyright (c) 1997, 2005, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage java.rmi.activation;
0N/A
0N/Aimport java.lang.reflect.Constructor;
0N/Aimport java.lang.reflect.InvocationTargetException;
0N/Aimport java.rmi.MarshalledObject;
0N/Aimport java.rmi.Naming;
0N/Aimport java.rmi.Remote;
0N/Aimport java.rmi.RemoteException;
0N/Aimport java.rmi.activation.UnknownGroupException;
0N/Aimport java.rmi.activation.UnknownObjectException;
0N/Aimport java.rmi.server.RMIClassLoader;
0N/Aimport java.rmi.server.UnicastRemoteObject;
0N/Aimport java.security.AccessController;
0N/Aimport sun.security.action.GetIntegerAction;
0N/A
0N/A/**
0N/A * An <code>ActivationGroup</code> is responsible for creating new
0N/A * instances of "activatable" objects in its group, informing its
0N/A * <code>ActivationMonitor</code> when either: its object's become
0N/A * active or inactive, or the group as a whole becomes inactive. <p>
0N/A *
0N/A * An <code>ActivationGroup</code> is <i>initially</i> created in one
0N/A * of several ways: <ul>
0N/A * <li>as a side-effect of creating an <code>ActivationDesc</code>
0N/A * without an explicit <code>ActivationGroupID</code> for the
0N/A * first activatable object in the group, or
0N/A * <li>via the <code>ActivationGroup.createGroup</code> method
0N/A * <li>as a side-effect of activating the first object in a group
0N/A * whose <code>ActivationGroupDesc</code> was only registered.</ul><p>
0N/A *
0N/A * Only the activator can <i>recreate</i> an
0N/A * <code>ActivationGroup</code>. The activator spawns, as needed, a
0N/A * separate VM (as a child process, for example) for each registered
0N/A * activation group and directs activation requests to the appropriate
0N/A * group. It is implementation specific how VMs are spawned. An
0N/A * activation group is created via the
0N/A * <code>ActivationGroup.createGroup</code> static method. The
0N/A * <code>createGroup</code> method has two requirements on the group
0N/A * to be created: 1) the group must be a concrete subclass of
0N/A * <code>ActivationGroup</code>, and 2) the group must have a
0N/A * constructor that takes two arguments:
0N/A *
0N/A * <ul>
0N/A * <li> the group's <code>ActivationGroupID</code>, and
0N/A * <li> the group's initialization data (in a
0N/A * <code>java.rmi.MarshalledObject</code>)</ul><p>
0N/A *
0N/A * When created, the default implementation of
0N/A * <code>ActivationGroup</code> will override the system properties
0N/A * with the properties requested when its
0N/A * <code>ActivationGroupDesc</code> was created, and will set a
0N/A * <code>java.rmi.RMISecurityManager</code> as the default system
0N/A * security manager. If your application requires specific properties
0N/A * to be set when objects are activated in the group, the application
0N/A * should create a special <code>Properties</code> object containing
0N/A * these properties, then create an <code>ActivationGroupDesc</code>
0N/A * with the <code>Properties</code> object, and use
0N/A * <code>ActivationGroup.createGroup</code> before creating any
0N/A * <code>ActivationDesc</code>s (before the default
0N/A * <code>ActivationGroupDesc</code> is created). If your application
0N/A * requires the use of a security manager other than
0N/A * <code>java.rmi.RMISecurityManager</code>, in the
0N/A * ActivativationGroupDescriptor properties list you can set
0N/A * <code>java.security.manager</code> property to the name of the security
0N/A * manager you would like to install.
0N/A *
0N/A * @author Ann Wollrath
0N/A * @see ActivationInstantiator
0N/A * @see ActivationGroupDesc
0N/A * @see ActivationGroupID
0N/A * @since 1.2
0N/A */
0N/Apublic abstract class ActivationGroup
0N/A extends UnicastRemoteObject
0N/A implements ActivationInstantiator
0N/A{
0N/A /**
0N/A * @serial the group's identifier
0N/A */
0N/A private ActivationGroupID groupID;
0N/A
0N/A /**
0N/A * @serial the group's monitor
0N/A */
0N/A private ActivationMonitor monitor;
0N/A
0N/A /**
0N/A * @serial the group's incarnation number
0N/A */
0N/A private long incarnation;
0N/A
0N/A /** the current activation group for this VM */
0N/A private static ActivationGroup currGroup;
0N/A /** the current group's identifier */
0N/A private static ActivationGroupID currGroupID;
0N/A /** the current group's activation system */
0N/A private static ActivationSystem currSystem;
0N/A /** used to control a group being created only once */
0N/A private static boolean canCreate = true;
0N/A
0N/A /** indicate compatibility with the Java 2 SDK v1.2 version of class */
0N/A private static final long serialVersionUID = -7696947875314805420L;
0N/A
0N/A /**
0N/A * Constructs an activation group with the given activation group
0N/A * identifier. The group is exported as a
0N/A * <code>java.rmi.server.UnicastRemoteObject</code>.
0N/A *
0N/A * @param groupID the group's identifier
0N/A * @throws RemoteException if this group could not be exported
0N/A * @since 1.2
0N/A */
0N/A protected ActivationGroup(ActivationGroupID groupID)
0N/A throws RemoteException
0N/A {
0N/A // call super constructor to export the object
0N/A super();
0N/A this.groupID = groupID;
0N/A }
0N/A
0N/A /**
0N/A * The group's <code>inactiveObject</code> method is called
0N/A * indirectly via a call to the <code>Activatable.inactive</code>
0N/A * method. A remote object implementation must call
0N/A * <code>Activatable</code>'s <code>inactive</code> method when
0N/A * that object deactivates (the object deems that it is no longer
0N/A * active). If the object does not call
0N/A * <code>Activatable.inactive</code> when it deactivates, the
0N/A * object will never be garbage collected since the group keeps
0N/A * strong references to the objects it creates. <p>
0N/A *
0N/A * <p>The group's <code>inactiveObject</code> method unexports the
0N/A * remote object from the RMI runtime so that the object can no
0N/A * longer receive incoming RMI calls. An object will only be unexported
0N/A * if the object has no pending or executing calls.
0N/A * The subclass of <code>ActivationGroup</code> must override this
0N/A * method and unexport the object. <p>
0N/A *
0N/A * <p>After removing the object from the RMI runtime, the group
0N/A * must inform its <code>ActivationMonitor</code> (via the monitor's
0N/A * <code>inactiveObject</code> method) that the remote object is
0N/A * not currently active so that the remote object will be
0N/A * re-activated by the activator upon a subsequent activation
0N/A * request.<p>
0N/A *
0N/A * <p>This method simply informs the group's monitor that the object
0N/A * is inactive. It is up to the concrete subclass of ActivationGroup
0N/A * to fulfill the additional requirement of unexporting the object. <p>
0N/A *
0N/A * @param id the object's activation identifier
0N/A * @return true if the object was successfully deactivated; otherwise
0N/A * returns false.
0N/A * @exception UnknownObjectException if object is unknown (may already
0N/A * be inactive)
0N/A * @exception RemoteException if call informing monitor fails
0N/A * @exception ActivationException if group is inactive
0N/A * @since 1.2
0N/A */
0N/A public boolean inactiveObject(ActivationID id)
0N/A throws ActivationException, UnknownObjectException, RemoteException
0N/A {
0N/A getMonitor().inactiveObject(id);
0N/A return true;
0N/A }
0N/A
0N/A /**
0N/A * The group's <code>activeObject</code> method is called when an
0N/A * object is exported (either by <code>Activatable</code> object
0N/A * construction or an explicit call to
0N/A * <code>Activatable.exportObject</code>. The group must inform its
0N/A * <code>ActivationMonitor</code> that the object is active (via
0N/A * the monitor's <code>activeObject</code> method) if the group
0N/A * hasn't already done so.
0N/A *
0N/A * @param id the object's identifier
0N/A * @param obj the remote object implementation
0N/A * @exception UnknownObjectException if object is not registered
0N/A * @exception RemoteException if call informing monitor fails
0N/A * @exception ActivationException if group is inactive
0N/A * @since 1.2
0N/A */
0N/A public abstract void activeObject(ActivationID id, Remote obj)
0N/A throws ActivationException, UnknownObjectException, RemoteException;
0N/A
0N/A /**
0N/A * Create and set the activation group for the current VM. The
0N/A * activation group can only be set if it is not currently set.
0N/A * An activation group is set using the <code>createGroup</code>
0N/A * method when the <code>Activator</code> initiates the
0N/A * re-creation of an activation group in order to carry out
0N/A * incoming <code>activate</code> requests. A group must first be
0N/A * registered with the <code>ActivationSystem</code> before it can
0N/A * be created via this method.
0N/A *
0N/A * <p>The group class specified by the
0N/A * <code>ActivationGroupDesc</code> must be a concrete subclass of
0N/A * <code>ActivationGroup</code> and have a public constructor that
0N/A * takes two arguments: the <code>ActivationGroupID</code> for the
0N/A * group and the <code>MarshalledObject</code> containing the
0N/A * group's initialization data (obtained from the
0N/A * <code>ActivationGroupDesc</code>.
0N/A *
0N/A * <p>If the group class name specified in the
0N/A * <code>ActivationGroupDesc</code> is <code>null</code>, then
0N/A * this method will behave as if the group descriptor contained
0N/A * the name of the default activation group implementation class.
0N/A *
0N/A * <p>Note that if your application creates its own custom
0N/A * activation group, a security manager must be set for that
0N/A * group. Otherwise objects cannot be activated in the group.
0N/A * <code>java.rmi.RMISecurityManager</code> is set by default.
0N/A *
0N/A * <p>If a security manager is already set in the group VM, this
0N/A * method first calls the security manager's
0N/A * <code>checkSetFactory</code> method. This could result in a
0N/A * <code>SecurityException</code>. If your application needs to
0N/A * set a different security manager, you must ensure that the
0N/A * policy file specified by the group's
0N/A * <code>ActivationGroupDesc</code> grants the group the necessary
0N/A * permissions to set a new security manager. (Note: This will be
0N/A * necessary if your group downloads and sets a security manager).
0N/A *
0N/A * <p>After the group is created, the
0N/A * <code>ActivationSystem</code> is informed that the group is
0N/A * active by calling the <code>activeGroup</code> method which
0N/A * returns the <code>ActivationMonitor</code> for the group. The
0N/A * application need not call <code>activeGroup</code>
0N/A * independently since it is taken care of by this method.
0N/A *
0N/A * <p>Once a group is created, subsequent calls to the
0N/A * <code>currentGroupID</code> method will return the identifier
0N/A * for this group until the group becomes inactive.
0N/A *
0N/A * @param id the activation group's identifier
0N/A * @param desc the activation group's descriptor
0N/A * @param incarnation the group's incarnation number (zero on group's
0N/A * initial creation)
0N/A * @return the activation group for the VM
0N/A * @exception ActivationException if group already exists or if error
0N/A * occurs during group creation
0N/A * @exception SecurityException if permission to create group is denied.
0N/A * (Note: The default implementation of the security manager
0N/A * <code>checkSetFactory</code>
0N/A * method requires the RuntimePermission "setFactory")
0N/A * @see SecurityManager#checkSetFactory
0N/A * @since 1.2
0N/A */
0N/A public static synchronized
0N/A ActivationGroup createGroup(ActivationGroupID id,
0N/A final ActivationGroupDesc desc,
0N/A long incarnation)
0N/A throws ActivationException
0N/A {
0N/A SecurityManager security = System.getSecurityManager();
0N/A if (security != null)
0N/A security.checkSetFactory();
0N/A
0N/A if (currGroup != null)
0N/A throw new ActivationException("group already exists");
0N/A
0N/A if (canCreate == false)
0N/A throw new ActivationException("group deactivated and " +
0N/A "cannot be recreated");
0N/A
0N/A try {
0N/A // load group's class
0N/A String groupClassName = desc.getClassName();
0N/A Class<? extends ActivationGroup> cl;
0N/A Class<? extends ActivationGroup> defaultGroupClass =
0N/A sun.rmi.server.ActivationGroupImpl.class;
0N/A if (groupClassName == null || // see 4252236
0N/A groupClassName.equals(defaultGroupClass.getName()))
0N/A {
0N/A cl = defaultGroupClass;
0N/A } else {
0N/A Class<?> cl0;
0N/A try {
0N/A cl0 = RMIClassLoader.loadClass(desc.getLocation(),
0N/A groupClassName);
0N/A } catch (Exception ex) {
0N/A throw new ActivationException(
0N/A "Could not load group implementation class", ex);
0N/A }
0N/A if (ActivationGroup.class.isAssignableFrom(cl0)) {
0N/A cl = cl0.asSubclass(ActivationGroup.class);
0N/A } else {
0N/A throw new ActivationException("group not correct class: " +
0N/A cl0.getName());
0N/A }
0N/A }
0N/A
0N/A // create group
0N/A Constructor<? extends ActivationGroup> constructor =
0N/A cl.getConstructor(ActivationGroupID.class,
0N/A MarshalledObject.class);
0N/A ActivationGroup newGroup =
0N/A constructor.newInstance(id, desc.getData());
0N/A currSystem = id.getSystem();
0N/A newGroup.incarnation = incarnation;
0N/A newGroup.monitor =
0N/A currSystem.activeGroup(id, newGroup, incarnation);
0N/A currGroup = newGroup;
0N/A currGroupID = id;
0N/A canCreate = false;
0N/A } catch (InvocationTargetException e) {
0N/A e.getTargetException().printStackTrace();
0N/A throw new ActivationException("exception in group constructor",
0N/A e.getTargetException());
0N/A
0N/A } catch (ActivationException e) {
0N/A throw e;
0N/A
0N/A } catch (Exception e) {
0N/A throw new ActivationException("exception creating group", e);
0N/A }
0N/A
0N/A return currGroup;
0N/A }
0N/A
0N/A /**
0N/A * Returns the current activation group's identifier. Returns null
0N/A * if no group is currently active for this VM.
0N/A * @return the activation group's identifier
0N/A * @since 1.2
0N/A */
0N/A public static synchronized ActivationGroupID currentGroupID() {
0N/A return currGroupID;
0N/A }
0N/A
0N/A /**
0N/A * Returns the activation group identifier for the VM. If an
0N/A * activation group does not exist for this VM, a default
0N/A * activation group is created. A group can be created only once,
0N/A * so if a group has already become active and deactivated.
0N/A *
0N/A * @return the activation group identifier
0N/A * @exception ActivationException if error occurs during group
0N/A * creation, if security manager is not set, or if the group
0N/A * has already been created and deactivated.
0N/A */
0N/A static synchronized ActivationGroupID internalCurrentGroupID()
0N/A throws ActivationException
0N/A {
0N/A if (currGroupID == null)
0N/A throw new ActivationException("nonexistent group");
0N/A
0N/A return currGroupID;
0N/A }
0N/A
0N/A /**
0N/A * Set the activation system for the VM. The activation system can
0N/A * only be set it if no group is currently active. If the activation
0N/A * system is not set via this call, then the <code>getSystem</code>
0N/A * method attempts to obtain a reference to the
0N/A * <code>ActivationSystem</code> by looking up the name
0N/A * "java.rmi.activation.ActivationSystem" in the Activator's
0N/A * registry. By default, the port number used to look up the
0N/A * activation system is defined by
0N/A * <code>ActivationSystem.SYSTEM_PORT</code>. This port can be overridden
0N/A * by setting the property <code>java.rmi.activation.port</code>.
0N/A *
0N/A * <p>If there is a security manager, this method first
0N/A * calls the security manager's <code>checkSetFactory</code> method.
0N/A * This could result in a SecurityException.
0N/A *
0N/A * @param system remote reference to the <code>ActivationSystem</code>
0N/A * @exception ActivationException if activation system is already set
0N/A * @exception SecurityException if permission to set the activation system is denied.
0N/A * (Note: The default implementation of the security manager
0N/A * <code>checkSetFactory</code>
0N/A * method requires the RuntimePermission "setFactory")
0N/A * @see #getSystem
0N/A * @see SecurityManager#checkSetFactory
0N/A * @since 1.2
0N/A */
0N/A public static synchronized void setSystem(ActivationSystem system)
0N/A throws ActivationException
0N/A {
0N/A SecurityManager security = System.getSecurityManager();
0N/A if (security != null)
0N/A security.checkSetFactory();
0N/A
0N/A if (currSystem != null)
0N/A throw new ActivationException("activation system already set");
0N/A
0N/A currSystem = system;
0N/A }
0N/A
0N/A /**
0N/A * Returns the activation system for the VM. The activation system
0N/A * may be set by the <code>setSystem</code> method. If the
0N/A * activation system is not set via the <code>setSystem</code>
0N/A * method, then the <code>getSystem</code> method attempts to
0N/A * obtain a reference to the <code>ActivationSystem</code> by
0N/A * looking up the name "java.rmi.activation.ActivationSystem" in
0N/A * the Activator's registry. By default, the port number used to
0N/A * look up the activation system is defined by
0N/A * <code>ActivationSystem.SYSTEM_PORT</code>. This port can be
0N/A * overridden by setting the property
0N/A * <code>java.rmi.activation.port</code>.
0N/A *
0N/A * @return the activation system for the VM/group
0N/A * @exception ActivationException if activation system cannot be
0N/A * obtained or is not bound
0N/A * (means that it is not running)
0N/A * @see #setSystem
0N/A * @since 1.2
0N/A */
0N/A public static synchronized ActivationSystem getSystem()
0N/A throws ActivationException
0N/A {
0N/A if (currSystem == null) {
0N/A try {
0N/A int port = AccessController.doPrivileged(
0N/A new GetIntegerAction("java.rmi.activation.port",
0N/A ActivationSystem.SYSTEM_PORT));
0N/A currSystem = (ActivationSystem)
0N/A Naming.lookup("//:" + port +
0N/A "/java.rmi.activation.ActivationSystem");
0N/A } catch (Exception e) {
0N/A throw new ActivationException(
0N/A "unable to obtain ActivationSystem", e);
0N/A }
0N/A }
0N/A return currSystem;
0N/A }
0N/A
0N/A /**
0N/A * This protected method is necessary for subclasses to
0N/A * make the <code>activeObject</code> callback to the group's
0N/A * monitor. The call is simply forwarded to the group's
0N/A * <code>ActivationMonitor</code>.
0N/A *
0N/A * @param id the object's identifier
0N/A * @param mobj a marshalled object containing the remote object's stub
0N/A * @exception UnknownObjectException if object is not registered
0N/A * @exception RemoteException if call informing monitor fails
0N/A * @exception ActivationException if an activation error occurs
0N/A * @since 1.2
0N/A */
0N/A protected void activeObject(ActivationID id,
0N/A MarshalledObject<? extends Remote> mobj)
0N/A throws ActivationException, UnknownObjectException, RemoteException
0N/A {
0N/A getMonitor().activeObject(id, mobj);
0N/A }
0N/A
0N/A /**
0N/A * This protected method is necessary for subclasses to
0N/A * make the <code>inactiveGroup</code> callback to the group's
0N/A * monitor. The call is simply forwarded to the group's
0N/A * <code>ActivationMonitor</code>. Also, the current group
0N/A * for the VM is set to null.
0N/A *
0N/A * @exception UnknownGroupException if group is not registered
0N/A * @exception RemoteException if call informing monitor fails
0N/A * @since 1.2
0N/A */
0N/A protected void inactiveGroup()
0N/A throws UnknownGroupException, RemoteException
0N/A {
0N/A try {
0N/A getMonitor().inactiveGroup(groupID, incarnation);
0N/A } finally {
0N/A destroyGroup();
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Returns the monitor for the activation group.
0N/A */
0N/A private ActivationMonitor getMonitor() throws RemoteException {
0N/A synchronized (ActivationGroup.class) {
0N/A if (monitor != null) {
0N/A return monitor;
0N/A }
0N/A }
0N/A throw new RemoteException("monitor not received");
0N/A }
0N/A
0N/A /**
0N/A * Destroys the current group.
0N/A */
0N/A private static synchronized void destroyGroup() {
0N/A currGroup = null;
0N/A currGroupID = null;
0N/A // NOTE: don't set currSystem to null since it may be needed
0N/A }
0N/A
0N/A /**
0N/A * Returns the current group for the VM.
0N/A * @exception ActivationException if current group is null (not active)
0N/A */
0N/A static synchronized ActivationGroup currentGroup()
0N/A throws ActivationException
0N/A {
0N/A if (currGroup == null) {
0N/A throw new ActivationException("group is not active");
0N/A }
0N/A return currGroup;
0N/A }
0N/A
0N/A}