Java tutorial
/* * This program is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software * Foundation. * * You should have received a copy of the GNU Lesser General Public License along with this * program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html * or from the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * Copyright (c) 2001 - 2013 Object Refinery Ltd, Hitachi Vantara and Contributors.. All rights reserved. */ package org.pentaho.reporting.libraries.serializer; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.pentaho.reporting.libraries.base.config.Configuration; import org.pentaho.reporting.libraries.base.util.ObjectUtilities; import java.io.IOException; import java.io.NotSerializableException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.HashMap; import java.util.Iterator; /** * The SerializeHelper is used to make implementing custom serialization handlers easier. Handlers for certain object * types need to be added to this helper before this implementation is usable. * * @author Thomas Morgner */ public class SerializerHelper { private static final Log logger = LogFactory.getLog(SerializerHelper.class); /** * The singleton instance of the serialize helper. */ private static SerializerHelper singleton; /** * Returns or creates a new SerializerHelper. When a new instance is created by this method, all known * SerializeMethods are registered. * * @return the SerializerHelper singleton instance. */ public static synchronized SerializerHelper getInstance() { if (singleton == null) { singleton = LibSerializerBoot.getInstance().getObjectFactory().get(SerializerHelper.class); singleton.registerMethods(); } return singleton; } /** * A collection of the serializer methods. */ private final HashMap<Class, SerializeMethod> methods; /** * A class comparator for searching the super class of an certain class. */ private final ClassComparator comparator; /** * Creates a new SerializerHelper. */ public SerializerHelper() { this.comparator = new ClassComparator(); this.methods = new HashMap<Class, SerializeMethod>(); } /** * Registers a new SerializeMethod with this SerializerHelper. * * @param method the method that should be registered. */ public synchronized void registerMethod(final SerializeMethod method) { this.methods.put(method.getObjectClass(), method); } /** * Traverses the configuration and registers all serialization handlers in this factory. */ protected void registerMethods() { final Configuration config = LibSerializerBoot.getInstance().getGlobalConfig(); final Iterator sit = config.findPropertyKeys("org.pentaho.reporting.libraries.serializer.handler."); while (sit.hasNext()) { final String configkey = (String) sit.next(); final String c = config.getConfigProperty(configkey); final SerializeMethod maybeModule = ObjectUtilities.loadAndInstantiate(c, SerializerHelper.class, SerializeMethod.class); if (maybeModule != null) { registerMethod(maybeModule); } else { logger.warn("Invalid SerializeMethod implementation: " + c); } } } /** * Deregisters a new SerializeMethod with this SerializerHelper. * * @param method the method that should be deregistered. */ public synchronized void unregisterMethod(final SerializeMethod method) { this.methods.remove(method.getObjectClass()); } /** * Returns the collection of all registered serialize methods. * * @return a collection of the registered serialize methods. */ protected HashMap getMethods() { return methods; } /** * Returns the class comparator instance used to find correct super classes. * * @return the class comparator. */ protected ClassComparator getComparator() { return comparator; } /** * Looks up the SerializeMethod for the given class or null if there is no SerializeMethod for the given class. * * @param c the class for which we want to lookup a serialize method. * @return the method or null, if there is no registered method for the class. */ protected SerializeMethod getSerializer(final Class c) { final SerializeMethod sm = methods.get(c); if (sm != null) { return sm; } return getSuperClassObjectDescription(c); } /** * Looks up the SerializeMethod for the given class or null if there is no SerializeMethod for the given class. This * method searches all superclasses. * * @param d the class for which we want to lookup a serialize method. * @return the method or null, if there is no registered method for the class. */ @SuppressWarnings("unchecked") protected SerializeMethod getSuperClassObjectDescription(final Class d) { SerializeMethod knownSuperClass = null; final Iterator<Class> keys = methods.keySet().iterator(); while (keys.hasNext()) { final Class keyClass = keys.next(); if (keyClass.isAssignableFrom(d)) { final SerializeMethod od = methods.get(keyClass); if (knownSuperClass == null) { knownSuperClass = od; } else { if (comparator.isComparable(knownSuperClass.getObjectClass(), od.getObjectClass())) { if (comparator.compare(knownSuperClass.getObjectClass(), od.getObjectClass()) < 0) { knownSuperClass = od; } } } } } return knownSuperClass; } /** * Writes a serializable object description to the given object output stream. This method selects the best serialize * helper method for the given object. * * @param o the to be serialized object. * @param out the outputstream that should receive the object. * @throws IOException if an I/O error occured. */ public synchronized void writeObject(final Object o, final ObjectOutputStream out) throws IOException { try { if (o == null) { out.writeByte(0); return; } if (o instanceof Serializable) { out.writeByte(1); out.writeObject(o); return; } final SerializeMethod m = getSerializer(o.getClass()); if (m == null) { throw new NotSerializableException(o.getClass().getName()); } out.writeByte(2); out.writeObject(m.getObjectClass()); m.writeObject(o, out); } catch (NotSerializableException nse) { logger.warn("Unable to serialize object: " + o); throw nse; } } public synchronized boolean isSerializable(final Object o) { if (o == null) { return true; } if (o instanceof Serializable) { return true; } final SerializeMethod m = getSerializer(o.getClass()); return m != null; } /** * Reads the object from the object input stream. This object selects the best serializer to read the object. * <p/> * Make sure, that you use the same configuration (library and class versions, registered methods in the * SerializerHelper) for reading as you used for writing. * * @param in the object input stream from where to read the serialized data. * @return the generated object. * @throws IOException if reading the stream failed. * @throws ClassNotFoundException if serialized object class cannot be found. */ public synchronized Object readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { final int type = in.readByte(); if (type == 0) { return null; } if (type == 1) { return in.readObject(); } final Class c = (Class) in.readObject(); final SerializeMethod m = getSerializer(c); if (m == null) { throw new NotSerializableException(c.getName()); } return m.readObject(in); } }