/*
 * 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.caucho.hessian.io;

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;

import com.caucho.hessian.HessianException;

The classloader-specific Factory for returning serialization
/** * The classloader-specific Factory for returning serialization */
public class ContextSerializerFactory { private static final Logger log = Logger.getLogger(ContextSerializerFactory.class.getName()); private static Deserializer OBJECT_DESERIALIZER = new BasicDeserializer(BasicDeserializer.OBJECT); private static final WeakHashMap<ClassLoader,SoftReference<ContextSerializerFactory>> _contextRefMap = new WeakHashMap<ClassLoader,SoftReference<ContextSerializerFactory>>(); private static final ClassLoader _systemClassLoader; private static HashMap<String,Serializer> _staticSerializerMap; private static HashMap<String,Deserializer> _staticDeserializerMap; private static HashMap _staticClassNameMap; private ContextSerializerFactory _parent; private WeakReference<ClassLoader> _loaderRef; 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>(); 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; } } public ClassLoader getClassLoader() { WeakReference<ClassLoader> loaderRef = _loaderRef; if (loaderRef != null) return loaderRef.get(); else return null; }
Returns the serializer for a given class.
/** * 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
Params:
  • cl – the class of the object that needs to be serialized.
Returns:a serializer object for the serialization.
/** * 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.
/** * 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
Params:
  • cl – the class of the object that needs to be deserialized.
Returns:a deserializer object for the deserialization.
/** * 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
/** * 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/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/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); } } 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); } 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; } }