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 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 }