/*
 * Copyright (c) 1996, 2014, 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.server;

import java.rmi.Remote;
import java.rmi.NoSuchObjectException;
import java.lang.reflect.Proxy;
import sun.rmi.server.Util;

The RemoteObject class implements the java.lang.Object behavior for remote objects. RemoteObject provides the remote semantics of Object by implementing methods for hashCode, equals, and toString.
Author: Ann Wollrath, Laird Dornin, Peter Jones
Since: 1.1
/** * The <code>RemoteObject</code> class implements the * <code>java.lang.Object</code> behavior for remote objects. * <code>RemoteObject</code> provides the remote semantics of Object by * implementing methods for hashCode, equals, and toString. * * @author Ann Wollrath * @author Laird Dornin * @author Peter Jones * @since 1.1 */
public abstract class RemoteObject implements Remote, java.io.Serializable {
The object's remote reference.
/** The object's remote reference. */
transient protected RemoteRef ref;
indicate compatibility with JDK 1.1.x version of class
/** indicate compatibility with JDK 1.1.x version of class */
private static final long serialVersionUID = -3215090123894869218L;
Creates a remote object.
/** * Creates a remote object. */
protected RemoteObject() { ref = null; }
Creates a remote object, initialized with the specified remote reference.
Params:
  • newref – remote reference
/** * Creates a remote object, initialized with the specified remote * reference. * @param newref remote reference */
protected RemoteObject(RemoteRef newref) { ref = newref; }
Returns the remote reference for the remote object.

Note: The object returned from this method may be an instance of an implementation-specific class. The RemoteObject class ensures serialization portability of its instances' remote references through the behavior of its custom writeObject and readObject methods. An instance of RemoteRef should not be serialized outside of its RemoteObject wrapper instance or the result may be unportable.

Returns:remote reference for the remote object
Since:1.2
/** * Returns the remote reference for the remote object. * * <p>Note: The object returned from this method may be an instance of * an implementation-specific class. The <code>RemoteObject</code> * class ensures serialization portability of its instances' remote * references through the behavior of its custom * <code>writeObject</code> and <code>readObject</code> methods. An * instance of <code>RemoteRef</code> should not be serialized outside * of its <code>RemoteObject</code> wrapper instance or the result may * be unportable. * * @return remote reference for the remote object * @since 1.2 */
public RemoteRef getRef() { return ref; }
Returns the stub for the remote object obj passed as a parameter. This operation is only valid after the object has been exported.
Params:
  • obj – the remote object whose stub is needed
Throws:
Returns:the stub for the remote object, obj.
Since:1.2
/** * Returns the stub for the remote object <code>obj</code> passed * as a parameter. This operation is only valid <i>after</i> * the object has been exported. * @param obj the remote object whose stub is needed * @return the stub for the remote object, <code>obj</code>. * @exception NoSuchObjectException if the stub for the * remote object could not be found. * @since 1.2 */
@SuppressWarnings("deprecation") public static Remote toStub(Remote obj) throws NoSuchObjectException { if (obj instanceof RemoteStub || (obj != null && Proxy.isProxyClass(obj.getClass()) && Proxy.getInvocationHandler(obj) instanceof RemoteObjectInvocationHandler)) { return obj; } else { return sun.rmi.transport.ObjectTable.getStub(obj); } }
Returns a hashcode for a remote object. Two remote object stubs that refer to the same remote object will have the same hash code (in order to support remote objects as keys in hash tables).
See Also:
  • Hashtable
/** * Returns a hashcode for a remote object. Two remote object stubs * that refer to the same remote object will have the same hash code * (in order to support remote objects as keys in hash tables). * * @see java.util.Hashtable */
public int hashCode() { return (ref == null) ? super.hashCode() : ref.remoteHashCode(); }
Compares two remote objects for equality. Returns a boolean that indicates whether this remote object is equivalent to the specified Object. This method is used when a remote object is stored in a hashtable. If the specified Object is not itself an instance of RemoteObject, then this method delegates by returning the result of invoking the equals method of its parameter with this remote object as the argument.
Params:
  • obj – the Object to compare with
See Also:
Returns: true if these Objects are equal; false otherwise.
/** * Compares two remote objects for equality. * Returns a boolean that indicates whether this remote object is * equivalent to the specified Object. This method is used when a * remote object is stored in a hashtable. * If the specified Object is not itself an instance of RemoteObject, * then this method delegates by returning the result of invoking the * <code>equals</code> method of its parameter with this remote object * as the argument. * @param obj the Object to compare with * @return true if these Objects are equal; false otherwise. * @see java.util.Hashtable */
public boolean equals(Object obj) { if (obj instanceof RemoteObject) { if (ref == null) { return obj == this; } else { return ref.remoteEquals(((RemoteObject)obj).ref); } } else if (obj != null) { /* * Fix for 4099660: if object is not an instance of RemoteObject, * use the result of its equals method, to support symmetry is a * remote object implementation class that does not extend * RemoteObject wishes to support equality with its stub objects. */ return obj.equals(this); } else { return false; } }
Returns a String that represents the value of this remote object.
/** * Returns a String that represents the value of this remote object. */
public String toString() { String classname = Util.getUnqualifiedName(getClass()); return (ref == null) ? classname : classname + "[" + ref.remoteToString() + "]"; }
writeObject for custom serialization.

This method writes this object's serialized form for this class as follows:

The getRefClass method is invoked on this object's ref field to obtain its external ref type name. If the value returned by getRefClass was a non-null string of length greater than zero, the writeUTF method is invoked on out with the value returned by getRefClass, and then the writeExternal method is invoked on this object's ref field passing out as the argument; otherwise, the writeUTF method is invoked on out with a zero-length string (""), and then the writeObject method is invoked on out passing this object's ref field as the argument.

@serialData The serialized data for this class comprises a string (written with ObjectOutput.writeUTF) that is either the external ref type name of the contained RemoteRef instance (the ref field) or a zero-length string, followed by either the external form of the ref field as written by its writeExternal method if the string was of non-zero length, or the serialized form of the ref field as written by passing it to the serialization stream's writeObject if the string was of zero length.

If this object is an instance of RemoteStub or RemoteObjectInvocationHandler that was returned from any of the UnicastRemoteObject.exportObject methods and custom socket factories are not used, the external ref type name is "UnicastRef". If this object is an instance of RemoteStub or RemoteObjectInvocationHandler that was returned from any of the UnicastRemoteObject.exportObject methods and custom socket factories are used, the external ref type name is "UnicastRef2". If this object is an instance of RemoteStub or RemoteObjectInvocationHandler that was returned from any of the java.rmi.activation.Activatable.exportObject methods, the external ref type name is "ActivatableRef". If this object is an instance of RemoteStub or RemoteObjectInvocationHandler that was returned from the RemoteObject.toStub method (and the argument passed to toStub was not itself a RemoteStub), the external ref type name is a function of how the remote object passed to toStub was exported, as described above. If this object is an instance of RemoteStub or RemoteObjectInvocationHandler that was originally created via deserialization, the external ref type name is the same as that which was read when this object was deserialized.

If this object is an instance of java.rmi.server.UnicastRemoteObject that does not use custom socket factories, the external ref type name is "UnicastServerRef". If this object is an instance of UnicastRemoteObject that does use custom socket factories, the external ref type name is "UnicastServerRef2".

Following is the data that must be written by the writeExternal method and read by the readExternal method of RemoteRef implementation classes that correspond to the each of the defined external ref type names:

For "UnicastRef":

For "UnicastRef2" with a null client socket factory:

For "UnicastRef2" with a non-null client socket factory:

