| /* |
| * Copyright (c) 2001-2008 Caucho Technology, Inc. All rights reserved. |
| * |
| * The Apache Software License, Version 1.1 |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in |
| * the documentation and/or other materials provided with the |
| * distribution. |
| * |
| * 3. The end-user documentation included with the redistribution, if |
| * any, must include the following acknowlegement: |
| * "This product includes software developed by the |
| * Caucho Technology (http://www.caucho.com/)." |
| * Alternately, this acknowlegement may appear in the software itself, |
| * if and wherever such third-party acknowlegements normally appear. |
| * |
| * 4. The names "Burlap", "Resin", and "Caucho" must not be used to |
| * endorse or promote products derived from this software without prior |
| * written permission. For written permission, please contact |
| * info@caucho.com. |
| * |
| * 5. Products derived from this software may not be called "Resin" |
| * nor may "Resin" appear in their names without prior written |
| * permission of Caucho Technology. |
| * |
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL CAUCHO TECHNOLOGY OR ITS CONTRIBUTORS |
| * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, |
| * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT |
| * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE |
| * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN |
| * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| * |
| * @author Scott Ferguson |
| */ |
| |
| package com.alibaba.com.caucho.hessian.io; |
| |
| import com.alibaba.com.caucho.hessian.HessianException; |
| |
| import java.io.InputStream; |
| import java.lang.ref.SoftReference; |
| import java.lang.ref.WeakReference; |
| import java.net.InetAddress; |
| import java.net.URL; |
| import java.util.Enumeration; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Map; |
| import java.util.Properties; |
| import java.util.WeakHashMap; |
| import java.util.concurrent.ConcurrentHashMap; |
| import java.util.logging.Level; |
| import java.util.logging.Logger; |
| |
| /** |
| * The classloader-specific Factory for returning serialization |
| */ |
| public class ContextSerializerFactory { |
| private static final Logger log |
| = Logger.getLogger(ContextSerializerFactory.class.getName()); |
| private static final WeakHashMap<ClassLoader, SoftReference<ContextSerializerFactory>> |
| _contextRefMap |
| = new WeakHashMap<ClassLoader, SoftReference<ContextSerializerFactory>>(); |
| private static final ClassLoader _systemClassLoader; |
| private static Deserializer OBJECT_DESERIALIZER |
| = new BasicDeserializer(BasicDeserializer.OBJECT); |
| private static HashMap<String, Serializer> _staticSerializerMap; |
| private static HashMap<String, Deserializer> _staticDeserializerMap; |
| private static HashMap _staticClassNameMap; |
| |
| static { |
| _staticSerializerMap = new HashMap(); |
| _staticDeserializerMap = new HashMap(); |
| _staticClassNameMap = new HashMap(); |
| |
| FieldDeserializer2Factory fieldFactory = FieldDeserializer2Factory.create(); |
| |
| addBasic(void.class, "void", BasicSerializer.NULL); |
| |
| addBasic(Boolean.class, "boolean", BasicSerializer.BOOLEAN); |
| addBasic(Byte.class, "byte", BasicSerializer.BYTE); |
| addBasic(Short.class, "short", BasicSerializer.SHORT); |
| addBasic(Integer.class, "int", BasicSerializer.INTEGER); |
| addBasic(Long.class, "long", BasicSerializer.LONG); |
| addBasic(Float.class, "float", BasicSerializer.FLOAT); |
| addBasic(Double.class, "double", BasicSerializer.DOUBLE); |
| addBasic(Character.class, "char", BasicSerializer.CHARACTER_OBJECT); |
| addBasic(String.class, "string", BasicSerializer.STRING); |
| addBasic(Object.class, "object", BasicSerializer.OBJECT); |
| addBasic(java.util.Date.class, "date", BasicSerializer.DATE); |
| |
| addBasic(boolean.class, "boolean", BasicSerializer.BOOLEAN); |
| addBasic(byte.class, "byte", BasicSerializer.BYTE); |
| addBasic(short.class, "short", BasicSerializer.SHORT); |
| addBasic(int.class, "int", BasicSerializer.INTEGER); |
| addBasic(long.class, "long", BasicSerializer.LONG); |
| addBasic(float.class, "float", BasicSerializer.FLOAT); |
| addBasic(double.class, "double", BasicSerializer.DOUBLE); |
| addBasic(char.class, "char", BasicSerializer.CHARACTER); |
| |
| addBasic(boolean[].class, "[boolean", BasicSerializer.BOOLEAN_ARRAY); |
| addBasic(byte[].class, "[byte", BasicSerializer.BYTE_ARRAY); |
| _staticSerializerMap.put(byte[].class.getName(), ByteArraySerializer.SER); |
| addBasic(short[].class, "[short", BasicSerializer.SHORT_ARRAY); |
| addBasic(int[].class, "[int", BasicSerializer.INTEGER_ARRAY); |
| addBasic(long[].class, "[long", BasicSerializer.LONG_ARRAY); |
| addBasic(float[].class, "[float", BasicSerializer.FLOAT_ARRAY); |
| addBasic(double[].class, "[double", BasicSerializer.DOUBLE_ARRAY); |
| addBasic(char[].class, "[char", BasicSerializer.CHARACTER_ARRAY); |
| addBasic(String[].class, "[string", BasicSerializer.STRING_ARRAY); |
| addBasic(Object[].class, "[object", BasicSerializer.OBJECT_ARRAY); |
| |
| Deserializer objectDeserializer = new JavaDeserializer(Object.class, fieldFactory); |
| _staticDeserializerMap.put("object", objectDeserializer); |
| _staticClassNameMap.put("object", objectDeserializer); |
| |
| _staticSerializerMap.put(Class.class.getName(), new ClassSerializer()); |
| |
| _staticDeserializerMap.put(Number.class.getName(), new BasicDeserializer(BasicSerializer.NUMBER)); |
| |
| /* |
| for (Class cl : new Class[] { BigDecimal.class, File.class, ObjectName.class }) { |
| _staticSerializerMap.put(cl, StringValueSerializer.SER); |
| _staticDeserializerMap.put(cl, new StringValueDeserializer(cl)); |
| } |
| |
| _staticSerializerMap.put(ObjectName.class, StringValueSerializer.SER); |
| try { |
| _staticDeserializerMap.put(ObjectName.class, |
| new StringValueDeserializer(ObjectName.class)); |
| } catch (Throwable e) { |
| } |
| */ |
| |
| _staticSerializerMap.put(InetAddress.class.getName(), |
| InetAddressSerializer.create()); |
| |
| _staticSerializerMap.put(java.sql.Date.class.getName(), |
| new SqlDateSerializer()); |
| _staticSerializerMap.put(java.sql.Time.class.getName(), |
| new SqlDateSerializer()); |
| _staticSerializerMap.put(java.sql.Timestamp.class.getName(), |
| new SqlDateSerializer()); |
| |
| _staticDeserializerMap.put(java.sql.Date.class.getName(), |
| new SqlDateDeserializer(java.sql.Date.class)); |
| _staticDeserializerMap.put(java.sql.Time.class.getName(), |
| new SqlDateDeserializer(java.sql.Time.class)); |
| _staticDeserializerMap.put(java.sql.Timestamp.class.getName(), |
| new SqlDateDeserializer(java.sql.Timestamp.class)); |
| |
| // hessian/3bb5 |
| _staticDeserializerMap.put(StackTraceElement.class.getName(), |
| new StackTraceElementDeserializer(fieldFactory)); |
| |
| ClassLoader systemClassLoader = null; |
| try { |
| systemClassLoader = ClassLoader.getSystemClassLoader(); |
| } catch (Exception e) { |
| } |
| |
| _systemClassLoader = systemClassLoader; |
| } |
| |
| private final HashSet<String> _serializerFiles = new HashSet<String>(); |
| private final HashSet<String> _deserializerFiles = new HashSet<String>(); |
| private final HashMap<String, Serializer> _serializerClassMap |
| = new HashMap<String, Serializer>(); |
| private final ConcurrentHashMap<String, Serializer> _customSerializerMap |
| = new ConcurrentHashMap<String, Serializer>(); |
| private final HashMap<Class<?>, Serializer> _serializerInterfaceMap |
| = new HashMap<Class<?>, Serializer>(); |
| private final HashMap<String, Deserializer> _deserializerClassMap |
| = new HashMap<String, Deserializer>(); |
| private final HashMap<String, Deserializer> _deserializerClassNameMap |
| = new HashMap<String, Deserializer>(); |
| private final ConcurrentHashMap<String, Deserializer> _customDeserializerMap |
| = new ConcurrentHashMap<String, Deserializer>(); |
| private final HashMap<Class<?>, Deserializer> _deserializerInterfaceMap |
| = new HashMap<Class<?>, Deserializer>(); |
| private ContextSerializerFactory _parent; |
| private WeakReference<ClassLoader> _loaderRef; |
| |
| public ContextSerializerFactory(ContextSerializerFactory parent, |
| ClassLoader loader) { |
| if (loader == null) |
| loader = _systemClassLoader; |
| |
| _loaderRef = new WeakReference<ClassLoader>(loader); |
| |
| init(); |
| } |
| |
| public static ContextSerializerFactory create() { |
| return create(Thread.currentThread().getContextClassLoader()); |
| } |
| |
| public static ContextSerializerFactory create(ClassLoader loader) { |
| synchronized (_contextRefMap) { |
| SoftReference<ContextSerializerFactory> factoryRef |
| = _contextRefMap.get(loader); |
| |
| ContextSerializerFactory factory = null; |
| |
| if (factoryRef != null) |
| factory = factoryRef.get(); |
| |
| if (factory == null) { |
| ContextSerializerFactory parent = null; |
| |
| if (loader != null) |
| parent = create(loader.getParent()); |
| |
| factory = new ContextSerializerFactory(parent, loader); |
| factoryRef = new SoftReference<ContextSerializerFactory>(factory); |
| |
| _contextRefMap.put(loader, factoryRef); |
| } |
| |
| return factory; |
| } |
| } |
| |
| private static void addBasic(Class cl, String typeName, int type) { |
| _staticSerializerMap.put(cl.getName(), new BasicSerializer(type)); |
| |
| Deserializer deserializer = new BasicDeserializer(type); |
| _staticDeserializerMap.put(cl.getName(), deserializer); |
| _staticClassNameMap.put(typeName, deserializer); |
| } |
| |
| public ClassLoader getClassLoader() { |
| WeakReference<ClassLoader> loaderRef = _loaderRef; |
| |
| if (loaderRef != null) |
| return loaderRef.get(); |
| else |
| return null; |
| } |
| |
| /** |
| * Returns the serializer for a given class. |
| */ |
| public Serializer getSerializer(String className) { |
| Serializer serializer = _serializerClassMap.get(className); |
| |
| if (serializer == AbstractSerializer.NULL) |
| return null; |
| else |
| return serializer; |
| } |
| |
| /** |
| * Returns a custom serializer the class |
| * |
| * @param cl the class of the object that needs to be serialized. |
| * @return a serializer object for the serialization. |
| */ |
| public Serializer getCustomSerializer(Class cl) { |
| Serializer serializer = _customSerializerMap.get(cl.getName()); |
| |
| if (serializer == AbstractSerializer.NULL) |
| return null; |
| else if (serializer != null) |
| return serializer; |
| |
| try { |
| Class serClass = Class.forName(cl.getName() + "HessianSerializer", |
| false, cl.getClassLoader()); |
| |
| Serializer ser = (Serializer) serClass.newInstance(); |
| |
| _customSerializerMap.put(cl.getName(), ser); |
| |
| return ser; |
| } catch (ClassNotFoundException e) { |
| log.log(Level.ALL, e.toString(), e); |
| } catch (Exception e) { |
| throw new HessianException(e); |
| } |
| |
| _customSerializerMap.put(cl.getName(), AbstractSerializer.NULL); |
| |
| return null; |
| } |
| |
| /** |
| * Returns the deserializer for a given class. |
| */ |
| public Deserializer getDeserializer(String className) { |
| Deserializer deserializer = _deserializerClassMap.get(className); |
| |
| if (deserializer != null && deserializer != AbstractDeserializer.NULL) { |
| return deserializer; |
| } |
| |
| deserializer = _deserializerInterfaceMap.get(className); |
| |
| if (deserializer != null && deserializer != AbstractDeserializer.NULL) { |
| return deserializer; |
| } |
| |
| return null; |
| } |
| |
| /** |
| * Returns a custom deserializer the class |
| * |
| * @param cl the class of the object that needs to be deserialized. |
| * @return a deserializer object for the deserialization. |
| */ |
| public Deserializer getCustomDeserializer(Class cl) { |
| Deserializer deserializer = _customDeserializerMap.get(cl.getName()); |
| |
| if (deserializer == AbstractDeserializer.NULL) |
| return null; |
| else if (deserializer != null) |
| return deserializer; |
| |
| try { |
| Class serClass = Class.forName(cl.getName() + "HessianDeserializer", |
| false, cl.getClassLoader()); |
| |
| Deserializer ser = (Deserializer) serClass.newInstance(); |
| |
| _customDeserializerMap.put(cl.getName(), ser); |
| |
| return ser; |
| } catch (ClassNotFoundException e) { |
| log.log(Level.ALL, e.toString(), e); |
| } catch (Exception e) { |
| throw new HessianException(e); |
| } |
| |
| _customDeserializerMap.put(cl.getName(), AbstractDeserializer.NULL); |
| |
| return null; |
| } |
| |
| /** |
| * Initialize the factory |
| */ |
| private void init() { |
| if (_parent != null) { |
| _serializerFiles.addAll(_parent._serializerFiles); |
| _deserializerFiles.addAll(_parent._deserializerFiles); |
| |
| _serializerClassMap.putAll(_parent._serializerClassMap); |
| _deserializerClassMap.putAll(_parent._deserializerClassMap); |
| } |
| |
| if (_parent == null) { |
| _serializerClassMap.putAll(_staticSerializerMap); |
| _deserializerClassMap.putAll(_staticDeserializerMap); |
| _deserializerClassNameMap.putAll(_staticClassNameMap); |
| } |
| |
| HashMap<Class, Class> classMap; |
| |
| classMap = new HashMap<Class, Class>(); |
| initSerializerFiles("META-INF/dubbo/hessian/serializers", |
| _serializerFiles, |
| classMap, |
| Serializer.class); |
| |
| for (Map.Entry<Class, Class> entry : classMap.entrySet()) { |
| try { |
| Serializer ser = (Serializer) entry.getValue().newInstance(); |
| |
| if (entry.getKey().isInterface()) |
| _serializerInterfaceMap.put(entry.getKey(), ser); |
| else |
| _serializerClassMap.put(entry.getKey().getName(), ser); |
| } catch (Exception e) { |
| throw new HessianException(e); |
| } |
| } |
| |
| classMap = new HashMap<Class, Class>(); |
| initSerializerFiles("META-INF/dubbo/hessian/deserializers", |
| _deserializerFiles, |
| classMap, |
| Deserializer.class); |
| |
| for (Map.Entry<Class, Class> entry : classMap.entrySet()) { |
| try { |
| Deserializer ser = (Deserializer) entry.getValue().newInstance(); |
| |
| if (entry.getKey().isInterface()) |
| _deserializerInterfaceMap.put(entry.getKey(), ser); |
| else { |
| _deserializerClassMap.put(entry.getKey().getName(), ser); |
| } |
| } catch (Exception e) { |
| throw new HessianException(e); |
| } |
| } |
| } |
| |
| private void initSerializerFiles(String fileName, |
| HashSet<String> fileList, |
| HashMap<Class, Class> classMap, |
| Class type) { |
| try { |
| ClassLoader classLoader = getClassLoader(); |
| |
| // on systems with the security manager enabled, the system classloader |
| // is null |
| if (classLoader == null) |
| return; |
| |
| Enumeration iter; |
| |
| iter = classLoader.getResources(fileName); |
| while (iter.hasMoreElements()) { |
| URL url = (URL) iter.nextElement(); |
| |
| if (fileList.contains(url.toString())) |
| continue; |
| |
| fileList.add(url.toString()); |
| |
| InputStream is = null; |
| try { |
| is = url.openStream(); |
| |
| Properties props = new Properties(); |
| props.load(is); |
| |
| for (Map.Entry entry : props.entrySet()) { |
| String apiName = (String) entry.getKey(); |
| String serializerName = (String) entry.getValue(); |
| |
| Class apiClass = null; |
| Class serializerClass = null; |
| |
| try { |
| apiClass = Class.forName(apiName, false, classLoader); |
| } catch (ClassNotFoundException e) { |
| log.fine(url + ": " + apiName + " is not available in this context: " + getClassLoader()); |
| continue; |
| } |
| |
| try { |
| serializerClass = Class.forName(serializerName, false, classLoader); |
| } catch (ClassNotFoundException e) { |
| log.fine(url + ": " + serializerName + " is not available in this context: " + getClassLoader()); |
| continue; |
| } |
| |
| if (!type.isAssignableFrom(serializerClass)) |
| throw new HessianException(url + ": " + serializerClass.getName() + " is invalid because it does not implement " + type.getName()); |
| |
| classMap.put(apiClass, serializerClass); |
| } |
| } finally { |
| if (is != null) |
| is.close(); |
| } |
| } |
| } catch (RuntimeException e) { |
| throw e; |
| } catch (Exception e) { |
| throw new HessianException(e); |
| } |
| } |
| } |
| |