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