001 /** 002 * =================================================== 003 * JCommon-Serializer : a free serialization framework 004 * =================================================== 005 * 006 * Project Info: http://www.jfree.org/jfreereport/jcommon-serializer/ 007 * Project Lead: Thomas Morgner; 008 * 009 * (C) Copyright 2006, by Object Refinery Limited and Pentaho Corporation. 010 * 011 * This library is free software; you can redistribute it and/or modify it under the terms 012 * of the GNU Lesser General Public License as published by the Free Software Foundation; 013 * either version 2.1 of the License, or (at your option) any later version. 014 * 015 * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 016 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 017 * See the GNU Lesser General Public License for more details. 018 * 019 * You should have received a copy of the GNU Lesser General Public License along with this 020 * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, 021 * Boston, MA 02111-1307, USA. 022 * 023 * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 024 * in the United States and other countries.] 025 * 026 * ------------ 027 * SerializerHelper.java 028 * ------------ 029 * (C) Copyright 2006, by Object Refinery Limited and Pentaho Corporation. 030 * 031 * Original Author: Thomas Morgner; 032 * Contributor(s): -; 033 * 034 * $Id: SerializerHelper.java 3044 2007-07-28 17:52:44Z tmorgner $ 035 * 036 * Changes 037 * ------- 038 * 039 * 040 */ 041 042 package org.jfree.serializer; 043 044 import java.io.IOException; 045 import java.io.NotSerializableException; 046 import java.io.ObjectInputStream; 047 import java.io.ObjectOutputStream; 048 import java.io.Serializable; 049 import java.util.HashMap; 050 import java.util.Iterator; 051 052 import org.jfree.util.ClassComparator; 053 import org.jfree.util.Configuration; 054 import org.jfree.util.Log; 055 import org.jfree.util.ObjectUtilities; 056 057 /** 058 * The SerializeHelper is used to make implementing custom serialization 059 * handlers easier. Handlers for certain object types need to be added to this 060 * helper before this implementation is usable. 061 * 062 * @author Thomas Morgner 063 */ 064 public class SerializerHelper 065 { 066 /** 067 * The singleton instance of the serialize helper. 068 */ 069 private static SerializerHelper singleton; 070 071 /** 072 * Returns or creates a new SerializerHelper. When a new instance is created 073 * by this method, all known SerializeMethods are registered. 074 * 075 * @return the SerializerHelper singleton instance. 076 */ 077 public synchronized static SerializerHelper getInstance() 078 { 079 if (singleton == null) 080 { 081 singleton = new SerializerHelper(); 082 singleton.registerMethods(); 083 } 084 return singleton; 085 } 086 087 088 /** 089 * This method can be used to replace the singleton instance of this helper. 090 * 091 * @param helper the new instance of the serialize helper. 092 */ 093 protected static void setInstance(final SerializerHelper helper) 094 { 095 singleton = helper; 096 } 097 098 /** 099 * 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 }