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 021package org.granite.messaging.jmf; 022 023import java.io.EOFException; 024import java.io.IOException; 025import java.io.InputStream; 026import java.lang.reflect.Field; 027import java.lang.reflect.InvocationTargetException; 028import java.util.ArrayList; 029import java.util.List; 030 031import org.granite.messaging.jmf.codec.StandardCodec; 032import org.granite.messaging.jmf.reflect.Reflection; 033 034/** 035 * @author Franck WOLFF 036 */ 037public 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}