/** * Copyright 2014 Duan Bingnan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.pinus4j.serializer.codec; import java.io.Serializable; import java.sql.Timestamp; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import org.pinus4j.exceptions.CodecException; import org.pinus4j.serializer.codec.impl.BooleanArrayCodec; import org.pinus4j.serializer.codec.impl.BooleanCodec; import org.pinus4j.serializer.codec.impl.ByteArrayCodec; import org.pinus4j.serializer.codec.impl.ByteCodec; import org.pinus4j.serializer.codec.impl.CalendarArrayCodec; import org.pinus4j.serializer.codec.impl.CalendarCodec; import org.pinus4j.serializer.codec.impl.CharArrayCodec; import org.pinus4j.serializer.codec.impl.CharCodec; import org.pinus4j.serializer.codec.impl.CharacterArrayCodec; import org.pinus4j.serializer.codec.impl.ClassCodec; import org.pinus4j.serializer.codec.impl.DateArrayCodec; import org.pinus4j.serializer.codec.impl.DateCodec; import org.pinus4j.serializer.codec.impl.DoubleArrayCodec; import org.pinus4j.serializer.codec.impl.DoubleCodec; import org.pinus4j.serializer.codec.impl.EnumArrayCodec; import org.pinus4j.serializer.codec.impl.EnumCodec; import org.pinus4j.serializer.codec.impl.ExceptionCodec; import org.pinus4j.serializer.codec.impl.FloatArrayCodec; import org.pinus4j.serializer.codec.impl.FloatCodec; import org.pinus4j.serializer.codec.impl.IntArrayCodec; import org.pinus4j.serializer.codec.impl.IntCodec; import org.pinus4j.serializer.codec.impl.IntegerArrayCodec; import org.pinus4j.serializer.codec.impl.ListCodec; import org.pinus4j.serializer.codec.impl.LongArrayCodec; import org.pinus4j.serializer.codec.impl.LongCodec; import org.pinus4j.serializer.codec.impl.MapCodec; import org.pinus4j.serializer.codec.impl.OBooleanArrayCodec; import org.pinus4j.serializer.codec.impl.OByteArrayCodec; import org.pinus4j.serializer.codec.impl.ODoubleArrayCodec; import org.pinus4j.serializer.codec.impl.OFloatArrayCodec; import org.pinus4j.serializer.codec.impl.OLongArrayCodec; import org.pinus4j.serializer.codec.impl.OShortArrayCodec; import org.pinus4j.serializer.codec.impl.ObjectArrayCodec; import org.pinus4j.serializer.codec.impl.ObjectCodec; import org.pinus4j.serializer.codec.impl.SetCodec; import org.pinus4j.serializer.codec.impl.ShortArrayCodec; import org.pinus4j.serializer.codec.impl.ShortCodec; import org.pinus4j.serializer.codec.impl.SqlDateArrayCodec; import org.pinus4j.serializer.codec.impl.SqlDateCodec; import org.pinus4j.serializer.codec.impl.StringArrayCodec; import org.pinus4j.serializer.codec.impl.StringCodec; import org.pinus4j.serializer.codec.impl.TimestampArrayCodec; import org.pinus4j.serializer.codec.impl.TimestampCodec; import org.pinus4j.utils.BeansUtil; /** * 编码类配置文件. 所以编码类都应该在这里进行配置,每一种编码类支持一种类型的编码. * * @author duanbn * @since 1.1 */ public class CodecConfig { /** * 通过被序列化类型查找编码类. */ public final Map<Class<?>, Codec> classCodecPool = new HashMap<Class<?>, Codec>(); /** * 通过被序列化类型查找编码标志位. */ public final Map<Class<?>, Byte> classCodecTypePool = new HashMap<Class<?>, Byte>(); /** * 通过编码标志位查找编码类. */ public final Map<Byte, Codec> codecTypeCodecPool = new HashMap<Byte, Codec>(); /** * 通过编码标志位查找被被序列化类型. */ public final Map<Byte, Class<?>> codecTypeClassPool = new HashMap<Byte, Class<?>>(); public final ConfigItem[] config = new ConfigItem[] { new ConfigItem(Throwable.class, CodecType.TYPE_EXCEPTION, new ExceptionCodec()), new ConfigItem(Class.class, CodecType.TYPE_CLASS, new ClassCodec()), new ConfigItem(Boolean.TYPE, CodecType.TYPE_BOOLEAN, new BooleanCodec()), new ConfigItem(Boolean.class, CodecType.TYPE_OBOOLEAN, new BooleanCodec()), new ConfigItem(boolean[].class, CodecType.TYPE_ARRAY_BOOLEAN, new BooleanArrayCodec()), new ConfigItem(Boolean[].class, CodecType.TYPE_ARRAY_OBOOLEAN, new OBooleanArrayCodec()), new ConfigItem(Byte.TYPE, CodecType.TYPE_BYTE, new ByteCodec()), new ConfigItem(Byte.class, CodecType.TYPE_OBYTE, new ByteCodec()), new ConfigItem(byte[].class, CodecType.TYPE_ARRAY_BYTE, new ByteArrayCodec()), new ConfigItem(Byte[].class, CodecType.TYPE_ARRAY_OBYTE, new OByteArrayCodec()), new ConfigItem(Character.TYPE, CodecType.TYPE_CHAR, new CharCodec()), new ConfigItem(Character.class, CodecType.TYPE_OCHAR, new CharCodec()), new ConfigItem(char[].class, CodecType.TYPE_ARRAY_CHAR, new CharArrayCodec()), new ConfigItem(Character[].class, CodecType.TYPE_ARRAY_OCHAR, new CharacterArrayCodec()), new ConfigItem(Short.TYPE, CodecType.TYPE_SHORT, new ShortCodec()), new ConfigItem(Short.class, CodecType.TYPE_OSHORT, new ShortCodec()), new ConfigItem(short[].class, CodecType.TYPE_ARRAY_SHORT, new ShortArrayCodec()), new ConfigItem(Short[].class, CodecType.TYPE_ARRAY_OSHORT, new OShortArrayCodec()), new ConfigItem(Integer.TYPE, CodecType.TYPE_INT, new IntCodec()), new ConfigItem(Integer.class, CodecType.TYPE_OINT, new IntCodec()), new ConfigItem(int[].class, CodecType.TYPE_ARRAY_INT, new IntArrayCodec()), new ConfigItem(Integer[].class, CodecType.TYPE_ARRAY_OINT, new IntegerArrayCodec()), new ConfigItem(Long.TYPE, CodecType.TYPE_LONG, new LongCodec()), new ConfigItem(Long.class, CodecType.TYPE_OLONG, new LongCodec()), new ConfigItem(long[].class, CodecType.TYPE_ARRAY_LONG, new LongArrayCodec()), new ConfigItem(Long[].class, CodecType.TYPE_ARRAY_OLONG, new OLongArrayCodec()), new ConfigItem(Float.TYPE, CodecType.TYPE_FLOAT, new FloatCodec()), new ConfigItem(Float.class, CodecType.TYPE_OFLOAT, new FloatCodec()), new ConfigItem(float[].class, CodecType.TYPE_ARRAY_FLOAT, new FloatArrayCodec()), new ConfigItem(Float[].class, CodecType.TYPE_ARRAY_OFLOAT, new OFloatArrayCodec()), new ConfigItem(Double.TYPE, CodecType.TYPE_DOUBLE, new DoubleCodec()), new ConfigItem(Double.class, CodecType.TYPE_ODOUBLE, new DoubleCodec()), new ConfigItem(double[].class, CodecType.TYPE_ARRAY_DOUBLE, new DoubleArrayCodec()), new ConfigItem(Double[].class, CodecType.TYPE_ARRAY_ODOUBLE, new ODoubleArrayCodec()), new ConfigItem(String.class, CodecType.TYPE_STRING, new StringCodec()), new ConfigItem(String[].class, CodecType.TYPE_ARRAY_STRING, new StringArrayCodec()), new ConfigItem(Object.class, CodecType.TYPE_OBJECT, new ObjectCodec()), new ConfigItem(Object[].class, CodecType.TYPE_ARRAY_OBJECT, new ObjectArrayCodec()), new ConfigItem(Enum.class, CodecType.TYPE_ENUM, new EnumCodec()), new ConfigItem(Enum[].class, CodecType.TYPE_ARRAY_ENUM, new EnumArrayCodec()), new ConfigItem(List.class, CodecType.TYPE_LIST, new ListCodec()), new ConfigItem(ArrayList.class, CodecType.TYPE_ARRAYLIST, new ListCodec()), new ConfigItem(LinkedList.class, CodecType.TYPE_LINKEDLIST, new ListCodec()), new ConfigItem(CopyOnWriteArrayList.class, CodecType.TYPE_COPYONWRITEARRAYLIST, new ListCodec()), new ConfigItem(Set.class, CodecType.TYPE_SET, new SetCodec()), new ConfigItem(HashSet.class, CodecType.TYPE_HASHSET, new SetCodec()), new ConfigItem(TreeSet.class, CodecType.TYPE_TREESET, new SetCodec()), new ConfigItem(LinkedHashSet.class, CodecType.TYPE_LINKEDHASHSET, new SetCodec()), new ConfigItem(Map.class, CodecType.TYPE_MAP, new MapCodec()), new ConfigItem(HashMap.class, CodecType.TYPE_HASHMAP, new MapCodec()), new ConfigItem(TreeMap.class, CodecType.TYPE_TREEMAP, new MapCodec()), new ConfigItem(ConcurrentHashMap.class, CodecType.TYPE_CONCURRENTHASHMAP, new MapCodec()), new ConfigItem(LinkedHashMap.class, CodecType.TYPE_LINKEDHASHMAP, new MapCodec()), new ConfigItem(Date.class, CodecType.TYPE_DATE, new DateCodec()), new ConfigItem(Date[].class, CodecType.TYPE_ARRAY_DATE, new DateArrayCodec()), new ConfigItem(java.sql.Date.class, CodecType.TYPE_SQLDATE, new SqlDateCodec()), new ConfigItem(java.sql.Date[].class, CodecType.TYPE_ARRAY_SQLDATE, new SqlDateArrayCodec()), new ConfigItem(Calendar.class, CodecType.TYPE_CALENDER, new CalendarCodec()), new ConfigItem(Calendar[].class, CodecType.TYPE_ARRAY_CALENDER, new CalendarArrayCodec()), new ConfigItem(GregorianCalendar.class, CodecType.TYPE_CALENDER, new CalendarCodec()), new ConfigItem(GregorianCalendar[].class, CodecType.TYPE_ARRAY_CALENDER, new CalendarArrayCodec()), new ConfigItem(Timestamp.class, CodecType.TYPE_TIMESTAMP, new TimestampCodec()), new ConfigItem(Timestamp[].class, CodecType.TYPE_ARRAY_TIMESTAMP, new TimestampArrayCodec()) }; private CodecConfig() { _loadClassCodec(); _loadClassCodecType(); _loadCodecTypeCodec(); _loadCodecTypeClass(); } private static CodecConfig instance; public static CodecConfig load() { if (instance == null) { synchronized (CodecConfig.class) { if (instance == null) { instance = new CodecConfig(); } } } return instance; } /** * 根据对象查找相关的Codec. * * @param obj 被序列化的对象. * @return 相关的Codec * @throws CodecException 此对象不能被序列化 */ public Codec lookup(Object obj) throws CodecException { if (obj == null) { return classCodecPool.get(Object.class); } // 判断是否是异常类型. if (obj instanceof Throwable) { return classCodecPool.get(Throwable.class); } Class<?> clazz = obj.getClass(); // 判断是否是基本类型, 如果是就从基本类型中找到Codec Codec codec = classCodecPool.get(clazz); if (codec != null) return codec; // 如果是枚举则使用枚举的序列化 if (clazz.isEnum()) { return classCodecPool.get(Enum.class); } // 如果是数组则判断是对象的数组还是枚举的数组 if (clazz.isArray()) { if (clazz.getComponentType().isEnum()) { return classCodecPool.get(Enum[].class); } else { return classCodecPool.get(Object[].class); } } _checkCodecable(clazz); return classCodecPool.get(Object.class); } /** * 根据序列化类型查找相关的Codec. * * @param type 序列化类型 * @return 相关的Codec * @throws CodecException 没有找到相关的Codec */ public Codec lookup(byte type) throws CodecException { Codec codec = codecTypeCodecPool.get(type); if (codec != null) { return codec; } throw new CodecException("找不到相关的codec(type:" + type + ")"); } /** * 获取CodecType. * * @param obj 根据这个对象获取类型. * @return 编码类型 * @throws 获取编码类型失败 */ public byte getCodecType(Object obj) throws CodecException { if (obj == null) { return classCodecTypePool.get(Object.class); } Class<?> clazz = obj.getClass(); if (clazz.isEnum()) { return classCodecTypePool.get(Enum.class); } Byte type = classCodecTypePool.get(clazz); if (type != null) { return type; } if (clazz.isArray()) { if (clazz.getComponentType().isEnum()) { return classCodecTypePool.get(Enum[].class); } else { return classCodecTypePool.get(Object[].class); } } _checkCodecable(clazz); return classCodecTypePool.get(Object.class); } /** * 根据序列化类型查找被序列化对象的class * * @param type 序列化类型 * @return 被序列化对象的class * @throws CodecException 没有找到class */ public Class<?> getClassByType(byte type) throws CodecException { Class<?> clazz = null; clazz = codecTypeClassPool.get(type); if (clazz != null) { return clazz; } throw new CodecException("不能识别的类型(type:" + type + ")"); } /** * 加载Class : Codec的映射关系 */ private void _loadClassCodec() { for (ConfigItem item : config) { classCodecPool.put(item.clazz, item.codec); } } /** * 加载Class : CodecType的映射关系 */ private void _loadClassCodecType() { for (ConfigItem item : config) { classCodecTypePool.put(item.clazz, item.ct); } } /** * 加载CodecType : Codec的映射关系 */ private void _loadCodecTypeCodec() { for (ConfigItem item : config) { if (item.codec != null) { codecTypeCodecPool.put(item.ct, item.codec); // if (log.isDebugEnabled()) { // log.debug("load " + item.ct + ":" + item.codec); // } } } } /** * 加载CodecType : Class的映射关系. */ private void _loadCodecTypeClass() { for (ConfigItem item : config) { codecTypeClassPool.put(item.ct, item.clazz); } } /** * 判断对象是否能够被序列化 */ private void _checkCodecable(Class<?> c) throws CodecException { // 如果是枚举类型则是可以被序列化的 if (c.isEnum()) { return; } if (c == Class.class) { return; } // 判断对象是否实现Codecable接口 Class<?>[] interfaces = BeansUtil.getInterfaces(c); for (Class<?> interf : interfaces) { if (interf == Serializable.class) { return; } } throw new CodecException("被序列化的对象(" + c + ")是不被支持的序列化类型也没有实现Serializable接口,序列化失败"); } /** * 配置项. */ class ConfigItem { /** * 被序列化类型. */ public Class<?> clazz; /** * 编码标志位. */ public byte ct; /** * 编码类. */ public Codec codec; public ConfigItem(Class<?> clazz, byte ct, Codec codec) { this.clazz = clazz; this.ct = ct; this.codec = codec; } } }