001/* MarshalledObject.java --
002   Copyright (c) 1996, 1997, 1998, 1999, 2004, 2006 
003   Free Software Foundation, Inc.
004
005This file is part of GNU Classpath.
006
007GNU Classpath is free software; you can redistribute it and/or modify
008it under the terms of the GNU General Public License as published by
009the Free Software Foundation; either version 2, or (at your option)
010any later version.
011 
012GNU Classpath is distributed in the hope that it will be useful, but
013WITHOUT ANY WARRANTY; without even the implied warranty of
014MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
015General Public License for more details.
016
017You should have received a copy of the GNU General Public License
018along with GNU Classpath; see the file COPYING.  If not, write to the
019Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02002110-1301 USA.
021
022Linking this library statically or dynamically with other modules is
023making a combined work based on this library.  Thus, the terms and
024conditions of the GNU General Public License cover the whole
025combination.
026
027As a special exception, the copyright holders of this library give you
028permission to link this library with independent modules to produce an
029executable, regardless of the license terms of these independent
030modules, and to copy and distribute the resulting executable under
031terms of your choice, provided that you also meet, for each linked
032independent module, the terms and conditions of the license of that
033module.  An independent module is a module which is not derived from
034or based on this library.  If you modify this library, you may extend
035this exception to your version of the library, but you are not
036obligated to do so.  If you do not wish to do so, delete this
037exception statement from your version. */
038
039
040package java.rmi;
041
042import gnu.java.rmi.RMIMarshalledObjectInputStream;
043import gnu.java.rmi.RMIMarshalledObjectOutputStream;
044
045import java.io.ByteArrayOutputStream;
046import java.io.IOException;
047import java.io.Serializable;
048
049/**
050 * A <code>MarshalledObject</code> consists of a serialized object which is
051 * marshalled according to the RMI specification.
052 * <p>
053 * An object passed to the constructor is serialized and tagged with the needed
054 * URL to retrieve its class definition for remote usage. If the object is a 
055 * remote reference its stub is serialized instead. The instance of this 
056 * marshalled object can be later retrieved by its <code>get()</code> method.
057 * </p>
058 *
059 * @author unknown
060 */
061public final class MarshalledObject<T>
062  implements Serializable
063{
064  // The following fields are from Java API Documentation "Serialized form"
065  private static final long serialVersionUID = 8988374069173025854L;
066
067  byte[] objBytes;
068  byte[] locBytes;
069  int hash;
070
071  /**
072   * Constructs a <code>MarshalledObject</code> from the given object.
073   * 
074   * @param obj the object to marshal
075   * @throws IOException if an I/O error during serialization occurs.
076   */
077  public MarshalledObject(T obj) throws IOException
078  {
079    ByteArrayOutputStream objStream = new ByteArrayOutputStream();
080    RMIMarshalledObjectOutputStream stream = 
081      new RMIMarshalledObjectOutputStream(objStream);
082    stream.writeObject(obj);
083    stream.flush();
084    objBytes = objStream.toByteArray();
085    locBytes = stream.getLocBytes();
086
087    // The following algorithm of calculating hashCode is similar to String
088    hash = 0;
089    for (int i = 0; i < objBytes.length; i++)
090      hash = hash * 31 + objBytes[i];
091    
092    if (locBytes != null)
093      for (int i = 0; i < locBytes.length; i++)
094        hash = hash * 31 + locBytes[i];
095  }
096
097  /**
098   * Checks if the given object is equal to this marshalled object.
099   * 
100   * <p>Marshalled objects are considered equal if they contain the
101   * same serialized object. Codebase annotations where the class 
102   * definition can be downloaded are ignored in the equals test.</p>
103   *
104   * @param obj the object to compare.   
105   * @return <code>true</code> if equal, <code>false</code> otherwise.
106   */
107  public boolean equals(Object obj)
108  {
109    if (! (obj instanceof MarshalledObject))
110      return false;
111
112    // hashCode even differs, don't do the time-consuming comparisons
113    if (obj.hashCode() != hash)
114      return false;
115
116    MarshalledObject aobj = (MarshalledObject) obj;
117    if (objBytes == null || aobj.objBytes == null)
118      return objBytes == aobj.objBytes;
119    if (objBytes.length != aobj.objBytes.length)
120      return false;
121    for (int i = 0; i < objBytes.length; i++)
122      {
123        if (objBytes[i] != aobj.objBytes[i])
124          return false;
125      }
126    // Ignore comparison of locBytes(annotation)
127    return true;
128  }
129
130  /**
131   * Constructs and returns a copy of the internal serialized object.
132   * 
133   * @return The deserialized object.
134   * 
135   * @throws IOException if an I/O exception occurs during deserialization.
136   * @throws ClassNotFoundException if the class of the deserialized object 
137   * cannot be found.
138   */
139  public T get() throws IOException, ClassNotFoundException
140  {
141    if (objBytes == null)
142      return null;
143    
144    RMIMarshalledObjectInputStream stream = 
145      new RMIMarshalledObjectInputStream(objBytes, locBytes);
146    return (T) stream.readObject();
147  }
148
149  public int hashCode()
150  {
151    return hash;
152  }
153
154}