  • the byte value 0x01 (indicating non-null client socket factory), written by DataOutput.writeByte(int)
  • the hostname of the referenced remote object, written by DataOutput.writeUTF(String)
  • the port of the referenced remote object, written by DataOutput.writeInt(int)
  • a client socket factory (object of type java.rmi.server.RMIClientSocketFactory), written by passing it to an invocation of writeObject on the stream instance
  • the data written as a result of calling {link java.rmi.server.ObjID#write(java.io.ObjectOutput)} on the ObjID instance contained in the reference
  • the boolean value false, written by DataOutput.writeBoolean(boolean)

For "ActivatableRef" with a null nested remote reference:

  • an instance of java.rmi.activation.ActivationID, written by passing it to an invocation of writeObject on the stream instance
  • a zero-length string (""), written by DataOutput.writeUTF(String)

For "ActivatableRef" with a non-null nested remote reference:

  • an instance of java.rmi.activation.ActivationID, written by passing it to an invocation of writeObject on the stream instance
  • the external ref type name of the nested remote reference, which must be "UnicastRef2", written by DataOutput.writeUTF(String)
  • the external form of the nested remote reference, written by invoking its writeExternal method with the stream instance (see the description of the external form for "UnicastRef2" above)

For "UnicastServerRef" and "UnicastServerRef2", no data is written by the writeExternal method or read by the readExternal method.

/** * <code>writeObject</code> for custom serialization. * * <p>This method writes this object's serialized form for this class * as follows: * * <p>The {@link RemoteRef#getRefClass(java.io.ObjectOutput) getRefClass} * method is invoked on this object's <code>ref</code> field * to obtain its external ref type name. * If the value returned by <code>getRefClass</code> was * a non-<code>null</code> string of length greater than zero, * 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 * this object's <code>ref</code> field passing <code>out</code> * as the argument; otherwise, * the <code>writeUTF</code> method is invoked on <code>out</code> * with a zero-length string (<code>""</code>), and then * the <code>writeObject</code> method is invoked on <code>out</code> * passing this object's <code>ref</code> field as the argument. * * @serialData * * The serialized data for this class comprises a string (written with * <code>ObjectOutput.writeUTF</code>) that is either the external * ref type name of the contained <code>RemoteRef</code> instance * (the <code>ref</code> field) or a zero-length string, followed by * either the external form of the <code>ref</code> field as written by * its <code>writeExternal</code> method if the string was of non-zero * length, or the serialized form of the <code>ref</code> field as * written by passing it to the serialization stream's * <code>writeObject</code> if the string was of zero length. * * <p>If this object is an instance of * {@link RemoteStub} or {@link RemoteObjectInvocationHandler} * that was returned from any of * the <code>UnicastRemoteObject.exportObject</code> methods * and custom socket factories are not used, * the external ref type name is <code>"UnicastRef"</code>. * * If this object is an instance of * <code>RemoteStub</code> or <code>RemoteObjectInvocationHandler</code> * that was returned from any of * the <code>UnicastRemoteObject.exportObject</code> methods * and custom socket factories are used, * the external ref type name is <code>"UnicastRef2"</code>. * * If this object is an instance of * <code>RemoteStub</code> or <code>RemoteObjectInvocationHandler</code> * that was returned from any of * the <code>java.rmi.activation.Activatable.exportObject</code> methods, * the external ref type name is <code>"ActivatableRef"</code>. * * If this object is an instance of * <code>RemoteStub</code> or <code>RemoteObjectInvocationHandler</code> * that was returned from * the <code>RemoteObject.toStub</code> method (and the argument passed * to <code>toStub</code> was not itself a <code>RemoteStub</code>), * the external ref type name is a function of how the remote object * passed to <code>toStub</code> was exported, as described above. * * If this object is an instance of * <code>RemoteStub</code> or <code>RemoteObjectInvocationHandler</code> * that was originally created via deserialization, * the external ref type name is the same as that which was read * when this object was deserialized. * * <p>If this object is an instance of * <code>java.rmi.server.UnicastRemoteObject</code> that does not * use custom socket factories, * the external ref type name is <code>"UnicastServerRef"</code>. * * If this object is an instance of * <code>UnicastRemoteObject</code> that does * use custom socket factories, * the external ref type name is <code>"UnicastServerRef2"</code>. * * <p>Following is the data that must be written by the * <code>writeExternal</code> method and read by the * <code>readExternal</code> method of <code>RemoteRef</code> * implementation classes that correspond to the each of the * defined external ref type names: * * <p>For <code>"UnicastRef"</code>: * * <ul> * * <li>the hostname of the referenced remote object, * written by {@link java.io.ObjectOutput#writeUTF(String)} * * <li>the port of the referenced remote object, * written by {@link java.io.ObjectOutput#writeInt(int)} * * <li>the data written as a result of calling * {link java.rmi.server.ObjID#write(java.io.ObjectOutput)} * on the <code>ObjID</code> instance contained in the reference * * <li>the boolean value <code>false</code>, * written by {@link java.io.ObjectOutput#writeBoolean(boolean)} * * </ul> * * <p>For <code>"UnicastRef2"</code> with a * <code>null</code> client socket factory: * * <ul> * * <li>the byte value <code>0x00</code> * (indicating <code>null</code> client socket factory), * written by {@link java.io.ObjectOutput#writeByte(int)} * * <li>the hostname of the referenced remote object, * written by {@link java.io.ObjectOutput#writeUTF(String)} * * <li>the port of the referenced remote object, * written by {@link java.io.ObjectOutput#writeInt(int)} * * <li>the data written as a result of calling * {link java.rmi.server.ObjID#write(java.io.ObjectOutput)} * on the <code>ObjID</code> instance contained in the reference * * <li>the boolean value <code>false</code>, * written by {@link java.io.ObjectOutput#writeBoolean(boolean)} * * </ul> * * <p>For <code>"UnicastRef2"</code> with a * non-<code>null</code> client socket factory: * * <ul> * * <li>the byte value <code>0x01</code> * (indicating non-<code>null</code> client socket factory), * written by {@link java.io.ObjectOutput#writeByte(int)} * * <li>the hostname of the referenced remote object, * written by {@link java.io.ObjectOutput#writeUTF(String)} * * <li>the port of the referenced remote object, * written by {@link java.io.ObjectOutput#writeInt(int)} * * <li>a client socket factory (object of type * <code>java.rmi.server.RMIClientSocketFactory</code>), * written by passing it to an invocation of * <code>writeObject</code> on the stream instance * * <li>the data written as a result of calling * {link java.rmi.server.ObjID#write(java.io.ObjectOutput)} * on the <code>ObjID</code> instance contained in the reference * * <li>the boolean value <code>false</code>, * written by {@link java.io.ObjectOutput#writeBoolean(boolean)} * * </ul> * * <p>For <code>"ActivatableRef"</code> with a * <code>null</code> nested remote reference: * * <ul> * * <li>an instance of * <code>java.rmi.activation.ActivationID</code>, * written by passing it to an invocation of * <code>writeObject</code> on the stream instance * * <li>a zero-length string (<code>""</code>), * written by {@link java.io.ObjectOutput#writeUTF(String)} * * </ul> * * <p>For <code>"ActivatableRef"</code> with a * non-<code>null</code> nested remote reference: * * <ul> * * <li>an instance of * <code>java.rmi.activation.ActivationID</code>, * written by passing it to an invocation of * <code>writeObject</code> on the stream instance * * <li>the external ref type name of the nested remote reference, * which must be <code>"UnicastRef2"</code>, * written by {@link java.io.ObjectOutput#writeUTF(String)} * * <li>the external form of the nested remote reference, * written by invoking its <code>writeExternal</code> method * with the stream instance * (see the description of the external form for * <code>"UnicastRef2"</code> above) * * </ul> * * <p>For <code>"UnicastServerRef"</code> and * <code>"UnicastServerRef2"</code>, no data is written by the * <code>writeExternal</code> method or read by the * <code>readExternal</code> method. */
private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException, java.lang.ClassNotFoundException { if (ref == null) { throw new java.rmi.MarshalException("Invalid remote object"); } else { String refClassName = ref.getRefClass(out); if (refClassName == null || refClassName.length() == 0) { /* * No reference class name specified, so serialize * remote reference. */ out.writeUTF(""); out.writeObject(ref); } else { /* * Built-in reference class specified, so delegate * to reference to write out its external form. */ out.writeUTF(refClassName); ref.writeExternal(out); } } }
readObject for custom serialization.

This method reads this object's serialized form for this class as follows:

The readUTF method is invoked on in to read the external ref type name for the RemoteRef instance to be filled in to this object's ref field. If the string returned by readUTF has length zero, the readObject method is invoked on in, and than the value returned by readObject is cast to RemoteRef and this object's ref field is set to that value. Otherwise, this object's ref field is set to a RemoteRef instance that is created of an implementation-specific class corresponding to the external ref type name returned by readUTF, and then the readExternal method is invoked on this object's ref field.

If the external ref type name is "UnicastRef", "UnicastServerRef", "UnicastRef2", "UnicastServerRef2", or "ActivatableRef", a corresponding implementation-specific class must be found, and its readExternal method must read the serial data for that external ref type name as specified to be written in the serialData documentation for this class. If the external ref type name is any other string (of non-zero length), a ClassNotFoundException will be thrown, unless the implementation provides an implementation-specific class corresponding to that external ref type name, in which case this object's ref field will be set to an instance of that implementation-specific class.

/** * <code>readObject</code> for custom serialization. * * <p>This method reads this object's serialized form for this class * as follows: * * <p>The <code>readUTF</code> method is invoked on <code>in</code> * to read the external ref type name for the <code>RemoteRef</code> * instance to be filled in to this object's <code>ref</code> field. * If the string returned by <code>readUTF</code> has length zero, * the <code>readObject</code> method is invoked on <code>in</code>, * and than the value returned by <code>readObject</code> is cast to * <code>RemoteRef</code> and this object's <code>ref</code> field is * set to that value. * Otherwise, this object's <code>ref</code> field is set to a * <code>RemoteRef</code> instance that is created of an * implementation-specific class corresponding to the external ref * type name returned by <code>readUTF</code>, and then * the <code>readExternal</code> method is invoked on * this object's <code>ref</code> field. * * <p>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 this object's <code>ref</code> field will be set to an * instance of that implementation-specific class. */
private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, java.lang.ClassNotFoundException { String refClassName = in.readUTF(); if (refClassName == null || refClassName.length() == 0) { /* * No reference class name specified, so construct * remote reference from its serialized form. */ ref = (RemoteRef) in.readObject(); } else { /* * Built-in reference class specified, so delegate to * internal reference class to initialize its fields from * its external form. */ String internalRefClassName = RemoteRef.packagePrefix + "." + refClassName; Class<?> refClass = Class.forName(internalRefClassName); try { @SuppressWarnings("deprecation") Object tmp = refClass.newInstance(); ref = (RemoteRef) tmp; /* * If this step fails, assume we found an internal * class that is not meant to be a serializable ref * type. */ } catch (InstantiationException | IllegalAccessException | ClassCastException e) { throw new ClassNotFoundException(internalRefClassName, e); } ref.readExternal(in); } } }