001 /**
002 * GRANITE DATA SERVICES
003 * Copyright (C) 2006-2013 GRANITE DATA SERVICES S.A.S.
004 *
005 * This file is part of the Granite Data Services Platform.
006 *
007 * Granite Data Services is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * Granite Data Services is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
015 * General Public License for more details.
016 *
017 * You should have received a copy of the GNU Lesser General Public
018 * License along with this library; if not, write to the Free Software
019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
020 * USA, or see <http://www.gnu.org/licenses/>.
021 */
022 package org.granite.messaging.jmf;
023
024 import java.io.EOFException;
025 import java.io.IOException;
026 import java.io.InputStream;
027 import java.lang.reflect.InvocationTargetException;
028 import java.util.ArrayList;
029 import java.util.List;
030
031 import org.granite.messaging.annotations.Include;
032 import org.granite.messaging.jmf.codec.StandardCodec;
033 import org.granite.messaging.reflect.NoopWritableProperty;
034 import org.granite.messaging.reflect.Property;
035 import org.granite.messaging.reflect.Reflection;
036
037 /**
038 * @author Franck WOLFF
039 */
040 public class JMFDeserializer implements InputContext {
041
042 ///////////////////////////////////////////////////////////////////////////
043 // Fields
044
045 protected final List<String> storedStrings = new ArrayList<String>(256);
046 protected final List<Object> storedObjects = new ArrayList<Object>(256);
047
048 protected final InputStream inputStream;
049 protected final SharedContext context;
050
051 protected final CodecRegistry codecRegistry;
052
053 ///////////////////////////////////////////////////////////////////////////
054 // Initialization
055
056 public JMFDeserializer(InputStream is, SharedContext context) {
057 this.inputStream = is;
058 this.context = context;
059 this.codecRegistry = context.getCodecRegistry();
060
061 this.storedStrings.addAll(context.getDefaultStoredStrings());
062 }
063
064 ///////////////////////////////////////////////////////////////////////////
065 // ObjectInput implementation
066
067 public boolean readBoolean() throws IOException {
068 return codecRegistry.getBooleanCodec().decodePrimitive(this);
069 }
070
071 public byte readByte() throws IOException {
072 return codecRegistry.getByteCodec().decodePrimitive(this);
073 }
074
075 public int readUnsignedByte() throws IOException {
076 return readByte() & 0xFF;
077 }
078
079 public short readShort() throws IOException {
080 return codecRegistry.getShortCodec().decodePrimitive(this);
081 }
082
083 public int readUnsignedShort() throws IOException {
084 return readShort() & 0xFFFF;
085 }
086
087 public char readChar() throws IOException {
088 return codecRegistry.getCharacterCodec().decodePrimitive(this);
089 }
090
091 public int readInt() throws IOException {
092 return codecRegistry.getIntegerCodec().decodePrimitive(this);
093 }
094
095 public long readLong() throws IOException {
096 return codecRegistry.getLongCodec().decodePrimitive(this);
097 }
098
099 public float readFloat() throws IOException {
100 return codecRegistry.getFloatCodec().decodePrimitive(this);
101 }
102
103 public double readDouble() throws IOException {
104 return codecRegistry.getDoubleCodec().decodePrimitive(this);
105 }
106
107 public String readUTF() throws IOException {
108 int parameterizedJmfType = safeRead();
109
110 if (parameterizedJmfType == JMF_NULL)
111 return (String)codecRegistry.getNullCodec().decode(this, parameterizedJmfType);
112
113 return codecRegistry.getStringCodec().decode(this, parameterizedJmfType);
114 }
115
116 public Object readObject() throws ClassNotFoundException, IOException {
117 int parameterizedJmfType = safeRead();
118 int jmfType = codecRegistry.extractJmfType(parameterizedJmfType);
119
120 StandardCodec<?> codec = codecRegistry.getCodec(jmfType);
121 if (codec == null)
122 throw new JMFEncodingException("Unsupported JMF type: " + jmfType);
123
124 try {
125 return codec.decode(this, parameterizedJmfType);
126 }
127 catch (InvocationTargetException e) {
128 throw new IOException(e.getTargetException());
129 }
130 catch (IllegalAccessException e) {
131 throw new IOException(e);
132 }
133 catch (InstantiationException e) {
134 throw new IOException(e);
135 }
136 catch (NoSuchMethodException e) {
137 throw new IOException(e);
138 }
139 }
140
141 public int available() throws IOException {
142 return inputStream.available();
143 }
144
145 public void close() throws IOException {
146 inputStream.close();
147 }
148
149 ///////////////////////////////////////////////////////////////////////////
150 // ObjectInput implementation (unsupported, marked at deprecated)
151
152 @Deprecated
153 public int read() throws IOException {
154 throw new UnsupportedOperationException("Use readByte()");
155 }
156
157 @Deprecated
158 public int read(byte[] b) throws IOException {
159 throw new UnsupportedOperationException("Use (byte[])readObject()");
160 }
161
162 @Deprecated
163 public int read(byte[] b, int off, int len) throws IOException {
164 throw new UnsupportedOperationException("Use (byte[])readObject()");
165 }
166
167 @Deprecated
168 public void readFully(byte[] b) throws IOException {
169 throw new UnsupportedOperationException("Use (byte[])readObject()");
170 }
171
172 @Deprecated
173 public void readFully(byte[] b, int off, int len) throws IOException {
174 throw new UnsupportedOperationException("Use (byte[])readObject()");
175 }
176
177 @Deprecated
178 public String readLine() throws IOException {
179 throw new UnsupportedOperationException("Use readUTF()");
180 }
181
182 @Deprecated
183 public int skipBytes(int n) throws IOException {
184 throw new UnsupportedOperationException();
185 }
186
187 @Deprecated
188 public long skip(long n) throws IOException {
189 throw new UnsupportedOperationException();
190 }
191
192 ///////////////////////////////////////////////////////////////////////////
193 // InputContext implementation
194
195 public SharedContext getSharedContext() {
196 return context;
197 }
198
199 public InputStream getInputStream() {
200 return inputStream;
201 }
202
203 public int safeRead() throws IOException {
204 int b = inputStream.read();
205 if (b == -1)
206 throw new EOFException();
207 return b;
208 }
209
210 public void safeReadFully(byte[] b) throws IOException {
211 safeReadFully(b, 0, b.length);
212 }
213
214 public void safeReadFully(byte[] b, int off, int len) throws IOException {
215 if (off < 0 || len < 0 || off + len > b.length)
216 throw new IndexOutOfBoundsException("b.length=" + b.length + ", off=" + off + ", len" + len);
217
218 if (len == 0)
219 return;
220
221 do {
222 int read = inputStream.read(b, off, len);
223 if (read == -1)
224 throw new EOFException();
225 off += read;
226 len -= read;
227 }
228 while (len > 0);
229 }
230
231 public void safeSkip(long n) throws IOException {
232 while (n > 0) {
233 if (inputStream.read() == -1)
234 throw new EOFException();
235 n--;
236 }
237 }
238
239 public int addSharedString(String s) {
240 int index = storedStrings.size();
241 storedStrings.add(index, s);
242 return index;
243 }
244
245 public String getSharedString(int index) {
246 return storedStrings.get(index);
247 }
248
249 public int addSharedObject(Object o) {
250 int index = storedObjects.size();
251 storedObjects.add(index, o);
252 return index;
253 }
254
255 public Object getSharedObject(int index) {
256 Object o = storedObjects.get(index);
257 if (o instanceof UnresolvedSharedObject)
258 throw new JMFUnresolvedSharedObjectException("Unresolved shared object: " + o);
259 return o;
260 }
261
262 public int addUnresolvedSharedObject(String className) {
263 int index = storedObjects.size();
264 storedObjects.add(index, new UnresolvedSharedObject(className, index));
265 return index;
266 }
267
268 public Object setUnresolvedSharedObject(int index, Object o) {
269 Object uso = storedObjects.set(index, o);
270 if (!(uso instanceof UnresolvedSharedObject))
271 throw new JMFUnresolvedSharedObjectException("Not an unresolved shared object: " + uso);
272 return uso;
273 }
274
275 ///////////////////////////////////////////////////////////////////////////
276 // ExtendedObjectInput implementation
277
278 public Reflection getReflection() {
279 return context.getReflection();
280 }
281
282 public String getAlias(String remoteAlias) {
283 return context.getClassName(remoteAlias);
284 }
285
286 public void readAndSetProperty(Object obj, Property property) throws IOException, ClassNotFoundException, IllegalAccessException, InvocationTargetException {
287 if (property.isAnnotationPresent(Include.class) && !property.isWritable())
288 property = new NoopWritableProperty(property.getName(), property.getType());
289
290 if (property.getType().isPrimitive())
291 codecRegistry.getPrimitivePropertyCodec(property.getType()).decodePrimitive(this, obj, property);
292 else
293 property.setObject(obj, readObject());
294 }
295
296 static class UnresolvedSharedObject {
297
298 private final String className;
299 private final int index;
300
301 public UnresolvedSharedObject(String className, int index) {
302 this.className = className;
303 this.index = index;
304 }
305
306 public String getClassName() {
307 return className;
308 }
309
310 public int getIndex() {
311 return index;
312 }
313
314 @Override
315 public String toString() {
316 return UnresolvedSharedObject.class.getName() + " {className=" + className + ", index=" + index + "}";
317 }
318 }
319 }