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