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