Source for org.jfree.serializer.SerializerHelper

   1: /**
   2:  * ===================================================
   3:  * JCommon-Serializer : a free serialization framework
   4:  * ===================================================
   5:  *
   6:  * Project Info:  http://www.jfree.org/jfreereport/jcommon-serializer/
   7:  * Project Lead:  Thomas Morgner;
   8:  *
   9:  * (C) Copyright 2006, by Object Refinery Limited and Pentaho Corporation.
  10:  *
  11:  * This library is free software; you can redistribute it and/or modify it under the terms
  12:  * of the GNU Lesser General Public License as published by the Free Software Foundation;
  13:  * either version 2.1 of the License, or (at your option) any later version.
  14:  *
  15:  * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
  16:  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  17:  * See the GNU Lesser General Public License for more details.
  18:  *
  19:  * You should have received a copy of the GNU Lesser General Public License along with this
  20:  * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  21:  * Boston, MA 02111-1307, USA.
  22:  *
  23:  * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
  24:  * in the United States and other countries.]
  25:  *
  26:  * ------------
  27:  * SerializerHelper.java
  28:  * ------------
  29:  * (C) Copyright 2006, by Object Refinery Limited and Pentaho Corporation.
  30:  *
  31:  * Original Author:  Thomas Morgner;
  32:  * Contributor(s):   -;
  33:  *
  34:  * $Id: SerializerHelper.java,v 1.3 2006/12/11 12:40:28 taqua Exp $
  35:  *
  36:  * Changes
  37:  * -------
  38:  *
  39:  *
  40:  */
  41: 
  42: package org.jfree.serializer;
  43: 
  44: import java.io.IOException;
  45: import java.io.NotSerializableException;
  46: import java.io.ObjectInputStream;
  47: import java.io.ObjectOutputStream;
  48: import java.io.Serializable;
  49: import java.util.HashMap;
  50: import java.util.Iterator;
  51: 
  52: import org.jfree.util.ClassComparator;
  53: import org.jfree.util.Configuration;
  54: import org.jfree.util.Log;
  55: import org.jfree.util.ObjectUtilities;
  56: 
  57: /**
  58:  * The SerializeHelper is used to make implementing custom serialization
  59:  * handlers easier. Handlers for certain object types need to be added to this
  60:  * helper before this implementation is usable.
  61:  *
  62:  * @author Thomas Morgner
  63:  */
  64: public class SerializerHelper
  65: {
  66:   /**
  67:    * The singleton instance of the serialize helper.
  68:    */
  69:   private static SerializerHelper singleton;
  70: 
  71:   /**
  72:    * Returns or creates a new SerializerHelper. When a new instance is created
  73:    * by this method, all known SerializeMethods are registered.
  74:    *
  75:    * @return the SerializerHelper singleton instance.
  76:    */
  77:   public synchronized static SerializerHelper getInstance()
  78:   {
  79:     if (singleton == null)
  80:     {
  81:       singleton = new SerializerHelper();
  82:       singleton.registerMethods();
  83:     }
  84:     return singleton;
  85:   }
  86: 
  87: 
  88:   /**
  89:    * This method can be used to replace the singleton instance of this helper.
  90:    *
  91:    * @param helper the new instance of the serialize helper.
  92:    */
  93:   protected static void setInstance(final SerializerHelper helper)
  94:   {
  95:     singleton = helper;
  96:   }
  97: 
  98:   /**
  99:    * A collection of the serializer methods.
 100:    */
 101:   private final HashMap methods;
 102: 
 103:   /**
 104:    * A class comparator for searching the super class of an certain class.
 105:    */
 106:   private final ClassComparator comparator;
 107: 
 108:   /**
 109:    * Creates a new SerializerHelper.
 110:    */
 111:   protected SerializerHelper()
 112:   {
 113:     this.comparator = new ClassComparator();
 114:     this.methods = new HashMap();
 115:   }
 116: 
 117:   /**
 118:    * Registers a new SerializeMethod with this SerializerHelper.
 119:    *
 120:    * @param method the method that should be registered.
 121:    */
 122:   public synchronized void registerMethod(final SerializeMethod method)
 123:   {
 124:     this.methods.put(method.getObjectClass(), method);
 125:   }
 126: 
 127:   protected void registerMethods()
 128:   {
 129:     final Configuration config = JCommonSerializerBoot.getInstance().getGlobalConfig();
 130:     Iterator sit = config.findPropertyKeys("org.jfree.serializer.handler.");
 131: 
 132:     while (sit.hasNext())
 133:     {
 134:       final String configkey = (String) sit.next();
 135:       final String c = config.getConfigProperty(configkey);
 136:       Object maybeModule = ObjectUtilities.loadAndInstantiate
 137:           (c, SerializerHelper.class, SerializeMethod.class);
 138:       if (maybeModule != null)
 139:       {
 140:         SerializeMethod module = (SerializeMethod) maybeModule;
 141:         registerMethod(module);
 142:       }
 143:       else
 144:       {
 145:         Log.warn("Invalid SerializeMethod implementation: " + c);
 146:       }
 147:     }
 148:   }
 149: 
 150:   /**
 151:    * Deregisters a new SerializeMethod with this SerializerHelper.
 152:    *
 153:    * @param method the method that should be deregistered.
 154:    */
 155:   public synchronized void unregisterMethod(final SerializeMethod method)
 156:   {
 157:     this.methods.remove(method.getObjectClass());
 158:   }
 159: 
 160:   /**
 161:    * Returns the collection of all registered serialize methods.
 162:    *
 163:    * @return a collection of the registered serialize methods.
 164:    */
 165:   protected HashMap getMethods()
 166:   {
 167:     return methods;
 168:   }
 169: 
 170:   /**
 171:    * Returns the class comparator instance used to find correct super classes.
 172:    *
 173:    * @return the class comparator.
 174:    */
 175:   protected ClassComparator getComparator()
 176:   {
 177:     return comparator;
 178:   }
 179: 
 180:   /**
 181:    * Looks up the SerializeMethod for the given class or null if there is no
 182:    * SerializeMethod for the given class.
 183:    *
 184:    * @param c the class for which we want to lookup a serialize method.
 185:    * @return the method or null, if there is no registered method for the
 186:    *         class.
 187:    */
 188:   protected SerializeMethod getSerializer(final Class c)
 189:   {
 190:     final SerializeMethod sm = (SerializeMethod) methods.get(c);
 191:     if (sm != null)
 192:     {
 193:       return sm;
 194:     }
 195:     return getSuperClassObjectDescription(c);
 196:   }
 197: 
 198:   /**
 199:    * Looks up the SerializeMethod for the given class or null if there is no
 200:    * SerializeMethod for the given class. This method searches all
 201:    * superclasses.
 202:    *
 203:    * @param d               the class for which we want to lookup a serialize
 204:    *                        method.
 205:    * @param knownSuperClass the known super class, if any or null.
 206:    * @return the method or null, if there is no registered method for the
 207:    *         class.
 208:    */
 209:   protected SerializeMethod getSuperClassObjectDescription
 210:       (final Class d)
 211:   {
 212:     SerializeMethod knownSuperClass = null;
 213:     final Iterator keys = methods.keySet().iterator();
 214:     while (keys.hasNext())
 215:     {
 216:       final Class keyClass = (Class) keys.next();
 217:       if (keyClass.isAssignableFrom(d))
 218:       {
 219:         final SerializeMethod od = (SerializeMethod) methods.get(keyClass);
 220:         if (knownSuperClass == null)
 221:         {
 222:           knownSuperClass = od;
 223:         }
 224:         else
 225:         {
 226:           if (comparator.isComparable
 227:               (knownSuperClass.getObjectClass(), od.getObjectClass()))
 228:           {
 229:             if (comparator.compare
 230:                 (knownSuperClass.getObjectClass(), od.getObjectClass()) < 0)
 231:             {
 232:               knownSuperClass = od;
 233:             }
 234:           }
 235:         }
 236:       }
 237:     }
 238:     return knownSuperClass;
 239:   }
 240: 
 241: 
 242:   /**
 243:    * Writes a serializable object description to the given object output stream.
 244:    * This method selects the best serialize helper method for the given object.
 245:    *
 246:    * @param o   the to be serialized object.
 247:    * @param out the outputstream that should receive the object.
 248:    * @throws IOException if an I/O error occured.
 249:    */
 250:   public synchronized void writeObject(final Object o,
 251:                                        final ObjectOutputStream out)
 252:       throws IOException
 253:   {
 254:     if (o == null)
 255:     {
 256:       out.writeByte(0);
 257:       return;
 258:     }
 259:     if (o instanceof Serializable)
 260:     {
 261:       out.writeByte(1);
 262:       out.writeObject(o);
 263:       return;
 264:     }
 265: 
 266:     final SerializeMethod m = getSerializer(o.getClass());
 267:     if (m == null)
 268:     {
 269:       throw new NotSerializableException(o.getClass().getName());
 270:     }
 271:     out.writeByte(2);
 272:     out.writeObject(m.getObjectClass());
 273:     m.writeObject(o, out);
 274:   }
 275: 
 276:   /**
 277:    * Reads the object from the object input stream. This object selects the best
 278:    * serializer to read the object.
 279:    * <p/>
 280:    * Make sure, that you use the same configuration (library and class versions,
 281:    * registered methods in the SerializerHelper) for reading as you used for
 282:    * writing.
 283:    *
 284:    * @param in the object input stream from where to read the serialized data.
 285:    * @return the generated object.
 286:    * @throws IOException            if reading the stream failed.
 287:    * @throws ClassNotFoundException if serialized object class cannot be found.
 288:    */
 289:   public synchronized Object readObject(final ObjectInputStream in)
 290:       throws IOException, ClassNotFoundException
 291:   {
 292:     final int type = in.readByte();
 293:     if (type == 0)
 294:     {
 295:       return null;
 296:     }
 297:     if (type == 1)
 298:     {
 299:       return in.readObject();
 300:     }
 301:     final Class c = (Class) in.readObject();
 302:     final SerializeMethod m = getSerializer(c);
 303:     if (m == null)
 304:     {
 305:       throw new NotSerializableException(c.getName());
 306:     }
 307:     return m.readObject(in);
 308:   }
 309: }