KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > rmi > MarshalledObject


1 /*
2  * @(#)MarshalledObject.java 1.33 03/12/19
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package java.rmi;
9
10 import java.io.*;
11 import sun.rmi.server.MarshalInputStream;
12 import sun.rmi.server.MarshalOutputStream;
13
14 /**
15  * A <code>MarshalledObject</code> contains a byte stream with the serialized
16  * representation of an object given to its constructor. The <code>get</code>
17  * method returns a new copy of the original object, as deserialized from
18  * the contained byte stream. The contained object is serialized and
19  * deserialized with the same serialization semantics used for marshaling
20  * and unmarshaling parameters and return values of RMI calls: When the
21  * serialized form is created:
22  *
23  * <ul>
24  * <li> classes are annotated with a codebase URL from where the class
25  * can be loaded (if available), and
26  * <li> any remote object in the <code>MarshalledObject</code> is
27  * represented by a serialized instance of its stub.
28  * </ul>
29  *
30  * <p>When copy of the object is retrieved (via the <code>get</code> method),
31  * if the class is not available locally, it will be loaded from the
32  * appropriate location (specified the URL annotated with the class descriptor
33  * when the class was serialized.
34  *
35  * <p><code>MarshalledObject</code> facilitates passing objects in RMI calls
36  * that are not automatically deserialized immediately by the remote peer.
37  *
38  * @version 1.33, 12/19/03
39  * @author Ann Wollrath
40  * @author Peter Jones
41  * @since 1.2
42  */

