home *** CD-ROM | disk | FTP | other *** search
Java Source | 1998-03-20 | 18.7 KB | 529 lines |
- /*
- * @(#)ActivationGroup.java 1.10 98/03/18
- *
- * Copyright 1997, 1998 by Sun Microsystems, Inc.,
- * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
- * All rights reserved.
- *
- * This software is the confidential and proprietary information
- * of Sun Microsystems, Inc. ("Confidential Information"). You
- * shall not disclose such Confidential Information and shall use
- * it only in accordance with the terms of the license agreement
- * you entered into with Sun.
- */
-
- package java.rmi.activation;
-
- import java.lang.reflect.Constructor;
-
- import java.rmi.MarshalledObject;
- import java.rmi.Naming;
- import java.rmi.activation.UnknownGroupException;
- import java.rmi.activation.UnknownObjectException;
- import java.rmi.Remote;
- import java.rmi.RemoteException;
-
- import java.rmi.server.UnicastRemoteObject;
-
- import sun.rmi.server.LoaderHandler;
- import sun.rmi.server.RMIClassLoader;
-
- /**
- * An <code>ActivationGroup</code> is responsible for creating new
- * instances of "activatable" objects in its group, informing its
- * <code>ActivationMonitor</code> when either: its object's become
- * active or inactive, or the group as a whole becomes inactive. <p>
- *
- * An <code>ActivationGroup</code> is <i>initially</i> created in one
- * of several ways: <ul>
- * <li>as a side-effect of creating an <code>ActivationDesc</code>
- * (using its first constructor) for the first activatable
- * object in the group, or
- * <li>via the <code>ActivationGroup.createGroup</code> method
- * <li>as a side-effect of activating the first object in a group
- * whose <code>ActivationGroupDesc</code> was only registered. <p>
- *
- * Only the activator can <i>recreate</i> an
- * <code>ActivationGroup</code>. The activator spawns, as needed, a
- * separate VM (as a child process, for example) for each registered
- * activation group and directs activation requests to the appropriate
- * group. It is implementation specific how VMs are spawned. An
- * activation group is created via the
- * <code>ActivationGroup.createGroup</code> static method. The
- * <code>createGroup</code> method has two requirements on the group
- * to be created: 1) the group must be a concrete subclass of
- * <code>ActivationGroup</code>, and 2) the group must have a
- * constructor that takes two arguments:
- *
- * <ul>
- * <li> the group's <code>ActivationGroupID</code>, and
- * <li> the group's initialization data (in a
- * <code>java.rmi.MarshalledObject</code>)</ul><p>
- *
- * When created, the default implementation of
- * <code>ActivationGroup</code> will set the system properties to the
- * system properties in force when its
- * <code>ActivationGroupDesc</code> was created, and will set the
- * security manager to the <code>java.rmi.RMISecurityManager</code>.
- * If your application requires some specific properties to be set
- * when objects are activated in the group, the application should set
- * the properties before creating any <code>ActivationDesc</code>s
- * (before the default <code>ActivationGroupDesc</code> is created).
- * If your application requires the use of a security manager other
- * than the <code>RMISecurityManager</code>, set the following two
- * properties to specify the <code>SecurityManager</code> class and
- * codebase:<ul>
- *
- * <li><code>java.rmi.activation.security.class</code>
- * <li><code>java.rmi.activation.security.codebase</code></ul>
- *
- * @author Ann Wollrath
- * @version 1.10, 03/18/98
- * @see ActivationInstantiator
- * @see ActivationGroupDesc
- * @see ActivationGroupID
- * @since JDK1.2
- */
- public abstract class ActivationGroup
- extends UnicastRemoteObject
- implements ActivationInstantiator
- {
- /** the group's identifier */
- private ActivationGroupID groupID;
- /** the group's monitor */
- private ActivationMonitor monitor;
- /** the group's incarnation number */
- private long incarnation;
-
- /** the current activation group for this VM */
- private static ActivationGroup currGroup;
- /** the current group's identifier */
- private static ActivationGroupID currGroupID;
- /** the current group's activation system */
- private static ActivationSystem currSystem;
- /** used to control a group being created only once */
- private static boolean canCreate = true;
- /** formal parameters for constructing an activation group */
- private static Class[] groupConstrParams = {
- ActivationGroupID.class, MarshalledObject.class
- };
-
- /** indicate compatibility with JDK 1.2 version of class */
- private static final long serialVersionUID = -7696947875314805420L;
-
- /**
- * Constructs and exports an activation group as a UnicastRemoteObject
- * so that a client can invoke its newInstance method.
- *
- * @param groupID the group's identifier
- * @exception RemoteException if group could not be exported
- */
- protected ActivationGroup(ActivationGroupID groupID)
- throws RemoteException
- {
- // call super constructor to export the object
- super();
- this.groupID = groupID;
- }
-
- /**
- * The group's <code>inactiveObject</code> method is called
- * indirectly via a call to the <code>Activatable.inactive</code>
- * method. A remote object implementation must call
- * <code>Activatable</code>'s <code>inactive</code> method when
- * that object deactivates (the object deems that it is no longer
- * active). If the object does not call
- * <code>Activatable.inactive</code> when it deactivates, the
- * object will never be garbage collected since the group keeps
- * strong references to the objects it creates. <p>
- *
- * The group's <code>inactiveObject</code> method unexports the
- * remote object from the RMI runtime so that the object can no
- * longer receive incoming RMI calls. An object will only be unexported
- * if the object has no pending or executing calls.
- * The subclass of <code>ActivationGroup</code> must override this
- * method and unexport the object. <p>
- *
- * After removing the object from the RMI runtime, the group
- * must inform its <code>ActivationMonitor</code> (via the monitor's
- * <code>inactiveObject</code> method) that the remote object is
- * not currently active so that the remote object will be
- * re-activated by the activator upon a subsequent activation
- * request.<p>
- *
- * This method simply informs the group's monitor that the object
- * is inactive. It is up to the concrete subclass of ActivationGroup
- * to fulfil the additional requirement of unexporting the object. <p>
- *
- * @param id the object's activation identifier
- * @return true if the object was successfully deactivated; otherwise
- * returns false.
- * @exception UnknownObjectException if object is unknown (may already
- * be inactive)
- * @exception RemoteException if call informing monitor fails
- */
- public boolean inactiveObject(ActivationID id)
- throws ActivationException, UnknownObjectException, RemoteException
- {
- monitor.inactiveObject(id);
- return true;
- }
-
- /**
- * The group's <code>activeObject</code> method is called when an
- * object is exported (either by <code>Activatable</code> object
- * construction or an explicit call to
- * <code>Activatable.exportObject</code>. The group must inform its
- * <code>ActivationMonitor</code> that the object is active (via
- * the monitor's <code>activeObject</code> method) if the group
- * hasn't already done so.
- *
- * @param id the object's identifier
- * @param obj the remote object implementation
- * @exception UnknownObjectException if object is not registered
- * @exception RemoteException if call informing monitor fails
- */
- public abstract void activeObject(ActivationID id, Remote obj)
- throws ActivationException, UnknownObjectException, RemoteException;
-
- /**
- * Create and set the activation group for the current VM. The
- * activation group can only be set if it is not currently set.
- * An activation group is set using the <code>createGroup</code>
- * method when the <code>Activator</code> initiates the
- * re-creation of an activation group in order to carry out
- * incoming <code>activate</code> requests. A group must first
- * be registered with the <code>ActivationSystem</code> before
- * it can be created via this method.<p>
- *
- * The group specified by the <code>ActivationGroupDesc</code>
- * must be a concrete subclass of <code>ActivationGroup</code>
- * and have a public constructor that takes two arguments: the
- * <code>ActivationGroupID</code> for the group and the
- * <code>MarshalledObject</code> containing the group's
- * initialization data (obtained from the
- * <code>ActivationGroupDesc</code>. Note: if your application
- * creates its own custom activation group, the group must
- * set a security manager in the constructor, or objects
- * cannot be activated in the group.<p>
- *
- * After the group is created, the <code>ActivationSystem</code>
- * is informed that the group is active by calling the
- * <code>activeGroup</code> method which returns the
- * <code>ActivationMonitor</code> for the group. The application
- * need not call <code>activeGroup</code> independently since
- * it is taken care of by this method. <p>
- *
- * Once a group is created, subsequent calls to the
- * <code>currentGroupID</code> method will return the identifier for
- * this group until the group becomes inactive.
- *
- * @param id the activation group's identifier
- * @param desc the activation group's descriptor
- * @param incarnation the group's incarnation number (zero on group's
- * initial creation)
- * @return the activation group for the VM
- * @exception ActivationException if group already exists or if error
- * occurs during group creation
- */
- public static synchronized
- ActivationGroup createGroup(ActivationGroupID id,
- ActivationGroupDesc desc,
- long incarnation)
- throws ActivationException
- {
- if (currGroup != null)
- throw new ActivationException("group already exists");
-
- if (canCreate == false)
- throw new ActivationException("group deactivated and " +
- "cannot be recreated");
-
- try {
- try {
- // load group's class
- Class cl = LoaderHandler.loadClass(desc.getCodeSource(),
- desc.getClassName());
-
- // create group
- Constructor constructor = cl.getConstructor(groupConstrParams);
- Object[] params = new Object[] { id, desc.getData() };
-
- Object obj = constructor.newInstance(params);
- if (obj instanceof ActivationGroup) {
- currGroup = (ActivationGroup)obj;
- currGroupID = id;
- currSystem = id.getSystem();
- currGroup.incarnation = incarnation;
- currGroup.monitor =
- currSystem.activeGroup(id, currGroup, incarnation);
- canCreate = false;
- } else {
- throw new ActivationException("group not correct class: " +
- obj.getClass().getName());
- }
- } catch (java.lang.reflect.InvocationTargetException e) {
- throw new ActivationException("exception in group constructor",
- e.getTargetException());
-
- } catch (ActivationException e) {
- throw e;
-
- } catch (Exception e) {
- throw new ActivationException("exception creating group", e);
- }
-
- } catch (ActivationException e) {
- destroyGroup();
- canCreate = true;
- throw e;
- }
- return currGroup;
- }
-
- /**
- * Returns the current activation group's identifier. Returns null
- * if no group is currently active for this VM.
- * @return the activation group's identifier
- */
- public static synchronized ActivationGroupID currentGroupID()
- {
- return currGroupID;
- }
-
- /**
- * Returns the activation group identifier for the VM. If an
- * activation group does not exist for this VM, a default
- * activation group is created. A group can be created only once,
- * so if a group has already become active and deactivated.
- *
- * @return the activation group identifier
- * @exception ActivationException if error occurs during group
- * creation, if security manager is not set, or if the group
- * has already been created and deactivated.
- */
- static synchronized ActivationGroupID internalCurrentGroupID()
- throws ActivationException
- {
- ActivationGroupID id = currGroupID;
-
- if (id == null) {
- if (canCreate == false) {
- throw new ActivationException("group deactivated and " +
- "cannot be recreated");
- }
-
- ActivationGroupDesc desc;
- SecurityManager security = System.getSecurityManager();
- if (security == null) {
- throw new ActivationException("security manager must be set");
- }
-
- try {
- java.security.AccessController.beginPrivileged();
-
- Class cl = security.getClass();
- String codebase = null;
-
- /*
- * REMIND: there needs to be a more general
- * way to obtain the codebase of a loaded class;
- * for now, the RMIClassLoader is the only way.
- */
- ClassLoader loader = cl.getClassLoader();
- if (loader instanceof RMIClassLoader) {
- /*
- * Get codebase from classloader
- */
- codebase = ((RMIClassLoader)loader).
- getCodeBase().toExternalForm();
-
- } else {
- /*
- * Use the codebase property as the codebase of
- * the security manager class.
- */
- codebase = System.getProperty("java.rmi.server.codebase");
- }
-
- /*
- * Set activation security class and codebase properties
- */
- System.setProperty("java.rmi.activation.security.class",
- cl.getName());
- if (codebase != null) {
- System.setProperty("java.rmi.activation.security.codebase",
- codebase);
- }
-
- } catch (Exception e) {
- throw new ActivationException("unable to obtain codebase " +
- "for security manager", e);
- } finally {
- java.security.AccessController.endPrivileged();
- }
-
- try {
- desc = new ActivationGroupDesc(System.getProperties());
- id = getSystem().registerGroup(desc);
- } catch (Exception e) {
- throw new ActivationException("unable to register group", e);
- }
-
- try {
- /*
- * Note: this call also sets the currGroupID...
- */
- createGroup(id, desc, 0);
-
- } catch (ActivationException e1) {
- /*
- * Unable to create group; make an attempt to unregister
- * since the group descriptor and id are meaningless
- */
- try {
- getSystem().unregisterGroup(id);
- } catch (Exception e2) {
- /*
- * If unregister fails; rethrow first exception,
- * since that is the exception the caller is most
- * interested in.
- */
- throw e1;
- }
- }
- }
-
- return id;
- }
-
- /**
- * Set the activation system for the VM. The activation system can
- * only be set it if no group is currently active. If the activation
- * system is not set via this call, then the <code>getSystem</code>
- * method attempts to obtain a reference to the
- * <code>ActivationSystem</code> by looking up the name
- * "java.rmi.activation.ActivationSystem" in the Activator's
- * registry. By default, the port number used to look up the
- * activation system is defined by
- * <code>ActivationSystem.SYSTEM_PORT</code>. This port can be overridden
- * by setting the property <code>java.rmi.activation.port</code>.
- *
- * @param system remote reference to the <code>ActivationSystem</code>
- * @exception ActivationException if activation system is already set
- */
- public static synchronized void setSystem(ActivationSystem system)
- throws ActivationException
- {
- if (currSystem != null) {
- throw new ActivationException("activation system already set");
- }
-
- currSystem = system;
- }
-
- /**
- * Returns the activation system for the VM. The activation system
- * may be set by the <code>setSystem</code> method. If the
- * activation system is not set via the <code>setSystem</code>
- * method, then the <code>getSystem</code> method attempts to
- * obtain a reference to the <code>ActivationSystem</code> by
- * looking up the name "java.rmi.activation.ActivationSystem" in
- * the Activator's registry. By default, the port number used to
- * look up the activation system is defined by
- * <code>ActivationSystem.SYSTEM_PORT</code>. This port can be
- * overridden by setting the property
- * <code>java.rmi.activation.port</code>.
- *
- * @return the activation system for the VM/group
- * @exception if activation system cannot be obtained or is not bound
- * (means that it is not running)
- */
- public static synchronized ActivationSystem getSystem()
- throws ActivationException
- {
- if (currSystem == null) {
- try {
- int port;
-
- try {
- java.security.AccessController.beginPrivileged();
- port = Integer.getInteger("java.rmi.activation.port",
- ActivationSystem.SYSTEM_PORT).
- intValue();
-
- } finally {
- java.security.AccessController.endPrivileged();
- }
- currSystem = (ActivationSystem)
- Naming.lookup("//:" + port +
- "/java.rmi.server.ActivationSystem");
- } catch (Exception e) {
- throw new ActivationException("ActivationSystem not running",
- e);
- }
- }
- return currSystem;
- }
-
- /**
- * This protected method is necessary for subclasses to
- * make the <code>activeObject</code> callback to the group's
- * monitor. The call is simply forwarded to the group's
- * <code>ActivationMonitor</code>.
- *
- * @param id the object's identifier
- * @param mobj a marshalled object containing the remote object's stub
- * @exception UnknownObjectException if object is not registered
- * @exception RemoteException if call informing monitor fails
- */
-
- protected void activeObject(ActivationID id, MarshalledObject mobj)
- throws ActivationException, UnknownObjectException, RemoteException
- {
- monitor.activeObject(id, mobj);
- }
-
- /**
- * This protected method is necessary for subclasses to
- * make the <code>inactiveGroup</code> callback to the group's
- * monitor. The call is simply forwarded to the group's
- * <code>ActivationMonitor</code>. Also, the current group
- * for the VM is set to null.
- *
- * @exception UnknownGroupException if group is not registered
- * @exception RemoteException if call informing monitor fails
- */
- protected void inactiveGroup()
- throws UnknownGroupException, RemoteException
- {
- monitor.inactiveGroup(groupID, incarnation);
- destroyGroup();
-
- }
-
- /**
- * Destroys the current group.
- */
- private static synchronized void destroyGroup()
- {
- currGroup = null;
- currGroupID = null;
- // NOTE: don't set currSystem to null since it may be needed
- }
-
- /**
- * Returns the current group for the VM.
- * @exception ActivationException if current group is null (not active)
- */
- static synchronized ActivationGroup currentGroup()
- throws ActivationException
- {
- if (currGroup == null) {
- throw new ActivationException("group is not active");
- }
- return currGroup;
- }
-
- }
-