src/java.rmi/share/classes/java/rmi/activation/ActivationID.java
changeset 47216 71c04702a3d5
parent 45983 4bcee8b28e89
child 51181 01b8120f867a
equal deleted inserted replaced
47215:4ebc2e2fb97c 47216:71c04702a3d5
       
     1 /*
       
     2  * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 package java.rmi.activation;
       
    27 
       
    28 import java.io.IOException;
       
    29 import java.io.InvalidObjectException;
       
    30 import java.io.ObjectInputStream;
       
    31 import java.io.ObjectOutputStream;
       
    32 import java.io.Serializable;
       
    33 import java.lang.reflect.InvocationHandler;
       
    34 import java.lang.reflect.Proxy;
       
    35 import java.rmi.MarshalledObject;
       
    36 import java.rmi.Remote;
       
    37 import java.rmi.RemoteException;
       
    38 import java.rmi.UnmarshalException;
       
    39 import java.rmi.server.RemoteObject;
       
    40 import java.rmi.server.RemoteObjectInvocationHandler;
       
    41 import java.rmi.server.RemoteRef;
       
    42 import java.rmi.server.UID;
       
    43 import java.security.AccessControlContext;
       
    44 import java.security.AccessController;
       
    45 import java.security.Permissions;
       
    46 import java.security.PrivilegedActionException;
       
    47 import java.security.PrivilegedExceptionAction;
       
    48 import java.security.ProtectionDomain;
       
    49 
       
    50 /**
       
    51  * Activation makes use of special identifiers to denote remote
       
    52  * objects that can be activated over time. An activation identifier
       
    53  * (an instance of the class <code>ActivationID</code>) contains several
       
    54  * pieces of information needed for activating an object:
       
    55  * <ul>
       
    56  * <li> a remote reference to the object's activator (a {@link
       
    57  * java.rmi.server.RemoteRef RemoteRef}
       
    58  * instance), and
       
    59  * <li> a unique identifier (a {@link java.rmi.server.UID UID}
       
    60  * instance) for the object. </ul> <p>
       
    61  *
       
    62  * An activation identifier for an object can be obtained by registering
       
    63  * an object with the activation system. Registration is accomplished
       
    64  * in a few ways: <ul>
       
    65  * <li>via the <code>Activatable.register</code> method
       
    66  * <li>via the first <code>Activatable</code> constructor (that takes
       
    67  * three arguments and both registers and exports the object, and
       
    68  * <li>via the first <code>Activatable.exportObject</code> method
       
    69  * that takes the activation descriptor, object and port as arguments;
       
    70  * this method both registers and exports the object. </ul>
       
    71  *
       
    72  * @author      Ann Wollrath
       
    73  * @see         Activatable
       
    74  * @since       1.2
       
    75  */
       
    76 public class ActivationID implements Serializable {
       
    77     /**
       
    78      * the object's activator
       
    79      */
       
    80     private transient Activator activator;
       
    81 
       
    82     /**
       
    83      * the object's unique id
       
    84      */
       
    85     private transient UID uid = new UID();
       
    86 
       
    87     /** indicate compatibility with the Java 2 SDK v1.2 version of class */
       
    88     private static final long serialVersionUID = -4608673054848209235L;
       
    89 
       
    90     /** an AccessControlContext with no permissions */
       
    91     private static final AccessControlContext NOPERMS_ACC;
       
    92     static {
       
    93         Permissions perms = new Permissions();
       
    94         ProtectionDomain[] pd = { new ProtectionDomain(null, perms) };
       
    95         NOPERMS_ACC = new AccessControlContext(pd);
       
    96     }
       
    97 
       
    98     /**
       
    99      * The constructor for <code>ActivationID</code> takes a single
       
   100      * argument, activator, that specifies a remote reference to the
       
   101      * activator responsible for activating the object associated with
       
   102      * this identifier. An instance of <code>ActivationID</code> is globally
       
   103      * unique.
       
   104      *
       
   105      * @param activator reference to the activator responsible for
       
   106      * activating the object
       
   107      * @throws UnsupportedOperationException if and only if activation is
       
   108      *         not supported by this implementation
       
   109      * @since 1.2
       
   110      */
       
   111     public ActivationID(Activator activator) {
       
   112         this.activator = activator;
       
   113     }
       
   114 
       
   115     /**
       
   116      * Activate the object for this id.
       
   117      *
       
   118      * @param force if true, forces the activator to contact the group
       
   119      * when activating the object (instead of returning a cached reference);
       
   120      * if false, returning a cached value is acceptable.
       
   121      * @return the reference to the active remote object
       
   122      * @exception ActivationException if activation fails
       
   123      * @exception UnknownObjectException if the object is unknown
       
   124      * @exception RemoteException if remote call fails
       
   125      * @since 1.2
       
   126      */
       
   127     public Remote activate(boolean force)
       
   128         throws ActivationException, UnknownObjectException, RemoteException
       
   129     {
       
   130         try {
       
   131             MarshalledObject<? extends Remote> mobj =
       
   132                 activator.activate(this, force);
       
   133             return AccessController.doPrivileged(
       
   134                 new PrivilegedExceptionAction<Remote>() {
       
   135                     public Remote run() throws IOException, ClassNotFoundException {
       
   136                         return mobj.get();
       
   137                     }
       
   138                 }, NOPERMS_ACC);
       
   139         } catch (PrivilegedActionException pae) {
       
   140             Exception ex = pae.getException();
       
   141             if (ex instanceof RemoteException) {
       
   142                 throw (RemoteException) ex;
       
   143             } else {
       
   144                 throw new UnmarshalException("activation failed", ex);
       
   145             }
       
   146         }
       
   147 
       
   148     }
       
   149 
       
   150     /**
       
   151      * Returns a hashcode for the activation id.  Two identifiers that
       
   152      * refer to the same remote object will have the same hash code.
       
   153      *
       
   154      * @see java.util.Hashtable
       
   155      * @since 1.2
       
   156      */
       
   157     public int hashCode() {
       
   158         return uid.hashCode();
       
   159     }
       
   160 
       
   161     /**
       
   162      * Compares two activation ids for content equality.
       
   163      * Returns true if both of the following conditions are true:
       
   164      * 1) the unique identifiers equivalent (by content), and
       
   165      * 2) the activator specified in each identifier
       
   166      *    refers to the same remote object.
       
   167      *
       
   168      * @param   obj     the Object to compare with
       
   169      * @return  true if these Objects are equal; false otherwise.
       
   170      * @see             java.util.Hashtable
       
   171      * @since 1.2
       
   172      */
       
   173     public boolean equals(Object obj) {
       
   174         if (obj instanceof ActivationID) {
       
   175             ActivationID id = (ActivationID) obj;
       
   176             return (uid.equals(id.uid) && activator.equals(id.activator));
       
   177         } else {
       
   178             return false;
       
   179         }
       
   180     }
       
   181 
       
   182     /**
       
   183      * <code>writeObject</code> for custom serialization.
       
   184      *
       
   185      * <p>This method writes this object's serialized form for
       
   186      * this class as follows:
       
   187      *
       
   188      * <p>The <code>writeObject</code> method is invoked on
       
   189      * <code>out</code> passing this object's unique identifier
       
   190      * (a {@link java.rmi.server.UID UID} instance) as the argument.
       
   191      *
       
   192      * <p>Next, the {@link
       
   193      * java.rmi.server.RemoteRef#getRefClass(java.io.ObjectOutput)
       
   194      * getRefClass} method is invoked on the activator's
       
   195      * <code>RemoteRef</code> instance to obtain its external ref
       
   196      * type name.  Next, the <code>writeUTF</code> method is
       
   197      * invoked on <code>out</code> with the value returned by
       
   198      * <code>getRefClass</code>, and then the
       
   199      * <code>writeExternal</code> method is invoked on the
       
   200      * <code>RemoteRef</code> instance passing <code>out</code>
       
   201      * as the argument.
       
   202      *
       
   203      * @serialData The serialized data for this class comprises a
       
   204      * <code>java.rmi.server.UID</code> (written with
       
   205      * <code>ObjectOutput.writeObject</code>) followed by the
       
   206      * external ref type name of the activator's
       
   207      * <code>RemoteRef</code> instance (a string written with
       
   208      * <code>ObjectOutput.writeUTF</code>), followed by the
       
   209      * external form of the <code>RemoteRef</code> instance as
       
   210      * written by its <code>writeExternal</code> method.
       
   211      *
       
   212      * <p>The external ref type name of the
       
   213      * <code>RemoteRef</Code> instance is
       
   214      * determined using the definitions of external ref type
       
   215      * names specified in the {@link java.rmi.server.RemoteObject
       
   216      * RemoteObject} <code>writeObject</code> method
       
   217      * <b>serialData</b> specification.  Similarly, the data
       
   218      * written by the <code>writeExternal</code> method and read
       
   219      * by the <code>readExternal</code> method of
       
   220      * <code>RemoteRef</code> implementation classes
       
   221      * corresponding to each of the defined external ref type
       
   222      * names is specified in the {@link
       
   223      * java.rmi.server.RemoteObject RemoteObject}
       
   224      * <code>writeObject</code> method <b>serialData</b>
       
   225      * specification.
       
   226      **/
       
   227     private void writeObject(ObjectOutputStream out)
       
   228         throws IOException, ClassNotFoundException
       
   229     {
       
   230         out.writeObject(uid);
       
   231 
       
   232         RemoteRef ref;
       
   233         if (activator instanceof RemoteObject) {
       
   234             ref = ((RemoteObject) activator).getRef();
       
   235         } else if (Proxy.isProxyClass(activator.getClass())) {
       
   236             InvocationHandler handler = Proxy.getInvocationHandler(activator);
       
   237             if (!(handler instanceof RemoteObjectInvocationHandler)) {
       
   238                 throw new InvalidObjectException(
       
   239                     "unexpected invocation handler");
       
   240             }
       
   241             ref = ((RemoteObjectInvocationHandler) handler).getRef();
       
   242 
       
   243         } else {
       
   244             throw new InvalidObjectException("unexpected activator type");
       
   245         }
       
   246         out.writeUTF(ref.getRefClass(out));
       
   247         ref.writeExternal(out);
       
   248     }
       
   249 
       
   250     /**
       
   251      * <code>readObject</code> for custom serialization.
       
   252      *
       
   253      * <p>This method reads this object's serialized form for this
       
   254      * class as follows:
       
   255      *
       
   256      * <p>The <code>readObject</code> method is invoked on
       
   257      * <code>in</code> to read this object's unique identifier
       
   258      * (a {@link java.rmi.server.UID UID} instance).
       
   259      *
       
   260      * <p>Next, the <code>readUTF</code> method is invoked on
       
   261      * <code>in</code> to read the external ref type name of the
       
   262      * <code>RemoteRef</code> instance for this object's
       
   263      * activator.  Next, the <code>RemoteRef</code>
       
   264      * instance is created of an implementation-specific class
       
   265      * corresponding to the external ref type name (returned by
       
   266      * <code>readUTF</code>), and the <code>readExternal</code>
       
   267      * method is invoked on that <code>RemoteRef</code> instance
       
   268      * to read the external form corresponding to the external
       
   269      * ref type name.
       
   270      *
       
   271      * <p>Note: If the external ref type name is
       
   272      * <code>"UnicastRef"</code>, <code>"UnicastServerRef"</code>,
       
   273      * <code>"UnicastRef2"</code>, <code>"UnicastServerRef2"</code>,
       
   274      * or <code>"ActivatableRef"</code>, a corresponding
       
   275      * implementation-specific class must be found, and its
       
   276      * <code>readExternal</code> method must read the serial data
       
   277      * for that external ref type name as specified to be written
       
   278      * in the <b>serialData</b> documentation for this class.
       
   279      * If the external ref type name is any other string (of non-zero
       
   280      * length), a <code>ClassNotFoundException</code> will be thrown,
       
   281      * unless the implementation provides an implementation-specific
       
   282      * class corresponding to that external ref type name, in which
       
   283      * case the <code>RemoteRef</code> will be an instance of
       
   284      * that implementation-specific class.
       
   285      */
       
   286     private void readObject(ObjectInputStream in)
       
   287         throws IOException, ClassNotFoundException
       
   288     {
       
   289         uid = (UID)in.readObject();
       
   290 
       
   291         try {
       
   292             Class<? extends RemoteRef> refClass =
       
   293                 Class.forName(RemoteRef.packagePrefix + "." + in.readUTF())
       
   294                 .asSubclass(RemoteRef.class);
       
   295             @SuppressWarnings("deprecation")
       
   296             RemoteRef ref = refClass.newInstance();
       
   297             ref.readExternal(in);
       
   298             activator = (Activator)
       
   299                 Proxy.newProxyInstance(Activator.class.getClassLoader(),
       
   300                                        new Class<?>[] { Activator.class },
       
   301                                        new RemoteObjectInvocationHandler(ref));
       
   302         } catch (InstantiationException e) {
       
   303             throw (IOException)
       
   304                 new InvalidObjectException(
       
   305                     "Unable to create remote reference").initCause(e);
       
   306         } catch (IllegalAccessException e) {
       
   307             throw (IOException)
       
   308                 new InvalidObjectException(
       
   309                     "Unable to create remote reference").initCause(e);
       
   310         }
       
   311     }
       
   312 }