43 public final class MarshalledObject implements Serializable {
44     /**
45      * @serial Bytes of serialized representation. If <code>objBytes</code> is
46      * <code>null</code> then the object marshalled was a <code>null</code>
47      * reference.
48      */

49     private byte[] objBytes = null;
50
51     /**
52      * @serial Bytes of location annotations, which are ignored by
53      * <code>equals</code>. If <code>locBytes</code> is null, there were no
54      * non-<code>null</code> annotations during marshalling.
55      */

56     private byte[] locBytes = null;
57
58     /**
59      * @serial Stored hash code of contained object.
60      *
61      * @see #hashCode
62      */

63     private int hash;
64
65     /** Indicate compatibility with 1.2 version of class. */
66     private static final long serialVersionUID = 8988374069173025854L;
67
68     /**
69      * Creates a new <code>MarshalledObject</code> that contains the
70      * serialized representation of the current state of the supplied object.
71      * The object is serialized with the semantics used for marshaling
72      * parameters for RMI calls.
73      *
74      * @param obj the object to be serialized (must be serializable)
75      * @exception IOException if an <code>IOException</code> occurs; an
76      * <code>IOException</code> may occur if <code>obj</code> is not
77      * serializable.
78      * @since 1.2
79      */

80     public MarshalledObject(Object JavaDoc obj)
81     throws java.io.IOException JavaDoc
82     {
83     if (obj == null) {
84         hash = 13;
85         return;
86     }
87
88     ByteArrayOutputStream bout = new ByteArrayOutputStream();
89     ByteArrayOutputStream lout = new ByteArrayOutputStream();
90     MarshalledObjectOutputStream out =
91         new MarshalledObjectOutputStream(bout, lout);
92     out.writeObject(obj);
93     out.flush();
94     objBytes = bout.toByteArray();
95     // locBytes is null if no annotations
96
locBytes = (out.hadAnnotations() ? lout.toByteArray() : null);
97
98     /*
99      * Calculate hash from the marshalled representation of object
100      * so the hashcode will be comparable when sent between VMs.
101      */

102     int h = 0;
103     for (int i = 0; i < objBytes.length; i++) {
104         h = 31 * h + objBytes[i];
105     }
106     hash = h;
107     }
108
109     /**
110      * Returns a new copy of the contained marshalledobject. The internal
111      * representation is deserialized with the semantics used for
112      * unmarshaling paramters for RMI calls.
113      *
114      * @return a copy of the contained object
115      * @exception IOException if an <code>IOException</code> occurs while
116      * deserializing the object from its internal representation.
117      * @exception ClassNotFoundException if a
118      * <code>ClassNotFoundException</code> occurs while deserializing the
119      * object from its internal representation.
120      * could not be found
121      * @since 1.2
122      */

123     public Object JavaDoc get()
124     throws java.io.IOException JavaDoc, java.lang.ClassNotFoundException JavaDoc
125     {
126     if (objBytes == null) // must have been a null object
127
return null;
128
129     ByteArrayInputStream bin = new ByteArrayInputStream(objBytes);
130     // locBytes is null if no annotations
131
ByteArrayInputStream lin =
132         (locBytes == null ? null : new ByteArrayInputStream(locBytes));
133     MarshalledObjectInputStream in =
134         new MarshalledObjectInputStream(bin, lin);
135     Object JavaDoc obj = in.readObject();
136     in.close();
137     return obj;
138     }
139
140     /**
141      * Return a hash code for this <code>MarshalledObject</code>.
142      *
143      * @return a hash code
144      */

145     public int hashCode() {
146     return hash;
147     }
148
149     /**
150      * Compares this <code>MarshalledObject</code> to another object.
151      * Returns true if and only if the argument refers to a
152      * <code>MarshalledObject</code> that contains exactly the same
153      * serialized representation of an object as this one does. The
154      * comparison ignores any class codebase annotation, meaning that
155      * two objects are equivalent if they have the same serialized
156      * representation <i>except</i> for the codebase of each class
157      * in the serialized representation.
158      *
159      * @param obj the object to compare with this <code>MarshalledObject</code>
160      * @return <code>true</code> if the argument contains an equaivalent
161      * serialized object; <code>false</code> otherwise
162      * @since 1.2
163      */

164     public boolean equals(Object JavaDoc obj) {
165     if (obj == this)
166         return true;
167
168     if (obj != null && obj instanceof MarshalledObject JavaDoc) {
169         MarshalledObject JavaDoc other = (MarshalledObject JavaDoc) obj;
170
171         // if either is a ref to null, both must be
172
if (objBytes == null || other.objBytes == null)
173         return objBytes == other.objBytes;
174
175         // quick, easy test
176
if (objBytes.length != other.objBytes.length)
177         return false;
178
179         //!! There is talk about adding an array comparision method
180
//!! at 1.2 -- if so, this should be rewritten. -arnold
181
for (int i = 0; i < objBytes.length; ++i) {
182         if (objBytes[i] != other.objBytes[i])
183             return false;
184         }
185         return true;
186     } else {
187         return false;
188     }
189     }
190
191     /**
192      * This class is used to marshal objects for
193      * <code>MarshalledObject</code>. It places the location annotations
194      * to one side so that two <code>MarshalledObject</code>s can be
195      * compared for equality if they differ only in location
196      * annotations. Objects written using this stream should be read back
197      * from a <code>MarshalledObjectInputStream</code>.
198      *
199      * @see java.rmi.MarshalledObject
200      * @see MarshalledObjectInputStream
201      */

202     private static class MarshalledObjectOutputStream
203         extends MarshalOutputStream
204     {
205     /** The stream on which location objects are written. */
206     private ObjectOutputStream locOut;
207
208     /** <code>true</code> if non-<code>null</code> annotations are
209          * written.
210      */

211     private boolean hadAnnotations;
212
213     /**
214      * Creates a new <code>MarshalledObjectOutputStream</code> whose
215      * non-location bytes will be written to <code>objOut</code> and whose
216      * location annotations (if any) will be written to
217      * <code>locOut</code>.
218      */

219     MarshalledObjectOutputStream(OutputStream objOut, OutputStream locOut)
220         throws IOException
221     {
222         super(objOut);
223         this.useProtocolVersion(ObjectStreamConstants.PROTOCOL_VERSION_2);
224         this.locOut = new ObjectOutputStream(locOut);
225         hadAnnotations = false;
226     }
227
228     /**
229      * Returns <code>true</code> if any non-<code>null</code> location
230      * annotations have been written to this stream.
231      */

232     boolean hadAnnotations() {
233         return hadAnnotations;
234     }
235
236     /**
237      * Overrides MarshalOutputStream.writeLocation implementation to write
238      * annotations to the location stream.
239      */

240     protected void writeLocation(String JavaDoc loc) throws IOException {
241         hadAnnotations |= (loc != null);
242         locOut.writeObject(loc);
243     }
244     
245     
246     public void flush() throws IOException {
247         super.flush();
248         locOut.flush();
249     }
250     }
251     
252     /**
253      * The counterpart to <code>MarshalledObjectOutputStream</code>.
254      *
255      * @see MarshalledObjectOutputStream
256      */

257     private static class MarshalledObjectInputStream
258         extends MarshalInputStream
259     {
260     /**
261      * The stream from which annotations will be read. If this is
262      * <code>null</code>, then all annotations were <code>null</code>.
263      */

264     private ObjectInputStream locIn;
265
266     /**
267      * Creates a new <code>MarshalledObjectInputStream</code> that
268      * reads its objects from <code>objIn</code> and annotations
269      * from <code>locIn</code>. If <code>locIn</code> is
270      * <code>null</code>, then all annotations will be
271      * <code>null</code>.
272      */

273     MarshalledObjectInputStream(InputStream objIn, InputStream locIn)
274         throws IOException
275     {
276         super(objIn);
277         this.locIn = (locIn == null ? null : new ObjectInputStream(locIn));
278     }
279
280     /**
281      * Overrides MarshalInputStream.readLocation to return locations from
282      * the stream we were given, or <code>null</code> if we were given a
283      * <code>null</code> location stream.
284      */

285     protected Object JavaDoc readLocation()
286         throws IOException, ClassNotFoundException JavaDoc
287     {
288         return (locIn == null ? null : locIn.readObject());
289     }
290     }
291
292 }
293
Popular Tags