2502 lines · 85.9 KB · Java
RawDownload
/* * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.rmi.server; import java.io.ByteArrayOutputStream;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.ObjectInputStream;import java.io.OutputStream;import java.io.PrintStream;import java.io.PrintWriter;import java.io.Serializable;import java.lang.Process;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.net.InetAddress;import java.net.ServerSocket;import java.net.Socket;import java.net.SocketAddress;import java.net.SocketException;import java.nio.channels.Channel;import java.nio.channels.ServerSocketChannel;import java.rmi.AccessException;import java.rmi.AlreadyBoundException;import java.rmi.ConnectException;import java.rmi.ConnectIOException;import java.rmi.MarshalledObject;import java.rmi.NoSuchObjectException;import java.rmi.NotBoundException;import java.rmi.Remote;import java.rmi.RemoteException;import java.rmi.activation.ActivationDesc;import java.rmi.activation.ActivationException;import java.rmi.activation.ActivationGroupDesc;import java.rmi.activation.ActivationGroup;import java.rmi.activation.ActivationGroupID;import java.rmi.activation.ActivationID;import java.rmi.activation.ActivationInstantiator;import java.rmi.activation.ActivationMonitor;import java.rmi.activation.ActivationSystem;import java.rmi.activation.Activator;import java.rmi.activation.UnknownGroupException;import java.rmi.activation.UnknownObjectException;import java.rmi.registry.Registry;import java.rmi.server.ObjID;import java.rmi.server.RMIClassLoader;import java.rmi.server.RMIClientSocketFactory;import java.rmi.server.RMIServerSocketFactory;import java.rmi.server.RemoteObject;import java.rmi.server.RemoteServer;import java.rmi.server.UnicastRemoteObject;import java.security.AccessControlException;import java.security.AccessController;import java.security.AllPermission;import java.security.CodeSource;import java.security.Permission;import java.security.PermissionCollection;import java.security.Permissions;import java.security.Policy;import java.security.PrivilegedAction;import java.security.PrivilegedExceptionAction;import java.security.cert.Certificate;import java.text.MessageFormat;import java.util.ArrayList;import java.util.Arrays;import java.util.Date;import java.util.Enumeration;import java.util.HashMap;import java.util.HashSet;import java.util.Iterator;import java.util.List;import java.util.Map;import java.util.MissingResourceException;import java.util.Properties;import java.util.ResourceBundle;import java.util.Set;import java.util.concurrent.ConcurrentHashMap;import sun.rmi.log.LogHandler;import sun.rmi.log.ReliableLog;import sun.rmi.registry.RegistryImpl;import sun.rmi.runtime.NewThreadAction;import sun.rmi.server.UnicastServerRef;import sun.rmi.transport.LiveRef;import sun.security.action.GetBooleanAction;import sun.security.action.GetIntegerAction;import sun.security.action.GetPropertyAction;import sun.security.provider.PolicyFile;import com.sun.rmi.rmid.ExecPermission;import com.sun.rmi.rmid.ExecOptionPermission; /** * The Activator facilitates remote object activation. A "faulting" * remote reference calls the activator's <code>activate</code> method * to obtain a "live" reference to a activatable remote object. Upon * receiving a request for activation, the activator looks up the * activation descriptor for the activation identifier, id, determines * the group in which the object should be activated and invokes the * activate method on the object's activation group (described by the * remote interface <code>ActivationInstantiator</code>). The * activator initiates the execution of activation groups as * necessary. For example, if an activation group for a specific group * identifier is not already executing, the activator will spawn a * child process for the activation group. <p> * * The activator is responsible for monitoring and detecting when * activation groups fail so that it can remove stale remote references * from its internal tables. <p> * * @author      Ann Wollrath * @since       1.2 */public class Activation implements Serializable {     /** indicate compatibility with JDK 1.2 version of class */    private static final long serialVersionUID = 2921265612698155191L;     private static final byte MAJOR_VERSION = 1;    private static final byte MINOR_VERSION = 0;     /** exec policy object */    private static Object execPolicy;    private static Method execPolicyMethod;    private static boolean debugExec;     /** maps activation id to its respective group id */    private Map<ActivationID,ActivationGroupID> idTable =        new ConcurrentHashMap<>();    /** maps group id to its GroupEntry groups */    private Map<ActivationGroupID,GroupEntry> groupTable =        new ConcurrentHashMap<>();     private byte majorVersion = MAJOR_VERSION;    private byte minorVersion = MINOR_VERSION;     /** number of simultaneous group exec's */    private transient int groupSemaphore;    /** counter for numbering groups */    private transient int groupCounter;    /** reliable log to hold descriptor table */    private transient ReliableLog log;    /** number of updates since last snapshot */    private transient int numUpdates;     /** the java command */    // accessed by GroupEntry    private transient String[] command;    /** timeout on wait for child process to be created or destroyed */    private static final long groupTimeout =        getInt("sun.rmi.activation.groupTimeout", 60000);    /** take snapshot after this many updates */    private static final int snapshotInterval =        getInt("sun.rmi.activation.snapshotInterval", 200);    /** timeout on wait for child process to be created */    private static final long execTimeout =        getInt("sun.rmi.activation.execTimeout", 30000);     private static final Object initLock = new Object();    private static boolean initDone = false;     // this should be a *private* method since it is privileged    private static int getInt(String name, int def) {        return AccessController.doPrivileged(new GetIntegerAction(name, def));    }     private transient Activator activator;    private transient Activator activatorStub;    private transient ActivationSystem system;    private transient ActivationSystem systemStub;    private transient ActivationMonitor monitor;    private transient Registry registry;    private transient volatile boolean shuttingDown = false;    private transient volatile Object startupLock;    private transient Thread shutdownHook;     private static ResourceBundle resources = null;     /**     * Create an uninitialized instance of Activation that can be     * populated with log data.  This is only called when the initial     * snapshot is taken during the first incarnation of rmid.     */    private Activation() {}     /**     * Recover activation state from the reliable log and initialize     * activation services.     */    private static void startActivation(int port,                                        RMIServerSocketFactory ssf,                                        String logName,                                        String[] childArgs)        throws Exception    {        ReliableLog log = new ReliableLog(logName, new ActLogHandler());        Activation state = (Activation) log.recover();        state.init(port, ssf, log, childArgs);    }     /**     * Initialize the Activation instantiation; start activation     * services.     */    private void init(int port,                      RMIServerSocketFactory ssf,                      ReliableLog log,                      String[] childArgs)        throws Exception    {        // initialize        this.log = log;        numUpdates = 0;        shutdownHook =  new ShutdownHook();        groupSemaphore = getInt("sun.rmi.activation.groupThrottle", 3);        groupCounter = 0;        Runtime.getRuntime().addShutdownHook(shutdownHook);         // Use array size of 0, since the value from calling size()        // may be out of date by the time toArray() is called.        ActivationGroupID[] gids =            groupTable.keySet().toArray(new ActivationGroupID[0]);         synchronized (startupLock = new Object()) {            // all the remote methods briefly synchronize on startupLock            // (via checkShutdown) to make sure they don't happen in the            // middle of this block.  This block must not cause any such            // incoming remote calls to happen, or deadlock would result!            activator = new ActivatorImpl(port, ssf);            activatorStub = (Activator) RemoteObject.toStub(activator);            system = new ActivationSystemImpl(port, ssf);            systemStub = (ActivationSystem) RemoteObject.toStub(system);            monitor = new ActivationMonitorImpl(port, ssf);            initCommand(childArgs);            registry = new SystemRegistryImpl(port, null, ssf, systemStub);             if (ssf != null) {                synchronized (initLock) {                    initDone = true;                    initLock.notifyAll();                }            }        }        startupLock = null;         // restart services        for (int i = gids.length; --i >= 0; ) {            try {                getGroupEntry(gids[i]).restartServices();            } catch (UnknownGroupException e) {                System.err.println(                    getTextResource("rmid.restart.group.warning"));                e.printStackTrace();            }        }    }     /**     * Previous versions used HashMap instead of ConcurrentHashMap.     * Replace any HashMaps found during deserialization with     * ConcurrentHashMaps.     */    private void readObject(ObjectInputStream ois)        throws IOException, ClassNotFoundException    {        ois.defaultReadObject();        if (! (groupTable instanceof ConcurrentHashMap)) {            groupTable = new ConcurrentHashMap<>(groupTable);        }        if (! (idTable instanceof ConcurrentHashMap)) {            idTable = new ConcurrentHashMap<>(idTable);        }    }     private static class SystemRegistryImpl extends RegistryImpl {         private static final String NAME = ActivationSystem.class.getName();        private final ActivationSystem systemStub;         SystemRegistryImpl(int port,                           RMIClientSocketFactory csf,                           RMIServerSocketFactory ssf,                           ActivationSystem systemStub)            throws RemoteException        {            super(port, csf, ssf);            this.systemStub = systemStub;        }         /**         * Returns the activation system stub if the specified name         * matches the activation system's class name, otherwise         * returns the result of invoking super.lookup with the specified         * name.         */        public Remote lookup(String name)            throws RemoteException, NotBoundException        {            if (name.equals(NAME)) {                return systemStub;            } else {                return super.lookup(name);            }        }         public String[] list() throws RemoteException {            String[] list1 = super.list();            int length = list1.length;            String[] list2 = new String[length + 1];            if (length > 0) {                System.arraycopy(list1, 0, list2, 0, length);            }            list2[length] = NAME;            return list2;        }         public void bind(String name, Remote obj)            throws RemoteException, AlreadyBoundException, AccessException        {            if (name.equals(NAME)) {                throw new AccessException(                    "binding ActivationSystem is disallowed");            } else {                super.bind(name, obj);            }        }         public void unbind(String name)            throws RemoteException, NotBoundException, AccessException        {            if (name.equals(NAME)) {                throw new AccessException(                    "unbinding ActivationSystem is disallowed");            } else {                super.unbind(name);            }        }          public void rebind(String name, Remote obj)            throws RemoteException, AccessException        {            if (name.equals(NAME)) {                throw new AccessException(                    "binding ActivationSystem is disallowed");            } else {                super.rebind(name, obj);            }        }    }      class ActivatorImpl extends RemoteServer implements Activator {        // Because ActivatorImpl has a fixed ObjID, it can be        // called by clients holding stale remote references.  Each of        // its remote methods, then, must check startupLock (calling        // checkShutdown() is easiest).         private static final long serialVersionUID = -3654244726254566136L;         /**         * Construct a new Activator on a specified port.         */        ActivatorImpl(int port, RMIServerSocketFactory ssf)            throws RemoteException        {            /* Server ref must be created and assigned before remote object             * 'this' can be exported.             */            LiveRef lref =                new LiveRef(new ObjID(ObjID.ACTIVATOR_ID), port, null, ssf);            UnicastServerRef uref = new UnicastServerRef(lref);            ref = uref;            uref.exportObject(this, null, false);        }         public MarshalledObject<? extends Remote> activate(ActivationID id,                                                           boolean force)            throws ActivationException, UnknownObjectException, RemoteException        {            checkShutdown();            return getGroupEntry(id).activate(id, force);        }    }     class ActivationMonitorImpl extends UnicastRemoteObject        implements ActivationMonitor    {        private static final long serialVersionUID = -6214940464757948867L;         ActivationMonitorImpl(int port, RMIServerSocketFactory ssf)            throws RemoteException        {            super(port, null, ssf);        }         public void inactiveObject(ActivationID id)            throws UnknownObjectException, RemoteException        {            try {                checkShutdown();            } catch (ActivationException e) {                return;            }            RegistryImpl.checkAccess("Activator.inactiveObject");            getGroupEntry(id).inactiveObject(id);        }         public void activeObject(ActivationID id,                                 MarshalledObject<? extends Remote> mobj)            throws UnknownObjectException, RemoteException        {            try {                checkShutdown();            } catch (ActivationException e) {                return;            }            RegistryImpl.checkAccess("ActivationSystem.activeObject");            getGroupEntry(id).activeObject(id, mobj);        }         public void inactiveGroup(ActivationGroupID id,                                  long incarnation)            throws UnknownGroupException, RemoteException        {            try {                checkShutdown();            } catch (ActivationException e) {                return;            }            RegistryImpl.checkAccess("ActivationMonitor.inactiveGroup");            getGroupEntry(id).inactiveGroup(incarnation, false);        }    }      class ActivationSystemImpl        extends RemoteServer        implements ActivationSystem    {        private static final long serialVersionUID = 9100152600327688967L;         // Because ActivationSystemImpl has a fixed ObjID, it can be        // called by clients holding stale remote references.  Each of        // its remote methods, then, must check startupLock (calling        // checkShutdown() is easiest).        ActivationSystemImpl(int port, RMIServerSocketFactory ssf)            throws RemoteException        {            /* Server ref must be created and assigned before remote object             * 'this' can be exported.             */            LiveRef lref = new LiveRef(new ObjID(4), port, null, ssf);            UnicastServerRef uref = new UnicastServerRef(lref);            ref = uref;            uref.exportObject(this, null);        }         public ActivationID registerObject(ActivationDesc desc)            throws ActivationException, UnknownGroupException, RemoteException        {            checkShutdown();            RegistryImpl.checkAccess("ActivationSystem.registerObject");             ActivationGroupID groupID = desc.getGroupID();            ActivationID id = new ActivationID(activatorStub);            getGroupEntry(groupID).registerObject(id, desc, true);            return id;        }         public void unregisterObject(ActivationID id)            throws ActivationException, UnknownObjectException, RemoteException        {            checkShutdown();            RegistryImpl.checkAccess("ActivationSystem.unregisterObject");            getGroupEntry(id).unregisterObject(id, true);        }

Lines 1–500 of 2502.