aboutsummaryrefslogtreecommitdiff
path: root/src/share/classes/java/rmi/server/RemoteObject.java
blob: 6cb56b28b9c7d5196db3f102828db1ceb322a11e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
/*
 * Copyright 1996-2003 Sun Microsystems, Inc.  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.  Sun designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
 * CA 95054 USA or visit www.sun.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 <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       JDK1.1
 */
public abstract class RemoteObject implements Remote, java.io.Serializable {

    /** The object's remote reference. */
    transient protected RemoteRef ref;

    /** indicate compatibility with JDK 1.1.x version of class */
    private static final long serialVersionUID = -3215090123894869218L;

    /**
     * Creates a remote object.
     */
    protected RemoteObject() {
        ref = null;
    }

    /**
     * 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.
     *
     * <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 <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
     */
    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             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
     * <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.
     */
    public String toString() {
        String classname = Util.getUnqualifiedName(getClass());
        return (ref == null) ? classname :
            classname + "[" + ref.remoteToString() + "]";
    }

    /**
     * <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);
            }
        }
    }

    /**
     * <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 {
                ref = (RemoteRef) refClass.newInstance();

                /*
                 * If this step fails, assume we found an internal
                 * class that is not meant to be a serializable ref
                 * type.
                 */
            } catch (InstantiationException e) {
                throw new ClassNotFoundException(internalRefClassName, e);
            } catch (IllegalAccessException e) {
                throw new ClassNotFoundException(internalRefClassName, e);
            } catch (ClassCastException e) {
                throw new ClassNotFoundException(internalRefClassName, e);
            }
            ref.readExternal(in);
        }
    }
}