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 */
022 package org.granite.messaging.jmf;
023
024 import java.io.IOException;
025 import java.lang.reflect.InvocationTargetException;
026 import java.util.ArrayList;
027 import java.util.Arrays;
028 import java.util.HashMap;
029 import java.util.List;
030 import java.util.Map;
031
032 import org.granite.messaging.jmf.codec.BijectiveCodec;
033 import org.granite.messaging.jmf.codec.ConditionalObjectCodec;
034 import org.granite.messaging.jmf.codec.ExtendedObjectCodec;
035 import org.granite.messaging.jmf.codec.PrimitiveCodec;
036 import org.granite.messaging.jmf.codec.StandardCodec;
037 import org.granite.messaging.jmf.codec.std.BooleanCodec;
038 import org.granite.messaging.jmf.codec.std.ByteCodec;
039 import org.granite.messaging.jmf.codec.std.CharacterCodec;
040 import org.granite.messaging.jmf.codec.std.DoubleCodec;
041 import org.granite.messaging.jmf.codec.std.FloatCodec;
042 import org.granite.messaging.jmf.codec.std.IntegerCodec;
043 import org.granite.messaging.jmf.codec.std.LongCodec;
044 import org.granite.messaging.jmf.codec.std.NullCodec;
045 import org.granite.messaging.jmf.codec.std.ShortCodec;
046 import org.granite.messaging.jmf.codec.std.StringCodec;
047 import org.granite.messaging.jmf.codec.std.impl.ArrayCodecImpl;
048 import org.granite.messaging.jmf.codec.std.impl.ArrayListCodecImpl;
049 import org.granite.messaging.jmf.codec.std.impl.BigDecimalCodecImpl;
050 import org.granite.messaging.jmf.codec.std.impl.BigIntegerCodecImpl;
051 import org.granite.messaging.jmf.codec.std.impl.BooleanCodecImpl;
052 import org.granite.messaging.jmf.codec.std.impl.ByteCodecImpl;
053 import org.granite.messaging.jmf.codec.std.impl.CharacterCodecImpl;
054 import org.granite.messaging.jmf.codec.std.impl.ClassCodecImpl;
055 import org.granite.messaging.jmf.codec.std.impl.DateCodecImpl;
056 import org.granite.messaging.jmf.codec.std.impl.DoubleCodecImpl;
057 import org.granite.messaging.jmf.codec.std.impl.EnumCodecImpl;
058 import org.granite.messaging.jmf.codec.std.impl.FloatCodecImpl;
059 import org.granite.messaging.jmf.codec.std.impl.HashMapCodecImpl;
060 import org.granite.messaging.jmf.codec.std.impl.HashSetCodecImpl;
061 import org.granite.messaging.jmf.codec.std.impl.IntegerCodecImpl;
062 import org.granite.messaging.jmf.codec.std.impl.LongCodecImpl;
063 import org.granite.messaging.jmf.codec.std.impl.NullCodecImpl;
064 import org.granite.messaging.jmf.codec.std.impl.ObjectCodecImpl;
065 import org.granite.messaging.jmf.codec.std.impl.ShortCodecImpl;
066 import org.granite.messaging.jmf.codec.std.impl.SqlDateCodecImpl;
067 import org.granite.messaging.jmf.codec.std.impl.SqlTimeCodecImpl;
068 import org.granite.messaging.jmf.codec.std.impl.SqlTimestampCodecImpl;
069 import org.granite.messaging.jmf.codec.std.impl.StringCodecImpl;
070 import org.granite.messaging.reflect.Property;
071
072 /**
073 * @author Franck WOLFF
074 */
075 public 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 }