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