home *** CD-ROM | disk | FTP | other *** search
/ Java 1.2 How-To / JavaHowTo.iso / 3rdParty / jbuilder / unsupported / JDK1.2beta3 / SOURCE / SRC.ZIP / java / rmi / activation / ActivationGroup.java < prev    next >
Encoding:
Java Source  |  1998-03-20  |  18.7 KB  |  529 lines

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