1 /*
2 * JBoss, Home of Professional Open Source
3 * Copyright 2005, JBoss Inc., and individual contributors as indicated
4 * by the @authors tag. See the copyright.txt in the distribution for a
5 * full listing of individual contributors.
6 *
7 * This is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
11 *
12 * This software is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this software; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21 */
22 package org.jboss.invocation;
23
24 import java.io.DataOutputStream;
25 import java.io.ByteArrayInputStream;
26 import java.io.ByteArrayOutputStream;
27 import java.io.IOException;
28 import java.io.ObjectInput;
29 import java.io.ObjectOutput;
30
31 import java.util.Arrays;
32
33 /**
34 * A simple replacement for the RMI MarshalledObject that uses the thread
35 * context class loader for resolving classes and proxies. This currently does
36 * not support class annotations and dynamic class loading.
37 *
38 * @author Scott.Stark@jboss.org
39 * @version $Revision: 37459 $
40 */
41 public class MarshalledValue
42 implements java.io.Externalizable
43 {
44 /** Serial Version Identifier. */
45 private static final long serialVersionUID = -1527598981234110311L;
46
47 /**
48 * The serialized form of the value. If <code>serializedForm</code> is
49 * <code>null</code> then the object marshalled was a <code>null</code>
50 * reference.
51 */
52 private byte[] serializedForm;
53
54 /**
55 * The RMI MarshalledObject hash of the serializedForm array
56 */
57 private int hashCode;
58
59 /**
60 * Exposed for externalization.
61 */
62 public MarshalledValue()
63 {
64 super();
65 }
66
67 public MarshalledValue(Object obj) throws IOException
68 {
69 ByteArrayOutputStream baos = new ByteArrayOutputStream();
70 MarshalledValueOutputStream mvos = new MarshalledValueOutputStream(baos);
71 mvos.writeObject(obj);
72 mvos.flush();
73 serializedForm = baos.toByteArray();
74 mvos.close();
75 // Use the java.rmi.MarshalledObject hash code calculation
76 int hash = 0;
77 for (int i = 0; i < serializedForm.length; i++)
78 {
79 hash = 31 * hash + serializedForm[i];
80 }
81
82 hashCode = hash;
83 }
84
85 public Object get() throws IOException, ClassNotFoundException
86 {
87 if (serializedForm == null)
88 return null;
89
90 ByteArrayInputStream bais = new ByteArrayInputStream(serializedForm);
91 MarshalledValueInputStream mvis = new MarshalledValueInputStream(bais);
92 Object retValue = mvis.readObject();
93 mvis.close();
94 return retValue;
95 }
96
97 public byte[] toByteArray()
98 {
99 return serializedForm;
100 }
101
102 public int size()
103 {
104 int size = serializedForm != null ? serializedForm.length : 0;
105 return size;
106 }
107
108 /**
109 * Return a hash code for the serialized form of the value.
110 *
111 * @return the serialized form value hash.
112 */
113 public int hashCode()
114 {
115 return hashCode;
116 }
117
118 public boolean equals(Object obj)
119 {
120 if( this == obj )
121 return true;
122
123 boolean equals = false;
124 if( obj instanceof MarshalledValue )
125 {
126 MarshalledValue mv = (MarshalledValue) obj;
127 if( serializedForm == mv.serializedForm )
128 {
129 equals = true;
130 }
131 else
132 {
133 equals = Arrays.equals(serializedForm, mv.serializedForm);
134 }
135 }
136 return equals;
137 }
138
139 /**
140 * The object implements the readExternal method to restore its
141 * contents by calling the methods of DataInput for primitive
142 * types and readObject for objects, strings and arrays. The
143 * readExternal method must read the values in the same sequence
144 * and with the same types as were written by writeExternal.
145 *
146 * @param in the stream to read data from in order to restore the object
147 *
148 * @throws IOException if I/O errors occur
149 * @throws ClassNotFoundException If the class for an object being
150 * restored cannot be found.
151 */
152 public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
153 {
154 int length = in.readInt();
155 serializedForm = null;
156 if( length > 0 )
157 {
158 serializedForm = new byte[length];
159 in.readFully(serializedForm);
160 }
161 hashCode = in.readInt();
162 }
163
164 /**
165 * The object implements the writeExternal method to save its contents
166 * by calling the methods of DataOutput for its primitive values or
167 * calling the writeObject method of ObjectOutput for objects, strings,
168 * and arrays.
169 *
170 * @serialData Overriding methods should use this tag to describe
171 * the data layout of this Externalizable object.
172 * List the sequence of element types and, if possible,
173 * relate the element to a public/protected field and/or
174 * method of this Externalizable class.
175 *
176 * @param out the stream to write the object to
177 *
178 * @throws IOException Includes any I/O exceptions that may occur
179 */
180 public void writeExternal(ObjectOutput out) throws IOException
181 {
182 int length = serializedForm != null ? serializedForm.length : 0;
183 out.writeInt(length);
184 if( length > 0 )
185 {
186 out.write(serializedForm);
187 }
188 out.writeInt(hashCode);
189 }
190 }