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.IOException; 024import java.lang.reflect.Field; 025import java.util.ArrayList; 026import java.util.Arrays; 027import java.util.HashMap; 028import java.util.List; 029import java.util.Map; 030 031import org.granite.messaging.jmf.codec.BijectiveCodec; 032import org.granite.messaging.jmf.codec.ConditionalObjectCodec; 033import org.granite.messaging.jmf.codec.ExtendedObjectCodec; 034import org.granite.messaging.jmf.codec.PrimitiveCodec; 035import org.granite.messaging.jmf.codec.StandardCodec; 036import org.granite.messaging.jmf.codec.std.BooleanCodec; 037import org.granite.messaging.jmf.codec.std.ByteCodec; 038import org.granite.messaging.jmf.codec.std.CharacterCodec; 039import org.granite.messaging.jmf.codec.std.DoubleCodec; 040import org.granite.messaging.jmf.codec.std.FloatCodec; 041import org.granite.messaging.jmf.codec.std.IntegerCodec; 042import org.granite.messaging.jmf.codec.std.LongCodec; 043import org.granite.messaging.jmf.codec.std.NullCodec; 044import org.granite.messaging.jmf.codec.std.ShortCodec; 045import org.granite.messaging.jmf.codec.std.StringCodec; 046import org.granite.messaging.jmf.codec.std.impl.ArrayCodecImpl; 047import org.granite.messaging.jmf.codec.std.impl.ArrayListCodecImpl; 048import org.granite.messaging.jmf.codec.std.impl.BigDecimalCodecImpl; 049import org.granite.messaging.jmf.codec.std.impl.BigIntegerCodecImpl; 050import org.granite.messaging.jmf.codec.std.impl.BooleanCodecImpl; 051import org.granite.messaging.jmf.codec.std.impl.ByteCodecImpl; 052import org.granite.messaging.jmf.codec.std.impl.CharacterCodecImpl; 053import org.granite.messaging.jmf.codec.std.impl.ClassCodecImpl; 054import org.granite.messaging.jmf.codec.std.impl.DateCodecImpl; 055import org.granite.messaging.jmf.codec.std.impl.DoubleCodecImpl; 056import org.granite.messaging.jmf.codec.std.impl.EnumCodecImpl; 057import org.granite.messaging.jmf.codec.std.impl.FloatCodecImpl; 058import org.granite.messaging.jmf.codec.std.impl.HashMapCodecImpl; 059import org.granite.messaging.jmf.codec.std.impl.HashSetCodecImpl; 060import org.granite.messaging.jmf.codec.std.impl.IntegerCodecImpl; 061import org.granite.messaging.jmf.codec.std.impl.LongCodecImpl; 062import org.granite.messaging.jmf.codec.std.impl.NullCodecImpl; 063import org.granite.messaging.jmf.codec.std.impl.ObjectCodecImpl; 064import org.granite.messaging.jmf.codec.std.impl.ShortCodecImpl; 065import org.granite.messaging.jmf.codec.std.impl.StringCodecImpl; 066 067/** 068 * @author Franck WOLFF 069 */ 070public class DefaultCodecRegistry implements CodecRegistry { 071 072 private static final int[] UNPARAMETERIZED_JMF_TYPES = new int[256]; 073 static { 074 for (int parameterizedJmfType = 0; parameterizedJmfType < 256; parameterizedJmfType++) { 075 int jmfType; 076 077 if ((parameterizedJmfType & 0x08) == 0x00) 078 jmfType = (parameterizedJmfType & 0x07); 079 else if ((parameterizedJmfType & 0x18) == 0x08) 080 jmfType = (parameterizedJmfType & 0x0F); 081 else if ((parameterizedJmfType & 0x38) == 0x18) 082 jmfType = (parameterizedJmfType & 0x1F); 083 else if ((parameterizedJmfType & 0x78) == 0x38) 084 jmfType = (parameterizedJmfType & 0x3F); 085 else 086 jmfType = parameterizedJmfType; 087 088 UNPARAMETERIZED_JMF_TYPES[parameterizedJmfType] = jmfType; 089 } 090 } 091 092 private NullCodec nullCodec; 093 094 private BooleanCodec booleanCodec; 095 private CharacterCodec characterCodec; 096 private ByteCodec byteCodec; 097 private ShortCodec shortCodec; 098 private IntegerCodec integerCodec; 099 private LongCodec longCodec; 100 private FloatCodec floatCodec; 101 private DoubleCodec doubleCodec; 102 private StringCodec stringCodec; 103 104 private final Map<Integer, StandardCodec<?>> typeToCodec = new HashMap<Integer, StandardCodec<?>>(); 105 private final Map<Class<?>, StandardCodec<?>> classToCodec = new HashMap<Class<?>, StandardCodec<?>>(); 106 private final List<ConditionalObjectCodec> conditionalObjectCodecs = new ArrayList<ConditionalObjectCodec>(); 107 private final Map<Class<?>, PrimitiveFieldCodec> primitiveFieldCodecs = new HashMap<Class<?>, PrimitiveFieldCodec>(); 108 109 private final List<ExtendedObjectCodec> extendedCodecs; 110 111 public DefaultCodecRegistry() { 112 this(null); 113 } 114 115 public DefaultCodecRegistry(List<ExtendedObjectCodec> extendedCodecs) { 116 this.extendedCodecs = (extendedCodecs != null ? extendedCodecs : new ArrayList<ExtendedObjectCodec>()); 117 118 List<StandardCodec<?>> standardCodecs = getStandardCodecs(); 119 for (StandardCodec<?> codec : standardCodecs) { 120 121 if (codec instanceof BijectiveCodec) { 122 if (codec instanceof PrimitiveCodec) { 123 assertNull(classToCodec.put(((PrimitiveCodec<?>)codec).getPrimitiveClass(), codec)); 124 assertNull(typeToCodec.put(((PrimitiveCodec<?>)codec).getPrimitiveType(), codec)); 125 126 switch (((PrimitiveCodec<?>)codec).getPrimitiveType()) { 127 case JMF_BOOLEAN: initBooleanCodec((BooleanCodec)codec); break; 128 case JMF_CHARACTER: initCharacterCodec((CharacterCodec)codec); break; 129 case JMF_BYTE: initByteCodec((ByteCodec)codec); break; 130 case JMF_SHORT: initShortCodec((ShortCodec)codec); break; 131 case JMF_INTEGER: initIntegerCodec((IntegerCodec)codec); break; 132 case JMF_LONG: initLongCodec((LongCodec)codec); break; 133 case JMF_FLOAT: initFloatCodec((FloatCodec)codec); break; 134 case JMF_DOUBLE: initDoubleCodec((DoubleCodec)codec); break; 135 } 136 } 137 138 assertNull(classToCodec.put(((BijectiveCodec<?>)codec).getObjectClass(), codec)); 139 assertNull(typeToCodec.put(codec.getObjectType(), codec)); 140 141 if (codec.getObjectType() == JMF_STRING) 142 initStringCodec((StringCodec)codec); 143 else if (codec.getObjectType() == JMF_NULL) 144 initNullCodec((NullCodec)codec); 145 } 146 else if (codec instanceof ConditionalObjectCodec) { 147 assertNull(typeToCodec.put(codec.getObjectType(), codec)); 148 conditionalObjectCodecs.add((ConditionalObjectCodec)codec); 149 } 150 else 151 throw new JMFConfigurationException("Codec must implement BijectiveCodec or ConditionalObjectCodec: " + codec); 152 } 153 154 checkPrimitiveCodecs(); 155 } 156 157 public NullCodec getNullCodec() { 158 return nullCodec; 159 } 160 161 public BooleanCodec getBooleanCodec() { 162 return booleanCodec; 163 } 164 165 public CharacterCodec getCharacterCodec() { 166 return characterCodec; 167 } 168 169 public ByteCodec getByteCodec() { 170 return byteCodec; 171 } 172 173 public ShortCodec getShortCodec() { 174 return shortCodec; 175 } 176 177 public IntegerCodec getIntegerCodec() { 178 return integerCodec; 179 } 180 181 public LongCodec getLongCodec() { 182 return longCodec; 183 } 184 185 public FloatCodec getFloatCodec() { 186 return floatCodec; 187 } 188 189 public DoubleCodec getDoubleCodec() { 190 return doubleCodec; 191 } 192 193 public StringCodec getStringCodec() { 194 return stringCodec; 195 } 196 197 @SuppressWarnings("unchecked") 198 public <T> StandardCodec<T> getCodec(int jmfType) { 199 return (StandardCodec<T>)typeToCodec.get(jmfType); 200 } 201 202 @SuppressWarnings("unchecked") 203 public <T> StandardCodec<T> getCodec(Object v) { 204 Class<?> cls = (v != null ? v.getClass() : null); 205 StandardCodec<T> codec = (StandardCodec<T>)classToCodec.get(cls); 206 if (codec == null) { 207 for (ConditionalObjectCodec condCodec : conditionalObjectCodecs) { 208 if (condCodec.canEncode(v)) { 209 codec = (StandardCodec<T>)condCodec; 210 break; 211 } 212 } 213 } 214 return codec; 215 } 216 217 public ExtendedObjectCodec findExtendedEncoder(ExtendedObjectOutput out, Object v) { 218 for (ExtendedObjectCodec c : extendedCodecs) { 219 if (c.canEncode(out, v)) 220 return c; 221 } 222 return null; 223 } 224 225 public ExtendedObjectCodec findExtendedDecoder(ExtendedObjectInput in, String className) 226 throws ClassNotFoundException { 227 228 for (ExtendedObjectCodec c : extendedCodecs) { 229 if (c.canDecode(in, className)) 230 return c; 231 } 232 return null; 233 } 234 235 public PrimitiveFieldCodec getPrimitiveFieldCodec(Class<?> fieldCls) { 236 return primitiveFieldCodecs.get(fieldCls); 237 } 238 239 public int extractJmfType(int parameterizedJmfType) { 240 return UNPARAMETERIZED_JMF_TYPES[parameterizedJmfType]; 241 } 242 243 public int jmfTypeOfPrimitiveClass(Class<?> cls) { 244 if (!cls.isPrimitive()) 245 return -1; 246 StandardCodec<?> codec = classToCodec.get(cls); 247 return (codec instanceof PrimitiveCodec ? ((PrimitiveCodec<?>)codec).getPrimitiveType() : -1); 248 } 249 250 public Class<?> primitiveClassOfJmfType(int jmfType) { 251 StandardCodec<?> codec = typeToCodec.get(Integer.valueOf(jmfType)); 252 return (codec instanceof PrimitiveCodec && ((PrimitiveCodec<?>)codec).getPrimitiveType() == jmfType ? ((PrimitiveCodec<?>)codec).getPrimitiveClass() : null); 253 } 254 255 protected List<StandardCodec<?>> getStandardCodecs() { 256 return Arrays.asList((StandardCodec<?>) 257 new NullCodecImpl(), 258 259 new BooleanCodecImpl(), 260 new CharacterCodecImpl(), 261 new ByteCodecImpl(), 262 new ShortCodecImpl(), 263 new IntegerCodecImpl(), 264 new LongCodecImpl(), 265 new FloatCodecImpl(), 266 new DoubleCodecImpl(), 267 268 new BigIntegerCodecImpl(), 269 new BigDecimalCodecImpl(), 270 271 new StringCodecImpl(), 272 273 new DateCodecImpl(), 274 275 new ArrayListCodecImpl(), 276 new HashSetCodecImpl(), 277 new HashMapCodecImpl(), 278 279 new EnumCodecImpl(), 280 new ArrayCodecImpl(), 281 new ClassCodecImpl(), 282 new ObjectCodecImpl() 283 ); 284 } 285 286 private void assertNull(StandardCodec<?> codec) { 287 if (codec != null) 288 throw new JMFConfigurationException("Codec conflict with: " + codec); 289 } 290 291 private void checkPrimitiveCodecs() { 292 if (nullCodec == null) 293 throw new JMFConfigurationException("No Null codec"); 294 295 if (booleanCodec == null) 296 throw new JMFConfigurationException("No Boolean codec"); 297 if (characterCodec == null) 298 throw new JMFConfigurationException("No Character codec"); 299 if (byteCodec == null) 300 throw new JMFConfigurationException("No Byte codec"); 301 if (shortCodec == null) 302 throw new JMFConfigurationException("No Short codec"); 303 if (integerCodec == null) 304 throw new JMFConfigurationException("No Integer codec"); 305 if (longCodec == null) 306 throw new JMFConfigurationException("No Long codec"); 307 if (floatCodec == null) 308 throw new JMFConfigurationException("No Float codec"); 309 if (doubleCodec == null) 310 throw new JMFConfigurationException("No Double codec"); 311 312 if (stringCodec == null) 313 throw new JMFConfigurationException("No String codec"); 314 } 315 316 private void initBooleanCodec(BooleanCodec codec) { 317 booleanCodec = codec; 318 primitiveFieldCodecs.put(booleanCodec.getPrimitiveClass(), new PrimitiveFieldCodec() { 319 public void encodePrimitive(OutputContext ctx, Object v, Field field) throws IllegalAccessException, IOException { 320 booleanCodec.encodePrimitive(ctx, field.getBoolean(v)); 321 } 322 public void decodePrimitive(InputContext ctx, Object v, Field field) throws IllegalAccessException, IOException { 323 field.setBoolean(v, booleanCodec.decodePrimitive(ctx)); 324 } 325 }); 326 } 327 328 private void initCharacterCodec(CharacterCodec codec) { 329 characterCodec = codec; 330 primitiveFieldCodecs.put(characterCodec.getPrimitiveClass(), new PrimitiveFieldCodec() { 331 public void encodePrimitive(OutputContext ctx, Object v, Field field) throws IllegalAccessException, IOException { 332 characterCodec.encodePrimitive(ctx, field.getChar(v)); 333 } 334 public void decodePrimitive(InputContext ctx, Object v, Field field) throws IllegalAccessException, IOException { 335 field.setChar(v, characterCodec.decodePrimitive(ctx)); 336 } 337 }); 338 } 339 340 private void initByteCodec(ByteCodec codec) { 341 byteCodec = codec; 342 primitiveFieldCodecs.put(byteCodec.getPrimitiveClass(), new PrimitiveFieldCodec() { 343 public void encodePrimitive(OutputContext ctx, Object v, Field field) throws IllegalAccessException, IOException { 344 byteCodec.encodePrimitive(ctx, field.getByte(v)); 345 } 346 public void decodePrimitive(InputContext ctx, Object v, Field field) throws IllegalAccessException, IOException { 347 field.setByte(v, byteCodec.decodePrimitive(ctx)); 348 } 349 }); 350 } 351 352 private void initShortCodec(ShortCodec codec) { 353 shortCodec = codec; 354 primitiveFieldCodecs.put(shortCodec.getPrimitiveClass(), new PrimitiveFieldCodec() { 355 public void encodePrimitive(OutputContext ctx, Object v, Field field) throws IllegalAccessException, IOException { 356 shortCodec.encodePrimitive(ctx, field.getShort(v)); 357 } 358 public void decodePrimitive(InputContext ctx, Object v, Field field) throws IllegalAccessException, IOException { 359 field.setShort(v, shortCodec.decodePrimitive(ctx)); 360 } 361 }); 362 } 363 364 private void initIntegerCodec(IntegerCodec codec) { 365 integerCodec = codec; 366 primitiveFieldCodecs.put(integerCodec.getPrimitiveClass(), new PrimitiveFieldCodec() { 367 public void encodePrimitive(OutputContext ctx, Object v, Field field) throws IllegalAccessException, IOException { 368 integerCodec.encodePrimitive(ctx, field.getInt(v)); 369 } 370 public void decodePrimitive(InputContext ctx, Object v, Field field) throws IllegalAccessException, IOException { 371 field.setInt(v, integerCodec.decodePrimitive(ctx)); 372 } 373 }); 374 } 375 376 private void initLongCodec(LongCodec codec) { 377 longCodec = codec; 378 primitiveFieldCodecs.put(longCodec.getPrimitiveClass(), new PrimitiveFieldCodec() { 379 public void encodePrimitive(OutputContext ctx, Object v, Field field) throws IllegalAccessException, IOException { 380 longCodec.encodePrimitive(ctx, field.getLong(v)); 381 } 382 public void decodePrimitive(InputContext ctx, Object v, Field field) throws IllegalAccessException, IOException { 383 field.setLong(v, longCodec.decodePrimitive(ctx)); 384 } 385 }); 386 } 387 388 private void initFloatCodec(FloatCodec codec) { 389 floatCodec = codec; 390 primitiveFieldCodecs.put(floatCodec.getPrimitiveClass(), new PrimitiveFieldCodec() { 391 public void encodePrimitive(OutputContext ctx, Object v, Field field) throws IllegalAccessException, IOException { 392 floatCodec.encodePrimitive(ctx, field.getFloat(v)); 393 } 394 public void decodePrimitive(InputContext ctx, Object v, Field field) throws IllegalAccessException, IOException { 395 field.setFloat(v, floatCodec.decodePrimitive(ctx)); 396 } 397 }); 398 } 399 400 private void initDoubleCodec(DoubleCodec codec) { 401 doubleCodec = codec; 402 primitiveFieldCodecs.put(doubleCodec.getPrimitiveClass(), new PrimitiveFieldCodec() { 403 public void encodePrimitive(OutputContext ctx, Object v, Field field) throws IllegalAccessException, IOException { 404 doubleCodec.encodePrimitive(ctx, field.getDouble(v)); 405 } 406 public void decodePrimitive(InputContext ctx, Object v, Field field) throws IllegalAccessException, IOException { 407 field.setDouble(v, doubleCodec.decodePrimitive(ctx)); 408 } 409 }); 410 } 411 412 private void initStringCodec(StringCodec codec) { 413 stringCodec = codec; 414 } 415 416 private void initNullCodec(NullCodec codec) { 417 nullCodec = codec; 418 } 419}