src/java.rmi/share/classes/java/rmi/activation/ActivationID.java
changeset 47216 71c04702a3d5
parent 45983 4bcee8b28e89
child 51181 01b8120f867a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.rmi/share/classes/java/rmi/activation/ActivationID.java	Tue Sep 12 19:03:39 2017 +0200
@@ -0,0 +1,312 @@
+/*
+ * Copyright (c) 1997, 2017, 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 java.rmi.activation;
+
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Proxy;
+import java.rmi.MarshalledObject;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.rmi.UnmarshalException;
+import java.rmi.server.RemoteObject;
+import java.rmi.server.RemoteObjectInvocationHandler;
+import java.rmi.server.RemoteRef;
+import java.rmi.server.UID;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.Permissions;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.security.ProtectionDomain;
+
+/**
+ * Activation makes use of special identifiers to denote remote
+ * objects that can be activated over time. An activation identifier
+ * (an instance of the class <code>ActivationID</code>) contains several
+ * pieces of information needed for activating an object:
+ * <ul>
+ * <li> a remote reference to the object's activator (a {@link
+ * java.rmi.server.RemoteRef RemoteRef}
+ * instance), and
+ * <li> a unique identifier (a {@link java.rmi.server.UID UID}
+ * instance) for the object. </ul> <p>
+ *
+ * An activation identifier for an object can be obtained by registering
+ * an object with the activation system. Registration is accomplished
+ * in a few ways: <ul>
+ * <li>via the <code>Activatable.register</code> method
+ * <li>via the first <code>Activatable</code> constructor (that takes
+ * three arguments and both registers and exports the object, and
+ * <li>via the first <code>Activatable.exportObject</code> method
+ * that takes the activation descriptor, object and port as arguments;
+ * this method both registers and exports the object. </ul>
+ *
+ * @author      Ann Wollrath
+ * @see         Activatable
+ * @since       1.2
+ */
+public class ActivationID implements Serializable {
+    /**
+     * the object's activator
+     */
+    private transient Activator activator;
+
+    /**
+     * the object's unique id
+     */
+    private transient UID uid = new UID();
+
+    /** indicate compatibility with the Java 2 SDK v1.2 version of class */
+    private static final long serialVersionUID = -4608673054848209235L;
+
+    /** an AccessControlContext with no permissions */
+    private static final AccessControlContext NOPERMS_ACC;
+    static {
+        Permissions perms = new Permissions();
+        ProtectionDomain[] pd = { new ProtectionDomain(null, perms) };
+        NOPERMS_ACC = new AccessControlContext(pd);
+    }
+
+    /**
+     * The constructor for <code>ActivationID</code> takes a single
+     * argument, activator, that specifies a remote reference to the
+     * activator responsible for activating the object associated with
+     * this identifier. An instance of <code>ActivationID</code> is globally
+     * unique.
+     *
+     * @param activator reference to the activator responsible for
+     * activating the object
+     * @throws UnsupportedOperationException if and only if activation is
+     *         not supported by this implementation
+     * @since 1.2
+     */
+    public ActivationID(Activator activator) {
+        this.activator = activator;
+    }
+
+    /**
+     * Activate the object for this id.
+     *
+     * @param force if true, forces the activator to contact the group
+     * when activating the object (instead of returning a cached reference);
+     * if false, returning a cached value is acceptable.
+     * @return the reference to the active remote object
+     * @exception ActivationException if activation fails
+     * @exception UnknownObjectException if the object is unknown
+     * @exception RemoteException if remote call fails
+     * @since 1.2
+     */
+    public Remote activate(boolean force)
+        throws ActivationException, UnknownObjectException, RemoteException
+    {
+        try {
+            MarshalledObject<? extends Remote> mobj =
+                activator.activate(this, force);
+            return AccessController.doPrivileged(
+                new PrivilegedExceptionAction<Remote>() {
+                    public Remote run() throws IOException, ClassNotFoundException {
+                        return mobj.get();
+                    }
+                }, NOPERMS_ACC);
+        } catch (PrivilegedActionException pae) {
+            Exception ex = pae.getException();
+            if (ex instanceof RemoteException) {
+                throw (RemoteException) ex;
+            } else {
+                throw new UnmarshalException("activation failed", ex);
+            }
+        }
+
+    }
+
+    /**
+     * Returns a hashcode for the activation id.  Two identifiers that
+     * refer to the same remote object will have the same hash code.
+     *
+     * @see java.util.Hashtable
+     * @since 1.2
+     */
+    public int hashCode() {
+        return uid.hashCode();
+    }
+
+    /**
+     * Compares two activation ids for content equality.
+     * Returns true if both of the following conditions are true:
+     * 1) the unique identifiers equivalent (by content), and
+     * 2) the activator specified in each identifier
+     *    refers to the same remote object.
+     *
+     * @param   obj     the Object to compare with
+     * @return  true if these Objects are equal; false otherwise.
+     * @see             java.util.Hashtable
+     * @since 1.2
+     */
+    public boolean equals(Object obj) {
+        if (obj instanceof ActivationID) {
+            ActivationID id = (ActivationID) obj;
+            return (uid.equals(id.uid) && activator.equals(id.activator));
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * <code>writeObject</code> for custom serialization.
+     *
+     * <p>This method writes this object's serialized form for
+     * this class as follows:
+     *
+     * <p>The <code>writeObject</code> method is invoked on
+     * <code>out</code> passing this object's unique identifier
+     * (a {@link java.rmi.server.UID UID} instance) as the argument.
+     *
+     * <p>Next, the {@link
+     * java.rmi.server.RemoteRef#getRefClass(java.io.ObjectOutput)
+     * getRefClass} method is invoked on the activator's
+     * <code>RemoteRef</code> instance to obtain its external ref
+     * type name.  Next, the <code>writeUTF</code> method is
+     * invoked on <code>out</code> with the value returned by
+     * <code>getRefClass</code>, and then the
+     * <code>writeExternal</code> method is invoked on the
+     * <code>RemoteRef</code> instance passing <code>out</code>
+     * as the argument.
+     *
+     * @serialData The serialized data for this class comprises a
+     * <code>java.rmi.server.UID</code> (written with
+     * <code>ObjectOutput.writeObject</code>) followed by the
+     * external ref type name of the activator's
+     * <code>RemoteRef</code> instance (a string written with
+     * <code>ObjectOutput.writeUTF</code>), followed by the
+     * external form of the <code>RemoteRef</code> instance as
+     * written by its <code>writeExternal</code> method.
+     *
+     * <p>The external ref type name of the
+     * <code>RemoteRef</Code> instance is
+     * determined using the definitions of external ref type
+     * names specified in the {@link java.rmi.server.RemoteObject
+     * RemoteObject} <code>writeObject</code> method
+     * <b>serialData</b> specification.  Similarly, the data
+     * written by the <code>writeExternal</code> method and read
+     * by the <code>readExternal</code> method of
+     * <code>RemoteRef</code> implementation classes
+     * corresponding to each of the defined external ref type
+     * names is specified in the {@link
+     * java.rmi.server.RemoteObject RemoteObject}
+     * <code>writeObject</code> method <b>serialData</b>
+     * specification.
+     **/
+    private void writeObject(ObjectOutputStream out)
+        throws IOException, ClassNotFoundException
+    {
+        out.writeObject(uid);
+
+        RemoteRef ref;
+        if (activator instanceof RemoteObject) {
+            ref = ((RemoteObject) activator).getRef();
+        } else if (Proxy.isProxyClass(activator.getClass())) {
+            InvocationHandler handler = Proxy.getInvocationHandler(activator);
+            if (!(handler instanceof RemoteObjectInvocationHandler)) {
+                throw new InvalidObjectException(
+                    "unexpected invocation handler");
+            }
+            ref = ((RemoteObjectInvocationHandler) handler).getRef();
+
+        } else {
+            throw new InvalidObjectException("unexpected activator type");
+        }
+        out.writeUTF(ref.getRefClass(out));
+        ref.writeExternal(out);
+    }
+
+    /**
+     * <code>readObject</code> for custom serialization.
+     *
+     * <p>This method reads this object's serialized form for this
+     * class as follows:
+     *
+     * <p>The <code>readObject</code> method is invoked on
+     * <code>in</code> to read this object's unique identifier
+     * (a {@link java.rmi.server.UID UID} instance).
+     *
+     * <p>Next, the <code>readUTF</code> method is invoked on
+     * <code>in</code> to read the external ref type name of the
+     * <code>RemoteRef</code> instance for this object's
+     * activator.  Next, the <code>RemoteRef</code>
+     * instance is created of an implementation-specific class
+     * corresponding to the external ref type name (returned by
+     * <code>readUTF</code>), and the <code>readExternal</code>
+     * method is invoked on that <code>RemoteRef</code> instance
+     * to read the external form corresponding to the external
+     * ref type name.
+     *
+     * <p>Note: If the external ref type name is
+     * <code>"UnicastRef"</code>, <code>"UnicastServerRef"</code>,
+     * <code>"UnicastRef2"</code>, <code>"UnicastServerRef2"</code>,
+     * or <code>"ActivatableRef"</code>, a corresponding
+     * implementation-specific class must be found, and its
+     * <code>readExternal</code> method must read the serial data
+     * for that external ref type name as specified to be written
+     * in the <b>serialData</b> documentation for this class.
+     * If the external ref type name is any other string (of non-zero
+     * length), a <code>ClassNotFoundException</code> will be thrown,
+     * unless the implementation provides an implementation-specific
+     * class corresponding to that external ref type name, in which
+     * case the <code>RemoteRef</code> will be an instance of
+     * that implementation-specific class.
+     */
+    private void readObject(ObjectInputStream in)
+        throws IOException, ClassNotFoundException
+    {
+        uid = (UID)in.readObject();
+
+        try {
+            Class<? extends RemoteRef> refClass =
+                Class.forName(RemoteRef.packagePrefix + "." + in.readUTF())
+                .asSubclass(RemoteRef.class);
+            @SuppressWarnings("deprecation")
+            RemoteRef ref = refClass.newInstance();
+            ref.readExternal(in);
+            activator = (Activator)
+                Proxy.newProxyInstance(Activator.class.getClassLoader(),
+                                       new Class<?>[] { Activator.class },
+                                       new RemoteObjectInvocationHandler(ref));
+        } catch (InstantiationException e) {
+            throw (IOException)
+                new InvalidObjectException(
+                    "Unable to create remote reference").initCause(e);
+        } catch (IllegalAccessException e) {
+            throw (IOException)
+                new InvalidObjectException(
+                    "Unable to create remote reference").initCause(e);
+        }
+    }
+}