1 /* 2 * Copyright (c) 1997, 2005, 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; 27 28 import java.io.ByteArrayInputStream; 29 import java.io.ByteArrayOutputStream; 30 import java.io.IOException; 31 import java.io.InputStream; 32 import java.io.ObjectInputStream; 33 import java.io.ObjectOutputStream; 34 import java.io.ObjectStreamConstants; 35 import java.io.OutputStream; 36 import java.io.Serializable; 37 import sun.rmi.server.MarshalInputStream; 38 import sun.rmi.server.MarshalOutputStream; 39 40 /** 41 * A <code>MarshalledObject</code> contains a byte stream with the serialized 42 * representation of an object given to its constructor. The <code>get</code> 43 * method returns a new copy of the original object, as deserialized from 44 * the contained byte stream. The contained object is serialized and 45 * deserialized with the same serialization semantics used for marshaling 46 * and unmarshaling parameters and return values of RMI calls: When the 47 * serialized form is created: 48 * 49 * <ul> 50 * <li> classes are annotated with a codebase URL from where the class 51 * can be loaded (if available), and 52 * <li> any remote object in the <code>MarshalledObject</code> is 53 * represented by a serialized instance of its stub. 54 * </ul> 55 * 56 * <p>When copy of the object is retrieved (via the <code>get</code> method), 57 * if the class is not available locally, it will be loaded from the 58 * appropriate location (specified the URL annotated with the class descriptor 59 * when the class was serialized. 60 * 61 * <p><code>MarshalledObject</code> facilitates passing objects in RMI calls 62 * that are not automatically deserialized immediately by the remote peer. 63 * 64 * @param <T> the type of the object contained in this 65 * <code>MarshalledObject</code> 66 * 67 * @author Ann Wollrath 68 * @author Peter Jones 69 * @since 1.2 70 */ 71 public final class MarshalledObject<T> implements Serializable { 72 /** 73 * @serial Bytes of serialized representation. If <code>objBytes</code> is 74 * <code>null</code> then the object marshalled was a <code>null</code> 75 * reference. 76 */ 77 private byte[] objBytes = null; 78 79 /** 80 * @serial Bytes of location annotations, which are ignored by 81 * <code>equals</code>. If <code>locBytes</code> is null, there were no 82 * non-<code>null</code> annotations during marshalling. 83 */ 84 private byte[] locBytes = null; 85 86 /** 87 * @serial Stored hash code of contained object. 88 * 89 * @see #hashCode 90 */ 91 private int hash; 92 93 /** Indicate compatibility with 1.2 version of class. */ 94 private static final long serialVersionUID = 8988374069173025854L; 95 96 /** 97 * Creates a new <code>MarshalledObject</code> that contains the 98 * serialized representation of the current state of the supplied object. 99 * The object is serialized with the semantics used for marshaling 100 * parameters for RMI calls. 101 * 102 * @param obj the object to be serialized (must be serializable) 103 * @exception IOException if an <code>IOException</code> occurs; an 104 * <code>IOException</code> may occur if <code>obj</code> is not 105 * serializable. 106 * @since 1.2 107 */ 108 public MarshalledObject(T obj) throws IOException { 109 if (obj == null) { 110 hash = 13; 111 return; 112 } 113 114 ByteArrayOutputStream bout = new ByteArrayOutputStream(); 115 ByteArrayOutputStream lout = new ByteArrayOutputStream(); 116 MarshalledObjectOutputStream out = 117 new MarshalledObjectOutputStream(bout, lout); 118 out.writeObject(obj); 119 out.flush(); 120 objBytes = bout.toByteArray(); 121 // locBytes is null if no annotations 122 locBytes = (out.hadAnnotations() ? lout.toByteArray() : null); 123 124 /* 125 * Calculate hash from the marshalled representation of object 126 * so the hashcode will be comparable when sent between VMs. 127 */ 128 int h = 0; 129 for (int i = 0; i < objBytes.length; i++) { 130 h = 31 * h + objBytes[i]; 131 } 132 hash = h; 133 } 134 135 /** 136 * Returns a new copy of the contained marshalledobject. The internal 137 * representation is deserialized with the semantics used for 138 * unmarshaling paramters for RMI calls. 139 * 140 * @return a copy of the contained object 141 * @exception IOException if an <code>IOException</code> occurs while 142 * deserializing the object from its internal representation. 143 * @exception ClassNotFoundException if a 144 * <code>ClassNotFoundException</code> occurs while deserializing the 145 * object from its internal representation. 146 * could not be found 147 * @since 1.2 148 */ 149 public T get() throws IOException, ClassNotFoundException { 150 if (objBytes == null) // must have been a null object 151 return null; 152 153 ByteArrayInputStream bin = new ByteArrayInputStream(objBytes); 154 // locBytes is null if no annotations 155 ByteArrayInputStream lin = 156 (locBytes == null ? null : new ByteArrayInputStream(locBytes)); 157 MarshalledObjectInputStream in = 158 new MarshalledObjectInputStream(bin, lin); 159 @SuppressWarnings("unchecked") 160 T obj = (T) in.readObject(); 161 in.close(); 162 return obj; 163 } 164 165 /** 166 * Return a hash code for this <code>MarshalledObject</code>. 167 * 168 * @return a hash code 169 */ 170 public int hashCode() { 171 return hash; 172 } 173 174 /** 175 * Compares this <code>MarshalledObject</code> to another object. 176 * Returns true if and only if the argument refers to a 177 * <code>MarshalledObject</code> that contains exactly the same 178 * serialized representation of an object as this one does. The 179 * comparison ignores any class codebase annotation, meaning that 180 * two objects are equivalent if they have the same serialized 181 * representation <i>except</i> for the codebase of each class 182 * in the serialized representation. 183 * 184 * @param obj the object to compare with this <code>MarshalledObject</code> 185 * @return <code>true</code> if the argument contains an equaivalent 186 * serialized object; <code>false</code> otherwise 187 * @since 1.2 188 */ 189 public boolean equals(Object obj) { 190 if (obj == this) 191 return true; 192 193 if (obj != null && obj instanceof MarshalledObject) { 194 MarshalledObject<?> other = (MarshalledObject<?>) obj; 195 196 // if either is a ref to null, both must be 197 if (objBytes == null || other.objBytes == null) 198 return objBytes == other.objBytes; 199 200 // quick, easy test 201 if (objBytes.length != other.objBytes.length) 202 return false; 203 204 //!! There is talk about adding an array comparision method 205 //!! at 1.2 -- if so, this should be rewritten. -arnold 206 for (int i = 0; i < objBytes.length; ++i) { 207 if (objBytes[i] != other.objBytes[i]) 208 return false; 209 } 210 return true; 211 } else { 212 return false; 213 } 214 } 215 216 /** 217 * This class is used to marshal objects for 218 * <code>MarshalledObject</code>. It places the location annotations 219 * to one side so that two <code>MarshalledObject</code>s can be 220 * compared for equality if they differ only in location 221 * annotations. Objects written using this stream should be read back 222 * from a <code>MarshalledObjectInputStream</code>. 223 * 224 * @see java.rmi.MarshalledObject 225 * @see MarshalledObjectInputStream 226 */ 227 private static class MarshalledObjectOutputStream 228 extends MarshalOutputStream 229 { 230 /** The stream on which location objects are written. */ 231 private ObjectOutputStream locOut; 232 233 /** <code>true</code> if non-<code>null</code> annotations are 234 * written. 235 */ 236 private boolean hadAnnotations; 237 238 /** 239 * Creates a new <code>MarshalledObjectOutputStream</code> whose 240 * non-location bytes will be written to <code>objOut</code> and whose 241 * location annotations (if any) will be written to 242 * <code>locOut</code>. 243 */ 244 MarshalledObjectOutputStream(OutputStream objOut, OutputStream locOut) 245 throws IOException 246 { 247 super(objOut); 248 this.useProtocolVersion(ObjectStreamConstants.PROTOCOL_VERSION_2); 249 this.locOut = new ObjectOutputStream(locOut); 250 hadAnnotations = false; 251 } 252 253 /** 254 * Returns <code>true</code> if any non-<code>null</code> location 255 * annotations have been written to this stream. 256 */ 257 boolean hadAnnotations() { 258 return hadAnnotations; 259 } 260 261 /** 262 * Overrides MarshalOutputStream.writeLocation implementation to write 263 * annotations to the location stream. 264 */ 265 protected void writeLocation(String loc) throws IOException { 266 hadAnnotations |= (loc != null); 267 locOut.writeObject(loc); 268 } 269 270 271 public void flush() throws IOException { 272 super.flush(); 273 locOut.flush(); 274 } 275 } 276 277 /** 278 * The counterpart to <code>MarshalledObjectOutputStream</code>. 279 * 280 * @see MarshalledObjectOutputStream 281 */ 282 private static class MarshalledObjectInputStream 283 extends MarshalInputStream 284 { 285 /** 286 * The stream from which annotations will be read. If this is 287 * <code>null</code>, then all annotations were <code>null</code>. 288 */ 289 private ObjectInputStream locIn; 290 291 /** 292 * Creates a new <code>MarshalledObjectInputStream</code> that 293 * reads its objects from <code>objIn</code> and annotations 294 * from <code>locIn</code>. If <code>locIn</code> is 295 * <code>null</code>, then all annotations will be 296 * <code>null</code>. 297 */ 298 MarshalledObjectInputStream(InputStream objIn, InputStream locIn) 299 throws IOException 300 { 301 super(objIn); 302 this.locIn = (locIn == null ? null : new ObjectInputStream(locIn)); 303 } 304 305 /** 306 * Overrides MarshalInputStream.readLocation to return locations from 307 * the stream we were given, or <code>null</code> if we were given a 308 * <code>null</code> location stream. 309 */ 310 protected Object readLocation() 311 throws IOException, ClassNotFoundException 312 { 313 return (locIn == null ? null : locIn.readObject()); 314 } 315 } 316 317 }