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