Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/java/rmi/activation/ActivationGroup.java
38918 views
/*1* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package java.rmi.activation;2627import java.lang.reflect.Constructor;28import java.lang.reflect.InvocationTargetException;29import java.rmi.MarshalledObject;30import java.rmi.Naming;31import java.rmi.Remote;32import java.rmi.RemoteException;33import java.rmi.activation.UnknownGroupException;34import java.rmi.activation.UnknownObjectException;35import java.rmi.server.RMIClassLoader;36import java.rmi.server.UnicastRemoteObject;37import java.security.AccessController;38import sun.security.action.GetIntegerAction;3940/**41* An <code>ActivationGroup</code> is responsible for creating new42* instances of "activatable" objects in its group, informing its43* <code>ActivationMonitor</code> when either: its object's become44* active or inactive, or the group as a whole becomes inactive. <p>45*46* An <code>ActivationGroup</code> is <i>initially</i> created in one47* of several ways: <ul>48* <li>as a side-effect of creating an <code>ActivationDesc</code>49* without an explicit <code>ActivationGroupID</code> for the50* first activatable object in the group, or51* <li>via the <code>ActivationGroup.createGroup</code> method52* <li>as a side-effect of activating the first object in a group53* whose <code>ActivationGroupDesc</code> was only registered.</ul><p>54*55* Only the activator can <i>recreate</i> an56* <code>ActivationGroup</code>. The activator spawns, as needed, a57* separate VM (as a child process, for example) for each registered58* activation group and directs activation requests to the appropriate59* group. It is implementation specific how VMs are spawned. An60* activation group is created via the61* <code>ActivationGroup.createGroup</code> static method. The62* <code>createGroup</code> method has two requirements on the group63* to be created: 1) the group must be a concrete subclass of64* <code>ActivationGroup</code>, and 2) the group must have a65* constructor that takes two arguments:66*67* <ul>68* <li> the group's <code>ActivationGroupID</code>, and69* <li> the group's initialization data (in a70* <code>java.rmi.MarshalledObject</code>)</ul><p>71*72* When created, the default implementation of73* <code>ActivationGroup</code> will override the system properties74* with the properties requested when its75* <code>ActivationGroupDesc</code> was created, and will set a76* {@link SecurityManager} as the default system77* security manager. If your application requires specific properties78* to be set when objects are activated in the group, the application79* should create a special <code>Properties</code> object containing80* these properties, then create an <code>ActivationGroupDesc</code>81* with the <code>Properties</code> object, and use82* <code>ActivationGroup.createGroup</code> before creating any83* <code>ActivationDesc</code>s (before the default84* <code>ActivationGroupDesc</code> is created). If your application85* requires the use of a security manager other than86* {@link SecurityManager}, in the87* ActivativationGroupDescriptor properties list you can set88* <code>java.security.manager</code> property to the name of the security89* manager you would like to install.90*91* @author Ann Wollrath92* @see ActivationInstantiator93* @see ActivationGroupDesc94* @see ActivationGroupID95* @since 1.296*/97public abstract class ActivationGroup98extends UnicastRemoteObject99implements ActivationInstantiator100{101/**102* @serial the group's identifier103*/104private ActivationGroupID groupID;105106/**107* @serial the group's monitor108*/109private ActivationMonitor monitor;110111/**112* @serial the group's incarnation number113*/114private long incarnation;115116/** the current activation group for this VM */117private static ActivationGroup currGroup;118/** the current group's identifier */119private static ActivationGroupID currGroupID;120/** the current group's activation system */121private static ActivationSystem currSystem;122/** used to control a group being created only once */123private static boolean canCreate = true;124125/** indicate compatibility with the Java 2 SDK v1.2 version of class */126private static final long serialVersionUID = -7696947875314805420L;127128/**129* Constructs an activation group with the given activation group130* identifier. The group is exported as a131* <code>java.rmi.server.UnicastRemoteObject</code>.132*133* @param groupID the group's identifier134* @throws RemoteException if this group could not be exported135* @throws UnsupportedOperationException if and only if activation is136* not supported by this implementation137* @since 1.2138*/139protected ActivationGroup(ActivationGroupID groupID)140throws RemoteException141{142// call super constructor to export the object143super();144this.groupID = groupID;145}146147/**148* The group's <code>inactiveObject</code> method is called149* indirectly via a call to the <code>Activatable.inactive</code>150* method. A remote object implementation must call151* <code>Activatable</code>'s <code>inactive</code> method when152* that object deactivates (the object deems that it is no longer153* active). If the object does not call154* <code>Activatable.inactive</code> when it deactivates, the155* object will never be garbage collected since the group keeps156* strong references to the objects it creates.157*158* <p>The group's <code>inactiveObject</code> method unexports the159* remote object from the RMI runtime so that the object can no160* longer receive incoming RMI calls. An object will only be unexported161* if the object has no pending or executing calls.162* The subclass of <code>ActivationGroup</code> must override this163* method and unexport the object.164*165* <p>After removing the object from the RMI runtime, the group166* must inform its <code>ActivationMonitor</code> (via the monitor's167* <code>inactiveObject</code> method) that the remote object is168* not currently active so that the remote object will be169* re-activated by the activator upon a subsequent activation170* request.171*172* <p>This method simply informs the group's monitor that the object173* is inactive. It is up to the concrete subclass of ActivationGroup174* to fulfill the additional requirement of unexporting the object. <p>175*176* @param id the object's activation identifier177* @return true if the object was successfully deactivated; otherwise178* returns false.179* @exception UnknownObjectException if object is unknown (may already180* be inactive)181* @exception RemoteException if call informing monitor fails182* @exception ActivationException if group is inactive183* @since 1.2184*/185public boolean inactiveObject(ActivationID id)186throws ActivationException, UnknownObjectException, RemoteException187{188getMonitor().inactiveObject(id);189return true;190}191192/**193* The group's <code>activeObject</code> method is called when an194* object is exported (either by <code>Activatable</code> object195* construction or an explicit call to196* <code>Activatable.exportObject</code>. The group must inform its197* <code>ActivationMonitor</code> that the object is active (via198* the monitor's <code>activeObject</code> method) if the group199* hasn't already done so.200*201* @param id the object's identifier202* @param obj the remote object implementation203* @exception UnknownObjectException if object is not registered204* @exception RemoteException if call informing monitor fails205* @exception ActivationException if group is inactive206* @since 1.2207*/208public abstract void activeObject(ActivationID id, Remote obj)209throws ActivationException, UnknownObjectException, RemoteException;210211/**212* Create and set the activation group for the current VM. The213* activation group can only be set if it is not currently set.214* An activation group is set using the <code>createGroup</code>215* method when the <code>Activator</code> initiates the216* re-creation of an activation group in order to carry out217* incoming <code>activate</code> requests. A group must first be218* registered with the <code>ActivationSystem</code> before it can219* be created via this method.220*221* <p>The group class specified by the222* <code>ActivationGroupDesc</code> must be a concrete subclass of223* <code>ActivationGroup</code> and have a public constructor that224* takes two arguments: the <code>ActivationGroupID</code> for the225* group and the <code>MarshalledObject</code> containing the226* group's initialization data (obtained from the227* <code>ActivationGroupDesc</code>.228*229* <p>If the group class name specified in the230* <code>ActivationGroupDesc</code> is <code>null</code>, then231* this method will behave as if the group descriptor contained232* the name of the default activation group implementation class.233*234* <p>Note that if your application creates its own custom235* activation group, a security manager must be set for that236* group. Otherwise objects cannot be activated in the group.237* {@link SecurityManager} is set by default.238*239* <p>If a security manager is already set in the group VM, this240* method first calls the security manager's241* <code>checkSetFactory</code> method. This could result in a242* <code>SecurityException</code>. If your application needs to243* set a different security manager, you must ensure that the244* policy file specified by the group's245* <code>ActivationGroupDesc</code> grants the group the necessary246* permissions to set a new security manager. (Note: This will be247* necessary if your group downloads and sets a security manager).248*249* <p>After the group is created, the250* <code>ActivationSystem</code> is informed that the group is251* active by calling the <code>activeGroup</code> method which252* returns the <code>ActivationMonitor</code> for the group. The253* application need not call <code>activeGroup</code>254* independently since it is taken care of by this method.255*256* <p>Once a group is created, subsequent calls to the257* <code>currentGroupID</code> method will return the identifier258* for this group until the group becomes inactive.259*260* @param id the activation group's identifier261* @param desc the activation group's descriptor262* @param incarnation the group's incarnation number (zero on group's263* initial creation)264* @return the activation group for the VM265* @exception ActivationException if group already exists or if error266* occurs during group creation267* @exception SecurityException if permission to create group is denied.268* (Note: The default implementation of the security manager269* <code>checkSetFactory</code>270* method requires the RuntimePermission "setFactory")271* @exception UnsupportedOperationException if and only if activation is272* not supported by this implementation273* @see SecurityManager#checkSetFactory274* @since 1.2275*/276public static synchronized277ActivationGroup createGroup(ActivationGroupID id,278final ActivationGroupDesc desc,279long incarnation)280throws ActivationException281{282SecurityManager security = System.getSecurityManager();283if (security != null)284security.checkSetFactory();285286if (currGroup != null)287throw new ActivationException("group already exists");288289if (canCreate == false)290throw new ActivationException("group deactivated and " +291"cannot be recreated");292293try {294// load group's class295String groupClassName = desc.getClassName();296Class<? extends ActivationGroup> cl;297Class<? extends ActivationGroup> defaultGroupClass =298sun.rmi.server.ActivationGroupImpl.class;299if (groupClassName == null || // see 4252236300groupClassName.equals(defaultGroupClass.getName()))301{302cl = defaultGroupClass;303} else {304Class<?> cl0;305try {306cl0 = RMIClassLoader.loadClass(desc.getLocation(),307groupClassName);308} catch (Exception ex) {309throw new ActivationException(310"Could not load group implementation class", ex);311}312if (ActivationGroup.class.isAssignableFrom(cl0)) {313cl = cl0.asSubclass(ActivationGroup.class);314} else {315throw new ActivationException("group not correct class: " +316cl0.getName());317}318}319320// create group321Constructor<? extends ActivationGroup> constructor =322cl.getConstructor(ActivationGroupID.class,323MarshalledObject.class);324ActivationGroup newGroup =325constructor.newInstance(id, desc.getData());326currSystem = id.getSystem();327newGroup.incarnation = incarnation;328newGroup.monitor =329currSystem.activeGroup(id, newGroup, incarnation);330currGroup = newGroup;331currGroupID = id;332canCreate = false;333} catch (InvocationTargetException e) {334e.getTargetException().printStackTrace();335throw new ActivationException("exception in group constructor",336e.getTargetException());337338} catch (ActivationException e) {339throw e;340341} catch (Exception e) {342throw new ActivationException("exception creating group", e);343}344345return currGroup;346}347348/**349* Returns the current activation group's identifier. Returns null350* if no group is currently active for this VM.351* @exception UnsupportedOperationException if and only if activation is352* not supported by this implementation353* @return the activation group's identifier354* @since 1.2355*/356public static synchronized ActivationGroupID currentGroupID() {357return currGroupID;358}359360/**361* Returns the activation group identifier for the VM. If an362* activation group does not exist for this VM, a default363* activation group is created. A group can be created only once,364* so if a group has already become active and deactivated.365*366* @return the activation group identifier367* @exception ActivationException if error occurs during group368* creation, if security manager is not set, or if the group369* has already been created and deactivated.370*/371static synchronized ActivationGroupID internalCurrentGroupID()372throws ActivationException373{374if (currGroupID == null)375throw new ActivationException("nonexistent group");376377return currGroupID;378}379380/**381* Set the activation system for the VM. The activation system can382* only be set it if no group is currently active. If the activation383* system is not set via this call, then the <code>getSystem</code>384* method attempts to obtain a reference to the385* <code>ActivationSystem</code> by looking up the name386* "java.rmi.activation.ActivationSystem" in the Activator's387* registry. By default, the port number used to look up the388* activation system is defined by389* <code>ActivationSystem.SYSTEM_PORT</code>. This port can be overridden390* by setting the property <code>java.rmi.activation.port</code>.391*392* <p>If there is a security manager, this method first393* calls the security manager's <code>checkSetFactory</code> method.394* This could result in a SecurityException.395*396* @param system remote reference to the <code>ActivationSystem</code>397* @exception ActivationException if activation system is already set398* @exception SecurityException if permission to set the activation system is denied.399* (Note: The default implementation of the security manager400* <code>checkSetFactory</code>401* method requires the RuntimePermission "setFactory")402* @exception UnsupportedOperationException if and only if activation is403* not supported by this implementation404* @see #getSystem405* @see SecurityManager#checkSetFactory406* @since 1.2407*/408public static synchronized void setSystem(ActivationSystem system)409throws ActivationException410{411SecurityManager security = System.getSecurityManager();412if (security != null)413security.checkSetFactory();414415if (currSystem != null)416throw new ActivationException("activation system already set");417418currSystem = system;419}420421/**422* Returns the activation system for the VM. The activation system423* may be set by the <code>setSystem</code> method. If the424* activation system is not set via the <code>setSystem</code>425* method, then the <code>getSystem</code> method attempts to426* obtain a reference to the <code>ActivationSystem</code> by427* looking up the name "java.rmi.activation.ActivationSystem" in428* the Activator's registry. By default, the port number used to429* look up the activation system is defined by430* <code>ActivationSystem.SYSTEM_PORT</code>. This port can be431* overridden by setting the property432* <code>java.rmi.activation.port</code>.433*434* @return the activation system for the VM/group435* @exception ActivationException if activation system cannot be436* obtained or is not bound437* (means that it is not running)438* @exception UnsupportedOperationException if and only if activation is439* not supported by this implementation440* @see #setSystem441* @since 1.2442*/443public static synchronized ActivationSystem getSystem()444throws ActivationException445{446if (currSystem == null) {447try {448int port = AccessController.doPrivileged(449new GetIntegerAction("java.rmi.activation.port",450ActivationSystem.SYSTEM_PORT));451currSystem = (ActivationSystem)452Naming.lookup("//:" + port +453"/java.rmi.activation.ActivationSystem");454} catch (Exception e) {455throw new ActivationException(456"unable to obtain ActivationSystem", e);457}458}459return currSystem;460}461462/**463* This protected method is necessary for subclasses to464* make the <code>activeObject</code> callback to the group's465* monitor. The call is simply forwarded to the group's466* <code>ActivationMonitor</code>.467*468* @param id the object's identifier469* @param mobj a marshalled object containing the remote object's stub470* @exception UnknownObjectException if object is not registered471* @exception RemoteException if call informing monitor fails472* @exception ActivationException if an activation error occurs473* @since 1.2474*/475protected void activeObject(ActivationID id,476MarshalledObject<? extends Remote> mobj)477throws ActivationException, UnknownObjectException, RemoteException478{479getMonitor().activeObject(id, mobj);480}481482/**483* This protected method is necessary for subclasses to484* make the <code>inactiveGroup</code> callback to the group's485* monitor. The call is simply forwarded to the group's486* <code>ActivationMonitor</code>. Also, the current group487* for the VM is set to null.488*489* @exception UnknownGroupException if group is not registered490* @exception RemoteException if call informing monitor fails491* @since 1.2492*/493protected void inactiveGroup()494throws UnknownGroupException, RemoteException495{496try {497getMonitor().inactiveGroup(groupID, incarnation);498} finally {499destroyGroup();500}501}502503/**504* Returns the monitor for the activation group.505*/506private ActivationMonitor getMonitor() throws RemoteException {507synchronized (ActivationGroup.class) {508if (monitor != null) {509return monitor;510}511}512throw new RemoteException("monitor not received");513}514515/**516* Destroys the current group.517*/518private static synchronized void destroyGroup() {519currGroup = null;520currGroupID = null;521// NOTE: don't set currSystem to null since it may be needed522}523524/**525* Returns the current group for the VM.526* @exception ActivationException if current group is null (not active)527*/528static synchronized ActivationGroup currentGroup()529throws ActivationException530{531if (currGroup == null) {532throw new ActivationException("group is not active");533}534return currGroup;535}536537}538539540