1 /* 2 * Copyright (c) 1997, 2013, 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 44 /** 45 * Activation makes use of special identifiers to denote remote 46 * objects that can be activated over time. An activation identifier 47 * (an instance of the class <code>ActivationID</code>) contains several 48 * pieces of information needed for activating an object: 49 * <ul> 50 * <li> a remote reference to the object's activator (a {@link 51 * java.rmi.server.RemoteRef RemoteRef} 52 * instance), and 53 * <li> a unique identifier (a {@link java.rmi.server.UID UID} 54 * instance) for the object. </ul> <p> 55 * 56 * An activation identifier for an object can be obtained by registering 57 * an object with the activation system. Registration is accomplished 58 * in a few ways: <ul> 59 * <li>via the <code>Activatable.register</code> method 60 * <li>via the first <code>Activatable</code> constructor (that takes 61 * three arguments and both registers and exports the object, and 62 * <li>via the first <code>Activatable.exportObject</code> method 63 * that takes the activation descriptor, object and port as arguments; 64 * this method both registers and exports the object. </ul> 65 * 66 * @author Ann Wollrath 67 * @see Activatable 68 * @since 1.2 69 */ 70 public class ActivationID implements Serializable { 71 /** 72 * the object's activator 73 */ 74 private transient Activator activator; 75 76 /** 77 * the object's unique id 78 */ 79 private transient UID uid = new UID(); 80 81 /** indicate compatibility with the Java 2 SDK v1.2 version of class */ 82 private static final long serialVersionUID = -4608673054848209235L; 83 84 /** 85 * The constructor for <code>ActivationID</code> takes a single 86 * argument, activator, that specifies a remote reference to the 87 * activator responsible for activating the object associated with 88 * this identifier. An instance of <code>ActivationID</code> is globally 89 * unique. 90 * 91 * @param activator reference to the activator responsible for 92 * activating the object 93 * @throws UnsupportedOperationException if and only if activation is 94 * not supported by this implementation 95 * @since 1.2 96 */ 97 public ActivationID(Activator activator) { 98 this.activator = activator; 99 } 100 101 /** 102 * Activate the object for this id. 103 * 104 * @param force if true, forces the activator to contact the group 105 * when activating the object (instead of returning a cached reference); 106 * if false, returning a cached value is acceptable. 107 * @return the reference to the active remote object 108 * @exception ActivationException if activation fails 109 * @exception UnknownObjectException if the object is unknown 110 * @exception RemoteException if remote call fails 111 * @since 1.2 112 */ 113 public Remote activate(boolean force) 114 throws ActivationException, UnknownObjectException, RemoteException 115 { 116 try { 117 MarshalledObject<? extends Remote> mobj = 118 activator.activate(this, force); 119 return mobj.get(); 120 } catch (RemoteException e) { 121 throw e; 122 } catch (IOException e) { 123 throw new UnmarshalException("activation failed", e); 124 } catch (ClassNotFoundException e) { 125 throw new UnmarshalException("activation failed", e); 126 } 127 128 } 129 130 /** 131 * Returns a hashcode for the activation id. Two identifiers that 132 * refer to the same remote object will have the same hash code. 133 * 134 * @see java.util.Hashtable 135 * @since 1.2 136 */ 137 public int hashCode() { 138 return uid.hashCode(); 139 } 140 141 /** 142 * Compares two activation ids for content equality. 143 * Returns true if both of the following conditions are true: 144 * 1) the unique identifiers equivalent (by content), and 145 * 2) the activator specified in each identifier 146 * refers to the same remote object. 147 * 148 * @param obj the Object to compare with 149 * @return true if these Objects are equal; false otherwise. 150 * @see java.util.Hashtable 151 * @since 1.2 152 */ 153 public boolean equals(Object obj) { 154 if (obj instanceof ActivationID) { 155 ActivationID id = (ActivationID) obj; 156 return (uid.equals(id.uid) && activator.equals(id.activator)); 157 } else { 158 return false; 159 } 160 } 161 162 /** 163 * <code>writeObject</code> for custom serialization. 164 * 165 * <p>This method writes this object's serialized form for 166 * this class as follows: 167 * 168 * <p>The <code>writeObject</code> method is invoked on 169 * <code>out</code> passing this object's unique identifier 170 * (a {@link java.rmi.server.UID UID} instance) as the argument. 171 * 172 * <p>Next, the {@link 173 * java.rmi.server.RemoteRef#getRefClass(java.io.ObjectOutput) 174 * getRefClass} method is invoked on the activator's 175 * <code>RemoteRef</code> instance to obtain its external ref 176 * type name. Next, the <code>writeUTF</code> method is 177 * invoked on <code>out</code> with the value returned by 178 * <code>getRefClass</code>, and then the 179 * <code>writeExternal</code> method is invoked on the 180 * <code>RemoteRef</code> instance passing <code>out</code> 181 * as the argument. 182 * 183 * @serialData The serialized data for this class comprises a 184 * <code>java.rmi.server.UID</code> (written with 185 * <code>ObjectOutput.writeObject</code>) followed by the 186 * external ref type name of the activator's 187 * <code>RemoteRef</code> instance (a string written with 188 * <code>ObjectOutput.writeUTF</code>), followed by the 189 * external form of the <code>RemoteRef</code> instance as 190 * written by its <code>writeExternal</code> method. 191 * 192 * <p>The external ref type name of the 193 * <code>RemoteRef</Code> instance is 194 * determined using the definitions of external ref type 195 * names specified in the {@link java.rmi.server.RemoteObject 196 * RemoteObject} <code>writeObject</code> method 197 * <b>serialData</b> specification. Similarly, the data 198 * written by the <code>writeExternal</code> method and read 199 * by the <code>readExternal</code> method of 200 * <code>RemoteRef</code> implementation classes 201 * corresponding to each of the defined external ref type 202 * names is specified in the {@link 203 * java.rmi.server.RemoteObject RemoteObject} 204 * <code>writeObject</code> method <b>serialData</b> 205 * specification. 206 **/ 207 private void writeObject(ObjectOutputStream out) 208 throws IOException, ClassNotFoundException 209 { 210 out.writeObject(uid); 211 212 RemoteRef ref; 213 if (activator instanceof RemoteObject) { 214 ref = ((RemoteObject) activator).getRef(); 215 } else if (Proxy.isProxyClass(activator.getClass())) { 216 InvocationHandler handler = Proxy.getInvocationHandler(activator); 217 if (!(handler instanceof RemoteObjectInvocationHandler)) { 218 throw new InvalidObjectException( 219 "unexpected invocation handler"); 220 } 221 ref = ((RemoteObjectInvocationHandler) handler).getRef(); 222 223 } else { 224 throw new InvalidObjectException("unexpected activator type"); 225 } 226 out.writeUTF(ref.getRefClass(out)); 227 ref.writeExternal(out); 228 } 229 230 /** 231 * <code>readObject</code> for custom serialization. 232 * 233 * <p>This method reads this object's serialized form for this 234 * class as follows: 235 * 236 * <p>The <code>readObject</code> method is invoked on 237 * <code>in</code> to read this object's unique identifier 238 * (a {@link java.rmi.server.UID UID} instance). 239 * 240 * <p>Next, the <code>readUTF</code> method is invoked on 241 * <code>in</code> to read the external ref type name of the 242 * <code>RemoteRef</code> instance for this object's 243 * activator. Next, the <code>RemoteRef</code> 244 * instance is created of an implementation-specific class 245 * corresponding to the external ref type name (returned by 246 * <code>readUTF</code>), and the <code>readExternal</code> 247 * method is invoked on that <code>RemoteRef</code> instance 248 * to read the external form corresponding to the external 249 * ref type name. 250 * 251 * <p>Note: If the external ref type name is 252 * <code>"UnicastRef"</code>, <code>"UnicastServerRef"</code>, 253 * <code>"UnicastRef2"</code>, <code>"UnicastServerRef2"</code>, 254 * or <code>"ActivatableRef"</code>, a corresponding 255 * implementation-specific class must be found, and its 256 * <code>readExternal</code> method must read the serial data 257 * for that external ref type name as specified to be written 258 * in the <b>serialData</b> documentation for this class. 259 * If the external ref type name is any other string (of non-zero 260 * length), a <code>ClassNotFoundException</code> will be thrown, 261 * unless the implementation provides an implementation-specific 262 * class corresponding to that external ref type name, in which 263 * case the <code>RemoteRef</code> will be an instance of 264 * that implementation-specific class. 265 */ 266 private void readObject(ObjectInputStream in) 267 throws IOException, ClassNotFoundException 268 { 269 uid = (UID)in.readObject(); 270 271 try { 272 Class<? extends RemoteRef> refClass = 273 Class.forName(RemoteRef.packagePrefix + "." + in.readUTF()) 274 .asSubclass(RemoteRef.class); 275 @SuppressWarnings("deprecation") 276 RemoteRef ref = refClass.newInstance(); 277 ref.readExternal(in); 278 activator = (Activator) 279 Proxy.newProxyInstance(Activator.class.getClassLoader(), 280 new Class<?>[] { Activator.class }, 281 new RemoteObjectInvocationHandler(ref)); 282 } catch (InstantiationException e) { 283 throw (IOException) 284 new InvalidObjectException( 285 "Unable to create remote reference").initCause(e); 286 } catch (IllegalAccessException e) { 287 throw (IOException) 288 new InvalidObjectException( 289 "Unable to create remote reference").initCause(e); 290 } 291 } 292 }