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.Field;
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.StringCodecImpl;
066
067 /**
068 * @author Franck WOLFF
069 */
070 public 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 }