1 /* 2 * Copyright (c) 1996, 2020, 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.server; 27 28 import java.io.IOException; 29 import java.rmi.Remote; 30 import java.rmi.NoSuchObjectException; 31 import java.lang.reflect.Proxy; 32 import sun.rmi.server.Util; 33 34 /** 35 * The <code>RemoteObject</code> class implements the 36 * <code>java.lang.Object</code> behavior for remote objects. 37 * <code>RemoteObject</code> provides the remote semantics of Object by 38 * implementing methods for hashCode, equals, and toString. 39 * 40 * @author Ann Wollrath 41 * @author Laird Dornin 42 * @author Peter Jones 43 * @since 1.1 44 */ 45 public abstract class RemoteObject implements Remote, java.io.Serializable { 46 47 /** The object's remote reference. */ 48 transient protected RemoteRef ref; 49 50 /** indicate compatibility with JDK 1.1.x version of class */ 51 @java.io.Serial 52 private static final long serialVersionUID = -3215090123894869218L; 53 54 /** 55 * Creates a remote object. 56 */ RemoteObject()57 protected RemoteObject() { 58 ref = null; 59 } 60 61 /** 62 * Creates a remote object, initialized with the specified remote 63 * reference. 64 * @param newref remote reference 65 */ RemoteObject(RemoteRef newref)66 protected RemoteObject(RemoteRef newref) { 67 ref = newref; 68 } 69 70 /** 71 * Returns the remote reference for the remote object. 72 * 73 * <p>Note: The object returned from this method may be an instance of 74 * an implementation-specific class. The <code>RemoteObject</code> 75 * class ensures serialization portability of its instances' remote 76 * references through the behavior of its custom 77 * <code>writeObject</code> and <code>readObject</code> methods. An 78 * instance of <code>RemoteRef</code> should not be serialized outside 79 * of its <code>RemoteObject</code> wrapper instance or the result may 80 * be unportable. 81 * 82 * @return remote reference for the remote object 83 * @since 1.2 84 */ getRef()85 public RemoteRef getRef() { 86 return ref; 87 } 88 89 /** 90 * Returns the stub for the remote object <code>obj</code> passed 91 * as a parameter. This operation is only valid <i>after</i> 92 * the object has been exported. 93 * @param obj the remote object whose stub is needed 94 * @return the stub for the remote object, <code>obj</code>. 95 * @throws NoSuchObjectException if the stub for the 96 * remote object could not be found. 97 * @since 1.2 98 */ 99 @SuppressWarnings("deprecation") toStub(Remote obj)100 public static Remote toStub(Remote obj) throws NoSuchObjectException { 101 if (obj instanceof RemoteStub || 102 (obj != null && 103 Proxy.isProxyClass(obj.getClass()) && 104 Proxy.getInvocationHandler(obj) instanceof 105 RemoteObjectInvocationHandler)) 106 { 107 return obj; 108 } else { 109 return sun.rmi.transport.ObjectTable.getStub(obj); 110 } 111 } 112 113 /** 114 * Returns a hashcode for a remote object. Two remote object stubs 115 * that refer to the same remote object will have the same hash code 116 * (in order to support remote objects as keys in hash tables). 117 * 118 * @see java.util.Hashtable 119 */ hashCode()120 public int hashCode() { 121 return (ref == null) ? super.hashCode() : ref.remoteHashCode(); 122 } 123 124 /** 125 * Compares two remote objects for equality. 126 * Returns a boolean that indicates whether this remote object is 127 * equivalent to the specified Object. This method is used when a 128 * remote object is stored in a hashtable. 129 * If the specified Object is not itself an instance of RemoteObject, 130 * then this method delegates by returning the result of invoking the 131 * <code>equals</code> method of its parameter with this remote object 132 * as the argument. 133 * @param obj the Object to compare with 134 * @return true if these Objects are equal; false otherwise. 135 * @see java.util.Hashtable 136 */ equals(Object obj)137 public boolean equals(Object obj) { 138 if (obj instanceof RemoteObject) { 139 if (ref == null) { 140 return obj == this; 141 } else { 142 return ref.remoteEquals(((RemoteObject)obj).ref); 143 } 144 } else if (obj != null) { 145 /* 146 * Fix for 4099660: if object is not an instance of RemoteObject, 147 * use the result of its equals method, to support symmetry is a 148 * remote object implementation class that does not extend 149 * RemoteObject wishes to support equality with its stub objects. 150 */ 151 return obj.equals(this); 152 } else { 153 return false; 154 } 155 } 156 157 /** 158 * Returns a String that represents the value of this remote object. 159 */ toString()160 public String toString() { 161 String classname = Util.getUnqualifiedName(getClass()); 162 return (ref == null) ? classname : 163 classname + "[" + ref.remoteToString() + "]"; 164 } 165 166 /** 167 * <code>writeObject</code> for custom serialization. 168 * 169 * <p>This method writes this object's serialized form for this class 170 * as follows: 171 * 172 * <p>The {@link RemoteRef#getRefClass(java.io.ObjectOutput) getRefClass} 173 * method is invoked on this object's <code>ref</code> field 174 * to obtain its external ref type name. 175 * If the value returned by <code>getRefClass</code> was 176 * a non-<code>null</code> string of length greater than zero, 177 * the <code>writeUTF</code> method is invoked on <code>out</code> 178 * with the value returned by <code>getRefClass</code>, and then 179 * the <code>writeExternal</code> method is invoked on 180 * this object's <code>ref</code> field passing <code>out</code> 181 * as the argument; otherwise, 182 * the <code>writeUTF</code> method is invoked on <code>out</code> 183 * with a zero-length string (<code>""</code>), and then 184 * the <code>writeObject</code> method is invoked on <code>out</code> 185 * passing this object's <code>ref</code> field as the argument. 186 * 187 * @serialData 188 * 189 * The serialized data for this class comprises a string (written with 190 * <code>ObjectOutput.writeUTF</code>) that is either the external 191 * ref type name of the contained <code>RemoteRef</code> instance 192 * (the <code>ref</code> field) or a zero-length string, followed by 193 * either the external form of the <code>ref</code> field as written by 194 * its <code>writeExternal</code> method if the string was of non-zero 195 * length, or the serialized form of the <code>ref</code> field as 196 * written by passing it to the serialization stream's 197 * <code>writeObject</code> if the string was of zero length. 198 * 199 * <p>If this object is an instance of 200 * {@link RemoteStub} or {@link RemoteObjectInvocationHandler} 201 * that was returned from any of 202 * the <code>UnicastRemoteObject.exportObject</code> methods 203 * and custom socket factories are not used, 204 * the external ref type name is <code>"UnicastRef"</code>. 205 * 206 * If this object is an instance of 207 * <code>RemoteStub</code> or <code>RemoteObjectInvocationHandler</code> 208 * that was returned from any of 209 * the <code>UnicastRemoteObject.exportObject</code> methods 210 * and custom socket factories are used, 211 * the external ref type name is <code>"UnicastRef2"</code>. 212 * 213 * If this object is an instance of 214 * <code>RemoteStub</code> or <code>RemoteObjectInvocationHandler</code> 215 * that was returned from any of 216 * the <code>java.rmi.activation.Activatable.exportObject</code> methods, 217 * the external ref type name is <code>"ActivatableRef"</code>. 218 * 219 * If this object is an instance of 220 * <code>RemoteStub</code> or <code>RemoteObjectInvocationHandler</code> 221 * that was returned from 222 * the <code>RemoteObject.toStub</code> method (and the argument passed 223 * to <code>toStub</code> was not itself a <code>RemoteStub</code>), 224 * the external ref type name is a function of how the remote object 225 * passed to <code>toStub</code> was exported, as described above. 226 * 227 * If this object is an instance of 228 * <code>RemoteStub</code> or <code>RemoteObjectInvocationHandler</code> 229 * that was originally created via deserialization, 230 * the external ref type name is the same as that which was read 231 * when this object was deserialized. 232 * 233 * <p>If this object is an instance of 234 * <code>java.rmi.server.UnicastRemoteObject</code> that does not 235 * use custom socket factories, 236 * the external ref type name is <code>"UnicastServerRef"</code>. 237 * 238 * If this object is an instance of 239 * <code>UnicastRemoteObject</code> that does 240 * use custom socket factories, 241 * the external ref type name is <code>"UnicastServerRef2"</code>. 242 * 243 * <p>Following is the data that must be written by the 244 * <code>writeExternal</code> method and read by the 245 * <code>readExternal</code> method of <code>RemoteRef</code> 246 * implementation classes that correspond to the each of the 247 * defined external ref type names: 248 * 249 * <p>For <code>"UnicastRef"</code>: 250 * 251 * <ul> 252 * 253 * <li>the hostname of the referenced remote object, 254 * written by {@link java.io.ObjectOutput#writeUTF(String)} 255 * 256 * <li>the port of the referenced remote object, 257 * written by {@link java.io.ObjectOutput#writeInt(int)} 258 * 259 * <li>the data written as a result of calling 260 * {link java.rmi.server.ObjID#write(java.io.ObjectOutput)} 261 * on the <code>ObjID</code> instance contained in the reference 262 * 263 * <li>the boolean value <code>false</code>, 264 * written by {@link java.io.ObjectOutput#writeBoolean(boolean)} 265 * 266 * </ul> 267 * 268 * <p>For <code>"UnicastRef2"</code> with a 269 * <code>null</code> client socket factory: 270 * 271 * <ul> 272 * 273 * <li>the byte value <code>0x00</code> 274 * (indicating <code>null</code> client socket factory), 275 * written by {@link java.io.ObjectOutput#writeByte(int)} 276 * 277 * <li>the hostname of the referenced remote object, 278 * written by {@link java.io.ObjectOutput#writeUTF(String)} 279 * 280 * <li>the port of the referenced remote object, 281 * written by {@link java.io.ObjectOutput#writeInt(int)} 282 * 283 * <li>the data written as a result of calling 284 * {link java.rmi.server.ObjID#write(java.io.ObjectOutput)} 285 * on the <code>ObjID</code> instance contained in the reference 286 * 287 * <li>the boolean value <code>false</code>, 288 * written by {@link java.io.ObjectOutput#writeBoolean(boolean)} 289 * 290 * </ul> 291 * 292 * <p>For <code>"UnicastRef2"</code> with a 293 * non-<code>null</code> client socket factory: 294 * 295 * <ul> 296 * 297 * <li>the byte value <code>0x01</code> 298 * (indicating non-<code>null</code> client socket factory), 299 * written by {@link java.io.ObjectOutput#writeByte(int)} 300 * 301 * <li>the hostname of the referenced remote object, 302 * written by {@link java.io.ObjectOutput#writeUTF(String)} 303 * 304 * <li>the port of the referenced remote object, 305 * written by {@link java.io.ObjectOutput#writeInt(int)} 306 * 307 * <li>a client socket factory (object of type 308 * <code>java.rmi.server.RMIClientSocketFactory</code>), 309 * written by passing it to an invocation of 310 * <code>writeObject</code> on the stream instance 311 * 312 * <li>the data written as a result of calling 313 * {link java.rmi.server.ObjID#write(java.io.ObjectOutput)} 314 * on the <code>ObjID</code> instance contained in the reference 315 * 316 * <li>the boolean value <code>false</code>, 317 * written by {@link java.io.ObjectOutput#writeBoolean(boolean)} 318 * 319 * </ul> 320 * 321 * <p>For <code>"ActivatableRef"</code> with a 322 * <code>null</code> nested remote reference: 323 * 324 * <ul> 325 * 326 * <li>an instance of 327 * <code>java.rmi.activation.ActivationID</code>, 328 * written by passing it to an invocation of 329 * <code>writeObject</code> on the stream instance 330 * 331 * <li>a zero-length string (<code>""</code>), 332 * written by {@link java.io.ObjectOutput#writeUTF(String)} 333 * 334 * </ul> 335 * 336 * <p>For <code>"ActivatableRef"</code> with a 337 * non-<code>null</code> nested remote reference: 338 * 339 * <ul> 340 * 341 * <li>an instance of 342 * <code>java.rmi.activation.ActivationID</code>, 343 * written by passing it to an invocation of 344 * <code>writeObject</code> on the stream instance 345 * 346 * <li>the external ref type name of the nested remote reference, 347 * which must be <code>"UnicastRef2"</code>, 348 * written by {@link java.io.ObjectOutput#writeUTF(String)} 349 * 350 * <li>the external form of the nested remote reference, 351 * written by invoking its <code>writeExternal</code> method 352 * with the stream instance 353 * (see the description of the external form for 354 * <code>"UnicastRef2"</code> above) 355 * 356 * </ul> 357 * 358 * <p>For <code>"UnicastServerRef"</code> and 359 * <code>"UnicastServerRef2"</code>, no data is written by the 360 * <code>writeExternal</code> method or read by the 361 * <code>readExternal</code> method. 362 * 363 * @param out the {@code ObjectOutputStream} to which data is written 364 * @throws IOException if an I/O error occurs 365 */ 366 @java.io.Serial writeObject(java.io.ObjectOutputStream out)367 private void writeObject(java.io.ObjectOutputStream out) 368 throws java.io.IOException 369 { 370 if (ref == null) { 371 throw new java.rmi.MarshalException("Invalid remote object"); 372 } else { 373 String refClassName = ref.getRefClass(out); 374 if (refClassName == null || refClassName.length() == 0) { 375 /* 376 * No reference class name specified, so serialize 377 * remote reference. 378 */ 379 out.writeUTF(""); 380 out.writeObject(ref); 381 } else { 382 /* 383 * Built-in reference class specified, so delegate 384 * to reference to write out its external form. 385 */ 386 out.writeUTF(refClassName); 387 ref.writeExternal(out); 388 } 389 } 390 } 391 392 /** 393 * <code>readObject</code> for custom serialization. 394 * 395 * <p>This method reads this object's serialized form for this class 396 * as follows: 397 * 398 * <p>The <code>readUTF</code> method is invoked on <code>in</code> 399 * to read the external ref type name for the <code>RemoteRef</code> 400 * instance to be filled in to this object's <code>ref</code> field. 401 * If the string returned by <code>readUTF</code> has length zero, 402 * the <code>readObject</code> method is invoked on <code>in</code>, 403 * and than the value returned by <code>readObject</code> is cast to 404 * <code>RemoteRef</code> and this object's <code>ref</code> field is 405 * set to that value. 406 * Otherwise, this object's <code>ref</code> field is set to a 407 * <code>RemoteRef</code> instance that is created of an 408 * implementation-specific class corresponding to the external ref 409 * type name returned by <code>readUTF</code>, and then 410 * the <code>readExternal</code> method is invoked on 411 * this object's <code>ref</code> field. 412 * 413 * <p>If the external ref type name is 414 * <code>"UnicastRef"</code>, <code>"UnicastServerRef"</code>, 415 * <code>"UnicastRef2"</code>, <code>"UnicastServerRef2"</code>, 416 * or <code>"ActivatableRef"</code>, a corresponding 417 * implementation-specific class must be found, and its 418 * <code>readExternal</code> method must read the serial data 419 * for that external ref type name as specified to be written 420 * in the <b>serialData</b> documentation for this class. 421 * If the external ref type name is any other string (of non-zero 422 * length), a <code>ClassNotFoundException</code> will be thrown, 423 * unless the implementation provides an implementation-specific 424 * class corresponding to that external ref type name, in which 425 * case this object's <code>ref</code> field will be set to an 426 * instance of that implementation-specific class. 427 * 428 * @param in the {@code ObjectInputStream} from which data is read 429 * @throws IOException if an I/O error occurs 430 * @throws ClassNotFoundException if a serialized class cannot be loaded 431 */ 432 @java.io.Serial readObject(java.io.ObjectInputStream in)433 private void readObject(java.io.ObjectInputStream in) 434 throws java.io.IOException, java.lang.ClassNotFoundException 435 { 436 String refClassName = in.readUTF(); 437 if (refClassName == null || refClassName.length() == 0) { 438 /* 439 * No reference class name specified, so construct 440 * remote reference from its serialized form. 441 */ 442 ref = (RemoteRef) in.readObject(); 443 } else { 444 /* 445 * Built-in reference class specified, so delegate to 446 * internal reference class to initialize its fields from 447 * its external form. 448 */ 449 String internalRefClassName = 450 RemoteRef.packagePrefix + "." + refClassName; 451 Class<?> refClass = Class.forName(internalRefClassName); 452 try { 453 @SuppressWarnings("deprecation") 454 Object tmp = refClass.newInstance(); 455 ref = (RemoteRef) tmp; 456 457 /* 458 * If this step fails, assume we found an internal 459 * class that is not meant to be a serializable ref 460 * type. 461 */ 462 } catch (InstantiationException | IllegalAccessException | ClassCastException e) { 463 throw new ClassNotFoundException(internalRefClassName, e); 464 } 465 ref.readExternal(in); 466 } 467 } 468 } 469