Update of /cvsroot/cweb/extser/src/java/org/CognitiveWeb/extser In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv22010/src/java/org/CognitiveWeb/extser Added Files: ISimpleSerializer.java SerializerIdProtocol.java LongPacker.java NativeType.java DataOutput.java IStreamSerializer.java AbstractExtensibleSerializer.java DataInput.java package.html ISerializer.java StringSerializer.java AbstractSingleton.java ShortPacker.java IExtensibleSerializer.java Stateless.java Log Message: Initial import. The extensible serialization framework was also contributed to the jdbm project and exists under that license as well. --- NEW FILE: DataInput.java --- /** The Notice below must appear in each file of the Source Code of any copy you distribute of the Licensed Product. Contributors to any Modifications may add their own copyright notices to identify their own contributions. License: The contents of this file are subject to the CognitiveWeb Open Source License Version 1.0 (the License). You may not copy or use this file, in either source code or executable form, except in compliance with the License. You may obtain a copy of the License from http://www.CognitiveWeb.org/legal/license/ Software distributed under the License is distributed on an AS IS basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. Copyrights: Portions created by or assigned to CognitiveWeb, Inc. are Copyright (c) 2003-2003 CognitiveWeb, Inc. All Rights Reserved. Contact information for CognitiveWeb, Inc. is available at http://www.CognitiveWeb.org Portions Copyright (c) 2002-2003 Bryan Thompson. Acknowledgements: Special thanks to the developers of the Jabber Open Source License 1.0 (JOSL), from which this License was derived. This License contains terms that differ from JOSL. Special thanks to the CognitiveWeb Open Source Contributors for their suggestions and support of the Cognitive Web. Modifications: */ /* * Created on Sep 30, 2005 */ package org.CognitiveWeb.extser; import java.io.IOException; /** * Supports stream-based serialization of objects and packed integer values. * * @author thompsonbry */ public interface DataInput extends java.io.DataInput { /** * Return the logical row id (recid) of the record being (de-)serialized * or zero (0L) iff the record is being inserted into the store. */ public long getRecid(); /** * The serialization handler. */ public IExtensibleSerializer getSerializationHandler(); /** * Applies the serialization handler to deserialize the next object * in the input stream. * * @return The deserialized object. */ public Object deserialize() throws IOException; /** * Unpacks a long value from the input stream. * * @return The long value. * * @throws IOException * * @see DataOutput#writePackedLong(long) */ public long readPackedLong() throws IOException; /** * Reads a packed int value. * * @return The unpacked int value. * * @throws IOException * * @see DataOutput#writePackedInt(int) */ public int readPackedInt() throws IOException; /** * Reads a packed short value. * * @return The unpacked short value. * * @throws IOException * * @see DataOutput#writePackedShort(short) */ public short readPackedShort() throws IOException; } --- NEW FILE: ISimpleSerializer.java --- /** The Notice below must appear in each file of the Source Code of any copy you distribute of the Licensed Product. Contributors to any Modifications may add their own copyright notices to identify their own contributions. License: The contents of this file are subject to the CognitiveWeb Open Source License Version 1.0 (the License). You may not copy or use this file, in either source code or executable form, except in compliance with the License. You may obtain a copy of the License from http://www.CognitiveWeb.org/legal/license/ Software distributed under the License is distributed on an AS IS basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. Copyrights: Portions created by or assigned to CognitiveWeb, Inc. are Copyright (c) 2003-2003 CognitiveWeb, Inc. All Rights Reserved. Contact information for CognitiveWeb, Inc. is available at http://www.CognitiveWeb.org Portions Copyright (c) 2002-2003 Bryan Thompson. Acknowledgements: Special thanks to the developers of the Jabber Open Source License 1.0 (JOSL), from which this License was derived. This License contains terms that differ from JOSL. Special thanks to the CognitiveWeb Open Source Contributors for their suggestions and support of the Cognitive Web. Modifications: */ package org.CognitiveWeb.extser; import java.io.IOException; import java.io.Serializable; import org.CognitiveWeb.extser.ISerializer; /** * Simple serialization interface. * * @see IStreamSerializer * * @author <a href="mailto:tho...@us...">Bryan Thompson</a> */ public interface ISimpleSerializer extends Serializable, ISerializer { /** * Serialize the persistent state of the object. * * @param obj * The object to be serialized (non-null). * * @return A byte[] containing the persistent state of the object. * * @throws IllegalArgumentException * If <code>obj == null</code>. */ public byte[] serialize( Object obj ) throws IOException; /** * Deserialize the persistent data for some object. * * @param data * A byte[] containing the persistent state of the object. * * @return The object. * * @throws IllegalArgumentException * If <code>data == null</code>. */ public Object deserialize( byte[] data ) throws IOException; } --- NEW FILE: ShortPacker.java --- /** The Notice below must appear in each file of the Source Code of any copy you distribute of the Licensed Product. Contributors to any Modifications may add their own copyright notices to identify their own contributions. License: The contents of this file are subject to the CognitiveWeb Open Source License Version 1.0 (the License). You may not copy or use this file, in either source code or executable form, except in compliance with the License. You may obtain a copy of the License from http://www.CognitiveWeb.org/legal/license/ Software distributed under the License is distributed on an AS IS basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. Copyrights: Portions created by or assigned to CognitiveWeb, Inc. are Copyright (c) 2003-2003 CognitiveWeb, Inc. All Rights Reserved. Contact information for CognitiveWeb, Inc. is available at http://www.CognitiveWeb.org Portions Copyright (c) 2002-2003 Bryan Thompson. Acknowledgements: Special thanks to the developers of the Jabber Open Source License 1.0 (JOSL), from which this License was derived. This License contains terms that differ from JOSL. Special thanks to the CognitiveWeb Open Source Contributors for their suggestions and support of the Cognitive Web. Modifications: */ /* * Created on Oct 24, 2005 */ package org.CognitiveWeb.extser; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; /** * Packing utility for non-negative <code>short</code> values. * * @author thompsonbry */ public class ShortPacker { public ShortPacker() { super(); } /** * Packs a non-negative short value into one or two bytes and writes them on * <i>os </i>. A short in [0:127] is packed into one byte. Larger values are * packed into two bytes. The high bit of the first byte is set if the value * was packed into two bytes. If the bit is set, clear the high bit, read * the next byte, and interpret the two bytes as a short value. Otherwise * interpret the byte as a short value. * * @return The #of bytes into which the value was packed. */ static public int packShort( DataOutput os, short v ) throws IOException { /* * You can only pack non-negative values with this method. */ if( v < 0 ) { throw new IllegalArgumentException( "negative value: v="+v ); } if( v > 127 ) { // the value requires two bytes. os.write( (byte)((0xff & (v >> 8))|0x80) ); // note: set the high bit. os.write( (byte)(0xff & v) ); return 2; } else { // the value fits in one byte. os.write( (byte)(0xff & v) ); return 1; } } /** * Unpack a non-negative short value from the input stream. * * @param is The input stream. * * @return The short value. * * @throws IOException */ static public short unpackShort( DataInput is ) throws IOException { short b = (short) is.readByte(); short v; if( ( b & 0x80 ) != 0 ) { // high bit is set. v = (short) (( b & 0x7f ) << 8); // clear the high bit and shift over one byte. b = is.readByte(); // read the next byte. v |= ( b & 0xff ); // and combine it together with the high byte. } else { // high bit is clear. v = b; // interpret the byte as a short value. } return (short) v; } /** * Returns the #of bytes into which a short value was packed based on the * first byte. * * @param firstByte The first byte. * * @return The #of bytes (either one (1) or two (2)). */ static public int getNBytes( byte firstByte ) { if( ( firstByte & 0x80 ) != 0 ) { return 2; } else { return 1; } } } --- NEW FILE: IStreamSerializer.java --- /** The Notice below must appear in each file of the Source Code of any copy you distribute of the Licensed Product. Contributors to any Modifications may add their own copyright notices to identify their own contributions. License: The contents of this file are subject to the CognitiveWeb Open Source License Version 1.0 (the License). You may not copy or use this file, in either source code or executable form, except in compliance with the License. You may obtain a copy of the License from http://www.CognitiveWeb.org/legal/license/ Software distributed under the License is distributed on an AS IS basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. Copyrights: Portions created by or assigned to CognitiveWeb, Inc. are Copyright (c) 2003-2003 CognitiveWeb, Inc. All Rights Reserved. Contact information for CognitiveWeb, Inc. is available at http://www.CognitiveWeb.org Portions Copyright (c) 2002-2003 Bryan Thompson. Acknowledgements: Special thanks to the developers of the Jabber Open Source License 1.0 (JOSL), from which this License was derived. This License contains terms that differ from JOSL. Special thanks to the CognitiveWeb Open Source Contributors for their suggestions and support of the Cognitive Web. Modifications: */ /* * Created on Oct 20, 2005 */ package org.CognitiveWeb.extser; import java.io.IOException; /** * Stream-oriented serializer for complex records (not blobs). This interface * MUST be used in conjunction with the {@link AbstractExtensibleSerializer}. * * @author thompsonbry * * @see ExtensibleSerializer */ public interface IStreamSerializer extends ISerializer { /** * Serialize an object. * * @param out Sink for the serialized object. * * @param obj The object to serialize (or null). * * @throws IOException */ public void serialize( DataOutput out, Object obj ) throws IOException; /** * Deserialize an object. * * @param in * Source for the serialized object. * * @param obj * An instance of the appropriate class whose persistent fields * need to be initialized from the input stream. * * @return The deserialized object. If desired, you can replace the <i>obj * </i> with another object by returning a different object here. * * @throws IOException */ public Object deserialize( DataInput in, Object obj ) throws IOException; } --- NEW FILE: ISerializer.java --- /** The Notice below must appear in each file of the Source Code of any copy you distribute of the Licensed Product. Contributors to any Modifications may add their own copyright notices to identify their own contributions. License: The contents of this file are subject to the CognitiveWeb Open Source License Version 1.0 (the License). You may not copy or use this file, in either source code or executable form, except in compliance with the License. You may obtain a copy of the License from http://www.CognitiveWeb.org/legal/license/ Software distributed under the License is distributed on an AS IS basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. Copyrights: Portions created by or assigned to CognitiveWeb, Inc. are Copyright (c) 2003-2003 CognitiveWeb, Inc. All Rights Reserved. Contact information for CognitiveWeb, Inc. is available at http://www.CognitiveWeb.org Portions Copyright (c) 2002-2003 Bryan Thompson. Acknowledgements: Special thanks to the developers of the Jabber Open Source License 1.0 (JOSL), from which this License was derived. This License contains terms that differ from JOSL. Special thanks to the CognitiveWeb Open Source Contributors for their suggestions and support of the Cognitive Web. Modifications: */ package org.CognitiveWeb.extser; import java.io.Serializable; /** * Interface used to provide a serialization mechanism other than the normal * Java serialization. * * @author thompsonbry */ public interface ISerializer extends Serializable { } --- NEW FILE: AbstractSingleton.java --- /** The Notice below must appear in each file of the Source Code of any copy you distribute of the Licensed Product. Contributors to any Modifications may add their own copyright notices to identify their own contributions. License: The contents of this file are subject to the CognitiveWeb Open Source License Version 1.0 (the License). You may not copy or use this file, in either source code or executable form, except in compliance with the License. You may obtain a copy of the License from http://www.CognitiveWeb.org/legal/license/ Software distributed under the License is distributed on an AS IS basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. Copyrights: Portions created by or assigned to CognitiveWeb, Inc. are Copyright (c) 2003-2003 CognitiveWeb, Inc. All Rights Reserved. Contact information for CognitiveWeb, Inc. is available at http://www.CognitiveWeb.org Portions Copyright (c) 2002-2003 Bryan Thompson. Acknowledgements: Special thanks to the developers of the Jabber Open Source License 1.0 (JOSL), from which this License was derived. This License contains terms that differ from JOSL. Special thanks to the CognitiveWeb Open Source Contributors for their suggestions and support of the Cognitive Web. Modifications: */ /* * Created on Nov 4, 2005 */ package org.CognitiveWeb.extser; import java.util.Map; import java.util.WeakHashMap; import org.CognitiveWeb.extser.IExtensibleSerializer; import org.CognitiveWeb.extser.Stateless; /** * Abstract base class for a {@link Stateless} singleton serialization handler * wrapping the semantics of a stateful {@link IExtensibleSerializer} * serialization handle. The use of this stateless singleton prevents multiple * copies of the state of the extensible serializer from being written into the * store. * <p> * * @author thompsonbry */ abstract public class AbstractSingleton implements Stateless { /** * Cache map from the persistence layer access object to the {@link * IExtensibleSerializer} instance for that access object. This is a * {@link WeakHashMap} so entries are transparently removed when the * corresponding access object is finalized by the garbage collector. */ static transient final private Map _cache = new WeakHashMap(); /** * Return the {@link IExtensibleSerializer} singleton for the store.<p> * * @exception IllegalStateException if the serializer has not been * set for the store. * * @see #setSerializer( Object obj, IExtensibleSerializer ser ) */ public IExtensibleSerializer getSerializer( Object obj ) throws IllegalStateException { if( obj == null ) { throw new IllegalArgumentException(); } IExtensibleSerializer ser = (IExtensibleSerializer) _cache.get ( obj ); if( ser == null ) { throw new IllegalStateException ( "Not initialized." ); } return ser; } /** * This method must be used to couple the access to the persistence layer * with a specific instance of a stateful {@link IExtensibleSerializer}. * Thereafter the serialization handler reference recovered from a static * transient cache managed by this class. * <p> * * @param accessObject * The access object for the persistence layer. * * @param ser * The serialization handler for the persistence layer. * * @exception IllegalStateException * If the serialization handler has already been set. */ public void setSerializer( Object accessObject, IExtensibleSerializer ser ) throws IllegalStateException { if( accessObject == null || ser == null ) { throw new IllegalArgumentException(); } if( _cache.get( accessObject ) != null ) { throw new IllegalStateException ( "Already initialized." ); } _cache.put( accessObject, ser ); } } --- NEW FILE: package.html --- <html> <body> <p>Extensible stream-based serialization with transparent versioning.</p> <dl> <dt><b>Version: </b></dt><dd>$Revision: 1.1 $ $Date: 2006/03/09 18:37:09 $</dd> <dt><b>Author: </b></dt><dd><a href="mailto:tho...@us...">Bryan Thompson</a></dd> </dl> </body> </html> --- NEW FILE: NativeType.java --- /** The Notice below must appear in each file of the Source Code of any copy you distribute of the Licensed Product. Contributors to any Modifications may add their own copyright notices to identify their own contributions. License: The contents of this file are subject to the CognitiveWeb Open Source License Version 1.0 (the License). You may not copy or use this file, in either source code or executable form, except in compliance with the License. You may obtain a copy of the License from http://www.CognitiveWeb.org/legal/license/ Software distributed under the License is distributed on an AS IS basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. Copyrights: Portions created by or assigned to CognitiveWeb, Inc. are Copyright (c) 2003-2003 CognitiveWeb, Inc. All Rights Reserved. Contact information for CognitiveWeb, Inc. is available at http://www.CognitiveWeb.org Portions Copyright (c) 2002-2003 Bryan Thompson. Acknowledgements: Special thanks to the developers of the Jabber Open Source License 1.0 (JOSL), from which this License was derived. This License contains terms that differ from JOSL. Special thanks to the CognitiveWeb Open Source Contributors for their suggestions and support of the Cognitive Web. Modifications: */ /* * Created on Nov 4, 2005 */ package org.CognitiveWeb.extser; import java.io.IOException; import java.lang.reflect.Array; /** * Used to assign classId codes to Java primitives, to arrays of Java * primitives, and to <code>Object[]</code>. Also provides some utility * methods for converting between a classId, a label for the class, and an * object that is an instance of the class. * * @author thompsonbry */ public class NativeType { /** * A <code>null</code>. */ final public static int NULL = 0x0; /* * Java primitive data types. */ final public static int BOOLEAN = 0x1; final public static int BYTE = 0x2; final public static int CHAR = 0x3; final public static int SHORT = 0x4; final public static int INT = 0x5; final public static int LONG = 0x6; final public static int FLOAT = 0x7; final public static int DOUBLE = 0x8; /* * Array of Java primitives. */ final public static int BOOLEAN_ARRAY = 0x9; final public static int BYTE_ARRAY = 0xa; final public static int CHAR_ARRAY = 0xb; final public static int SHORT_ARRAY = 0xc; final public static int INT_ARRAY = 0xd; final public static int LONG_ARRAY = 0xe; final public static int FLOAT_ARRAY = 0xf; final public static int DOUBLE_ARRAY = 0x10; /** * An array of Java objects (vs an array of primitives). */ final public static int OBJECT_ARRAY = 0x11; /** * The starting classId index assigned to Java Objects. */ final public static int FIRST_OBJECT_INDEX = 0x12; /** * Return true if the <i>classId </i> identifies a Java Object (vs a * Java primitive or an Array type). * * @param classId The classId. */ final public static boolean isJavaObject( int classId ) { return classId >= FIRST_OBJECT_INDEX; } /** * Return true iff the <i>classId </i> corresponds to a * <code>null</code>. * * @param classId The classId. */ final public static boolean isNull( int classId ) { return classId == NULL; } /** * Return true iff the <i>classId </i> corresponds to one of the Java * primitive datatypes {boolean, byte, char, short, int, long, float, or * double}. * * @param classId The classId. */ final public static boolean isPrimitive( int classId ) { return classId >= BOOLEAN && classId <= DOUBLE; } /** * Return true iff the <i>classId </i> corresponds to one of the * primitive array types, eg, <code>byte[]</code>. * * @param classId * The classId. */ final public static boolean isPrimitiveArrayType( int classId ) { return classId >= BOOLEAN_ARRAY && classId <= DOUBLE_ARRAY; } /** * Return true iff the <i>classId </i> corresponds to one of the * primitive array types, eg, <code>byte[]</code> or to an array of * some class, eg, <code>Object[]</code>,<code>String[]</code>, * etc. * * @param classId * The classId. */ final public static boolean isArrayType( int classId ) { return classId >= BOOLEAN_ARRAY && classId <= OBJECT_ARRAY; } /** * A human consumable name for the corresponding class. * * @param classId The classId. */ public static String asString( int classId ) { switch( classId ) { case NULL: return "null"; case BOOLEAN: return java.lang.Boolean.class.getName(); case BYTE: return java.lang.Byte.class.getName(); case CHAR: return java.lang.Character.class.getName(); case SHORT: return java.lang.Short.class.getName(); case INT: return java.lang.Integer.class.getName(); case LONG: return java.lang.Long.class.getName(); case FLOAT: return java.lang.Float.class.getName(); case DOUBLE: return java.lang.Double.class.getName(); case BOOLEAN_ARRAY: return "boolean[]"; case BYTE_ARRAY: return "byte[]"; case CHAR_ARRAY: return "char[]"; case SHORT_ARRAY: return "short[]"; case INT_ARRAY: return "int[]"; case LONG_ARRAY: return "long[]"; case FLOAT_ARRAY: return "float[]"; case DOUBLE_ARRAY: return "double[]"; case OBJECT_ARRAY: return "Object[]"; default: return "Object<"+classId+">"; } } /** * Return the {@link NativeType} for a Java Object. * * @param val * The Java Object (including arrays, nulls, etc.). * * @return The {@link NativeType} * * @exception UnsupportedOperationException * if there is no native type for that Java Object. */ public static int getNativeType( Object val ) { if( val == null ) return NULL; else if( val instanceof Boolean ) return BOOLEAN; else if( val instanceof Character ) return CHAR; else if( val instanceof Number ) { if( val instanceof Byte ) return BYTE; else if( val instanceof Short ) return SHORT; else if( val instanceof Integer ) return INT; else if( val instanceof Long ) return LONG; else if( val instanceof Float ) return FLOAT; else if( val instanceof Double ) return DOUBLE; else return FIRST_OBJECT_INDEX; // Java Object (implements Number). } else if( val.getClass().isArray() ) { // Array types. if( val.getClass().getComponentType().isPrimitive() ) { // Array of Java primitives. Class componentType = val.getClass().getComponentType(); if( componentType.equals( Boolean.TYPE ) ) return BOOLEAN_ARRAY; else if( componentType.equals( Byte.TYPE ) ) return BYTE_ARRAY; else if( componentType.equals( Character.TYPE ) ) return CHAR_ARRAY; else if( componentType.equals( Short.TYPE ) ) return SHORT_ARRAY; else if( componentType.equals( Integer.TYPE ) ) return INT_ARRAY; else if( componentType.equals( Long.TYPE ) ) return LONG_ARRAY; else if( componentType.equals( Float.TYPE ) ) return FLOAT_ARRAY; else if( componentType.equals( Double.TYPE ) ) return DOUBLE_ARRAY; else throw new AssertionError(); } else { // Array of Java Objects. We do not specialize any further than // this. return OBJECT_ARRAY; } } else { // Java Object. return FIRST_OBJECT_INDEX; } } /** * Serialize a null object wrapping a Java primitive or an array type on * the output stream. * * @param dos * @param classId * The classId assigned to that object. * @param obj * The object. * * FIXME Add multi-dimensional array serialization (and test cases). We * need to write out the #of dimensions and the length of each * dimension before we write out the elements in the array. * Traversal itself is difficult (and perhaps even impossible w/in * Java) since we need to cast to a strongly typed array type * before we can index into the array. If we can't support this in * any optimized manner then we need to detect multidimensional * arrays and route them through Java serialization. */ public static void serialize( DataOutput dos, int classId, Object obj ) throws IOException { switch( classId ) { case NULL: return; case BOOLEAN: dos.writeBoolean( ((Boolean)obj).booleanValue() ); return; case BYTE: dos.writeByte( ((Byte)obj).byteValue() ); return; case CHAR: dos.writeChar( ((Character)obj).charValue() ); return; case SHORT: dos.writeShort( ((Short)obj).shortValue() ); return; case INT: dos.writeInt( ((Integer)obj).intValue() ); return; case LONG: dos.writeLong( ((Long)obj).longValue() ); return; case FLOAT: dos.writeFloat( ((Float)obj).floatValue() ); return; case DOUBLE: dos.writeDouble( ((Double)obj).doubleValue() ); return; case BOOLEAN_ARRAY: { final boolean[] ary = (boolean[]) obj; final int len = ary.length; dos.writePackedInt( len ); for( int i=0; i<len; i++ ) { dos.writeBoolean( ary[ i ] ); } return; } case BYTE_ARRAY: { final byte[] ary = (byte[]) obj; final int len = ary.length; dos.writePackedInt( len ); for( int i=0; i<len; i++ ) { dos.writeByte( ary[ i ] ); } return; } case CHAR_ARRAY: { final char[] ary = (char[]) obj; final int len = ary.length; dos.writePackedInt( len ); for( int i=0; i<len; i++ ) { dos.writeChar( ary[ i ] ); } return; } case SHORT_ARRAY: { final short[] ary = (short[]) obj; final int len = ary.length; dos.writePackedInt( len ); for( int i=0; i<len; i++ ) { dos.writeShort( ary[ i ] ); } return; } case INT_ARRAY: { final int[] ary = (int[]) obj; final int len = ary.length; dos.writePackedInt( len ); for( int i=0; i<len; i++ ) { dos.writeInt( ary[ i ] ); } return; } case LONG_ARRAY: { final long[] ary = (long[]) obj; final int len = ary.length; dos.writePackedInt( len ); for( int i=0; i<len; i++ ) { dos.writeLong( ary[ i ] ); } return; } case FLOAT_ARRAY: { final float[] ary = (float[]) obj; final int len = ary.length; dos.writePackedInt( len ); for( int i=0; i<len; i++ ) { dos.writeFloat( ary[ i ] ); } return; } case DOUBLE_ARRAY: { final double[] ary = (double[]) obj; final int len = ary.length; dos.writePackedInt( len ); for( int i=0; i<len; i++ ) { dos.writeDouble( ary[ i ] ); } return; } case OBJECT_ARRAY: { // Note: The Class of the array component type is also written onto // the stream so that we can re-create the appropriate array type // when the Object[] is deserialized. final Object[] ary = (Object[]) obj; final Class componentType = ary.getClass().getComponentType(); final int componentTypeId = dos.getSerializationHandler().getClassId( componentType ); dos.writePackedInt( componentTypeId ); final int len = ary.length; dos.writePackedInt( len ); for( int i=0; i<len; i++ ) { dos.serialize( ary[ i ] ); } return; } default: throw new AssertionError("classId="+classId); } } /** * Reads a Java primitive or array type from the input stream. * * @param dis * @param classId * @param versionId * @return The deserialized object. * @throws IOException */ public static Object deserialize( DataInput dis, int classId, short versionId ) throws IOException { switch( classId ) { case NULL: return null; case BOOLEAN: { if( dis.readBoolean() ) { return Boolean.TRUE; } else { return Boolean.FALSE; } } case BYTE: return new Byte( dis.readByte() ); case CHAR: return new Character( dis.readChar() ); case SHORT: return new Short( dis.readShort() ); case INT: return new Integer( dis.readInt() ); case LONG: return new Long( dis.readLong() ); case FLOAT: return new Float( dis.readFloat() ); case DOUBLE: return new Double( dis.readDouble() ); case BOOLEAN_ARRAY: { final int len = dis.readPackedInt(); final boolean[] ary = new boolean[len]; for( int i=0; i<len; i++ ) { ary[ i ] = dis.readBoolean(); } return ary; } case BYTE_ARRAY: { final int len = dis.readPackedInt(); final byte[] ary = new byte[len]; for( int i=0; i<len; i++ ) { ary[ i ] = dis.readByte(); } return ary; } case CHAR_ARRAY: { final int len = dis.readPackedInt(); final char[] ary = new char[len]; for( int i=0; i<len; i++ ) { ary[ i ] = dis.readChar(); } return ary; } case SHORT_ARRAY: { final int len = dis.readPackedInt(); final short[] ary = new short[len]; for( int i=0; i<len; i++ ) { ary[ i ] = dis.readShort(); } return ary; } case INT_ARRAY: { final int len = dis.readPackedInt(); final int[] ary = new int[len]; for( int i=0; i<len; i++ ) { ary[ i ] = dis.readInt(); } return ary; } case LONG_ARRAY: { final int len = dis.readPackedInt(); final long[] ary = new long[len]; for( int i=0; i<len; i++ ) { ary[ i ] = dis.readLong(); } return ary; } case FLOAT_ARRAY: { final int len = dis.readPackedInt(); final float[] ary = new float[len]; for( int i=0; i<len; i++ ) { ary[ i ] = dis.readFloat(); } return ary; } case DOUBLE_ARRAY: { final int len = dis.readPackedInt(); final double[] ary = new double[len]; for( int i=0; i<len; i++ ) { ary[ i ] = dis.readDouble(); } return ary; } case OBJECT_ARRAY: { final int componentTypeId = dis.readPackedInt(); final Class componentType = dis.getSerializationHandler().getClass( componentTypeId ); final int len = dis.readPackedInt(); final Object[] ary = (Object[]) Array.newInstance( componentType, len ); for( int i=0; i<len; i++ ) { ary[ i ] = dis.deserialize(); } return ary; } default: throw new AssertionError("classId="+classId); } } } --- NEW FILE: LongPacker.java --- /** The Notice below must appear in each file of the Source Code of any copy you distribute of the Licensed Product. Contributors to any Modifications may add their own copyright notices to identify their own contributions. License: The contents of this file are subject to the CognitiveWeb Open Source License Version 1.0 (the License). You may not copy or use this file, in either source code or executable form, except in compliance with the License. You may obtain a copy of the License from http://www.CognitiveWeb.org/legal/license/ Software distributed under the License is distributed on an AS IS basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. Copyrights: Portions created by or assigned to CognitiveWeb, Inc. are Copyright (c) 2003-2003 CognitiveWeb, Inc. All Rights Reserved. Contact information for CognitiveWeb, Inc. is available at http://www.CognitiveWeb.org Portions Copyright (c) 2002-2003 Bryan Thompson. Acknowledgements: Special thanks to the developers of the Jabber Open Source License 1.0 (JOSL), from which this License was derived. This License contains terms that differ from JOSL. Special thanks to the CognitiveWeb Open Source Contributors for their suggestions and support of the Cognitive Web. Modifications: */ /* * Created on Oct 24, 2005 */ package org.CognitiveWeb.extser; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; /** * Packing utility for non-negative <code>long</code> values. * * @author thompsonbry */ public class LongPacker { public LongPacker() { super(); } /** * Packs a non-negative long value into the minimum #of bytes in which the * value can be represented and writes those bytes onto the output stream. * The first byte determines whether or not the long value was packed and, * if packed, how many bytes were required to represent the packed long * value. When the high bit of the first byte is a one (1), then the long * value could not be packed and the long value is found by clearing the * high bit and interpreting the first byte plus the next seven (7) bytes as * a long. Otherwise the next three (3) bits are interpreted as an unsigned * integer giving the #of bytes (nbytes) required to represent the packed * long value. To recover the long value the high nibble is cleared and the * first byte together with the next nbytes are interpeted as an unsigned * long value whose leading zero bytes were not written. * * <pre> * * [0|1|2|3|4|5|6|7] * 1 - - - nbytes = 8, clear high bit and interpret this plus the next 7 bytes as a long. * 0 1 1 1 nbytes = 7, clear high nibble and interpret this plus the next 6 bytes as a long. * 0 1 1 0 nbytes = 6, clear high nibble and interpret this plus the next 5 bytes as a long. * 0 1 0 1 nbytes = 5, clear high nibble and interpret this plus the next 4 bytes as a long. * 0 1 0 0 nbytes = 4, clear high nibble and interpret this plus the next 3 bytes as a long. * 0 0 1 1 nbytes = 3, clear high nibble and interpret this plus the next 3 bytes as a long. * 0 0 1 0 nbytes = 2, clear high nibble and interpret this plus the next byte as a long. * 0 0 0 1 nbytes = 1, clear high nibble. value is the low nibble. * * </pre> */ static public int packLong( DataOutput os, long v ) throws IOException { /* * You can only pack non-negative long values with this method. */ if( v < 0 ) { throw new IllegalArgumentException( "negative value: v="+v ); } /* * If the high byte is non-zero then we will write the value as a normal * long and return nbytes == 8. This case handles large positive long * values. */ if( ( v >> 56 ) != 0 ) { os.write( (byte)((0xff & (v >> 56))|0x80) ); // note: set the high bit. os.write( (byte)(0xff & (v >> 48)) ); os.write( (byte)(0xff & (v >> 40)) ); os.write( (byte)(0xff & (v >> 32)) ); os.write( (byte)(0xff & (v >> 24)) ); os.write( (byte)(0xff & (v >> 16)) ); os.write( (byte)(0xff & (v >> 8)) ); os.write( (byte)(0xff & v) ); return 8; } // #of nibbles required to represent the long value. final int nnibbles = getNibbleLength( v ); // Is [nnibbles] even? (If it is even then we need to pad out an extra zero // nibble in the first byte.) final boolean evenNibbleCount = ( nnibbles == ( ( nnibbles >> 1 ) << 1 ) ); // #of bytes required to represent the long value (plus the header nibble). final int nbytes = ( ( nnibbles +1 ) >> 1 ) + (evenNibbleCount?1:0); int nwritten = 0; if( evenNibbleCount ) { /* * An even nibble count requires that we pad the low nibble of the * first byte with zeros. */ // header byte. low nibble is empty. byte b = (byte) ( nbytes << 4 ); os.write( b ); nwritten++; // remaining bytes containing the packed value. for( int i=(nnibbles-2)<<2; i>=0; i-=8 ) { b = (byte) (0xff & (v >> i)); os.write( b ); nwritten++; } } else { /* * An odd nibble count means that we pack the first nibble of the * long value into the low nibble of the header byte. In this case * the first nibble will always be the low nibble of the first * non-zero byte in the long value (the high nibble of that byte * must be zero since there is an odd nibble count). */ byte highByte = (byte) (0xff & (v >> ((nbytes-1)*8) )); byte b = (byte) ( ( nbytes << 4 ) | highByte ); os.write( b ); nwritten++; for( int i=(nnibbles-3)<<2; i>=0; i-=8 ) { b = (byte) (0xff & (v >> i)); os.write( b ); nwritten++; } } return nwritten; } /** * Return the #of non-zero nibbles, counting from the first non-zero nibble * in the long value. A value of <code>0L</code> is considered to be one * nibble for our purposes. * * @param v * The long value. * * @return The #of nibbles in [1:16]. */ static protected int getNibbleLength( long v ) { for( int i=56, j=16; i>=0; i-=8, j-=2 ) { if( (0xf0 & (v >> i)) != 0 ) return j; if( (0x0f & (v >> i)) != 0 ) return j-1; } if( v != 0 ) throw new AssertionError( "v="+v ); return 1; // value is zero, which is considered to be one nibble for our purposes. } /** * Unpack a long value from the input stream. * * @param is The input stream. * * @return The long value. * * @throws IOException */ static public long unpackLong( DataInput is ) throws IOException { int b = is.readByte(); int nbytes; long l; if( ( b & 0x80 ) != 0 ) { // high bit is set. nbytes = 8; // use 8 bytes (this one plus the next 7). l = b & 0x7f; // clear the high bit - the rest of the byte is the start value. } else { // high bit is clear. nbytes = b >> 4; // nbytes is the upper nibble. (right shift one nibble). l = b & 0x0f; // starting value is lower nibble (clear the upper nibble). } for( int i=1; i<nbytes; i++ ) { // Read the next byte. b = is.readByte(); // readByte( is ); // Shift the existing value one byte left and add into the low (unsigned) byte. l = (l << 8) + (0xff & b); } return l; } } --- NEW FILE: StringSerializer.java --- /** The Notice below must appear in each file of the Source Code of any copy you distribute of the Licensed Product. Contributors to any Modifications may add their own copyright notices to identify their own contributions. License: The contents of this file are subject to the CognitiveWeb Open Source License Version 1.0 (the License). You may not copy or use this file, in either source code or executable form, except in compliance with the License. You may obtain a copy of the License from http://www.CognitiveWeb.org/legal/license/ Software distributed under the License is distributed on an AS IS basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. Copyrights: Portions created by or assigned to CognitiveWeb, Inc. are Copyright (c) 2003-2003 CognitiveWeb, Inc. All Rights Reserved. Contact information for CognitiveWeb, Inc. is available at http://www.CognitiveWeb.org Portions Copyright (c) 2002-2003 Bryan Thompson. Acknowledgements: Special thanks to the developers of the Jabber Open Source License 1.0 (JOSL), from which this License was derived. This License contains terms that differ from JOSL. Special thanks to the CognitiveWeb Open Source Contributors for their suggestions and support of the Cognitive Web. Modifications: */ /* * Created on Nov 8, 2005 */ package org.CognitiveWeb.extser; import java.io.IOException; /** * Serializer for Java {@link String}s. * * @author thompsonbry */ final public class StringSerializer implements ISimpleSerializer, Stateless { /** * The character set encoding used to serialize Java {@link String}s (UTF8). */ protected static final transient String charset = "UTF8"; public byte[] serialize(Object obj) throws IOException { return ((String)obj).getBytes(charset); } public Object deserialize(byte[] serialized) throws IOException { return new String( serialized, charset ); } } --- NEW FILE: DataOutput.java --- /** The Notice below must appear in each file of the Source Code of any copy you distribute of the Licensed Product. Contributors to any Modifications may add their own copyright notices to identify their own contributions. License: The contents of this file are subject to the CognitiveWeb Open Source License Version 1.0 (the License). You may not copy or use this file, in either source code or executable form, except in compliance with the License. You may obtain a copy of the License from http://www.CognitiveWeb.org/legal/license/ Software distributed under the License is distributed on an AS IS basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. Copyrights: Portions created by or assigned to CognitiveWeb, Inc. are Copyright (c) 2003-2003 CognitiveWeb, Inc. All Rights Reserved. Contact information for CognitiveWeb, Inc. is available at http://www.CognitiveWeb.org Portions Copyright (c) 2002-2003 Bryan Thompson. Acknowledgements: Special thanks to the developers of the Jabber Open Source License 1.0 (JOSL), from which this License was derived. This License contains terms that differ from JOSL. Special thanks to the CognitiveWeb Open Source Contributors for their suggestions and support of the Cognitive Web. Modifications: */ /* * Created on Sep 30, 2005 */ package org.CognitiveWeb.extser; import java.io.IOException; /** * Supports stream-based serialization of objects and packed integer values. * * @author thompsonbry */ public interface DataOutput extends java.io.DataOutput { /** * Return the logical row id (recid) of the record being (de-)serialized * or zero (0L) iff the record is being inserted into the store. */ abstract public long getRecid(); /** * The serialization handler. */ abstract public IExtensibleSerializer getSerializationHandler(); /** * Applies the serialization handler to serialize the next object onto the * output stream. * <p> * * @param obj * * @throws IOException */ abstract public void serialize( Object obj ) throws IOException; /** * Pack a non-negative long value onto the output stream. * * @param val * * @throws IOException * * @return The #of bytes in which the long value was packed. */ abstract public int writePackedLong( long val ) throws IOException; /** * Pack a non-negative int value onto the output stream. * * @param val The int value. * * @return The #of bytes written on the output stream. * * @throws IOException */ abstract public int writePackedInt( int val ) throws IOException; /** * Pack a non-negative short value onto the output stream. * * @param val The short value. * * @return The #of bytes written on the output stream. * * @throws IOException */ abstract public int writePackedShort( short val ) throws IOException; } --- NEW FILE: Stateless.java --- /** The Notice below must appear in each file of the Source Code of any copy you distribute of the Licensed Product. Contributors to any Modifications may add their own copyright notices to identify their own contributions. License: The contents of this file are subject to the CognitiveWeb Open Source License Version 1.0 (the License). You may not copy or use this file, in either source code or executable form, except in compliance with the License. You may obtain a copy of the License from http://www.CognitiveWeb.org/legal/license/ Software distributed under the License is distributed on an AS IS basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. Copyrights: Portions created by or assigned to CognitiveWeb, Inc. are Copyright (c) 2003-2003 CognitiveWeb, Inc. All Rights Reserved. Contact information for CognitiveWeb, Inc. is available at http://www.CognitiveWeb.org Portions Copyright (c) 2002-2003 Bryan Thompson. Acknowledgements: Special thanks to the developers of the Jabber Open Source License 1.0 (JOSL), from which this License was derived. This License contains terms that differ from JOSL. Special thanks to the CognitiveWeb Open Source Contributors for their suggestions and support of the Cognitive Web. Modifications: */ /* * Created on Oct 5, 2005 */ package org.CognitiveWeb.extser; import java.io.Serializable; /** * Classes which implement this interface make a declaration that their * instances have NO persistent state. This makes possible certain * optimizations, e.g., the {@link AbstractExtensibleSerializer} will only write * the <code>classId</code> for such objects rather than using {@link * java.io.ObjectOutput} to serialize their state. * * @author thompsonbry */ public interface Stateless extends Serializable { // marker interface. } --- NEW FILE: AbstractExtensibleSerializer.java --- /** The Notice below must appear in each file of the Source Code of any copy you distribute of the Licensed Product. Contributors to any Modifications may add their own copyright notices to identify their own contributions. License: The contents of this file are subject to the CognitiveWeb Open Source License Version 1.0 (the License). You may not copy or use this file, in either source code or executable form, except in compliance with the License. You may obtain a copy of the License from http://www.CognitiveWeb.org/legal/license/ Software distributed under the License is distributed on an AS IS basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations [...1580 lines suppressed...] } } else { // We have run out of options. This should never happen since // we managed to serialize the object in the first place. throw new UnsupportedOperationException ( "Do not know how to deserialize: class="+ser.getClassName( classId ) ); } } } } } --- NEW FILE: IExtensibleSerializer.java --- /** The Notice below must appear in each file of the Source Code of any copy you distribute of the Licensed Product. Contributors to any Modifications may add their own copyright notices to identify their own contributions. License: The contents of this file are subject to the CognitiveWeb Open Source License Version 1.0 (the License). You may not copy or use this file, in either source code or executable form, except in compliance with the License. You may obtain a copy of the License from http://www.CognitiveWeb.org/legal/license/ Software distributed under the License is distributed on an AS IS basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. Copyrights: Portions created by or assigned to CognitiveWeb, Inc. are Copyright (c) 2003-2003 CognitiveWeb, Inc. All Rights Reserved. Contact information for CognitiveWeb, Inc. is available at http://www.CognitiveWeb.org Portions Copyright (c) 2002-2003 Bryan Thompson. Acknowledgements: Special thanks to the developers of the Jabber Open Source License 1.0 (JOSL), from which this License was derived. This License contains terms that differ from JOSL. Special thanks to the CognitiveWeb Open Source Contributors for their suggestions and support of the Cognitive Web. Modifications: */ /* * Created on Nov 4, 2005 */ package org.CognitiveWeb.extser; import java.io.Externalizable; import java.io.IOException; import org.CognitiveWeb.extser.profiler.Profiler; /** * Interface for an extensible serialization handler. * <p> * * The extensible serialization handler that figures out how to serialize and * de-serialize objects using a metadata header for for each serialized object. * Tuned serialization is provided for the Java classes corresponding to the * primitive datatypes ({@link Long},{@link String}, etc.), the * {@link Stateless} interface, and the {@link Externalizable} interface. Custom * serializers may be written using either the {@link ISimpleSerializer} or the * {@link IStreamSerializer} interface. Serializer registrations are persistent. * <p> * * A serializer is registered for a Java Class and a versionId. The default * versionId is zero(0). The serializer registered against a given version is * always used to deserialize that version of a class. An instance of a class is * serialized using the default versionId (0) unless a versionId is explicitly * declared using: * * <pre> * static public short SERIAL_VERSION_ID = { versionId }; * </pre> * * <p> * * A persistent serializer may be explicitly specified on a per instance basis * using the {@link SerializerIdProtocol}. * <p> * * @todo Replace field for versionId with VersionIdProtocol interface? This * would let us drop the versionId cache and make it viable to have the * versionId be specified as a class method or an instance method. * * @author thompsonbry */ public interface IExtensibleSerializer extends ISerializer { /** * The name of the optional public field coding the versionId on a class * whose instance is being (de-)serialized. When the field is not present * the versionId is zero (0). When present the field must be a <em>short</em> * value coding the versionId under which the class will be serialized. * * <pre> * SERIAL_VERSION_ID * </pre> */ static public final String VERSION_FIELD_NAME = "SERIAL_VERSION_ID"; /** * Return the versionId used to serialize an instance of <i>cl </i>. A class * denotes the versionId used when it is serialized by making a declaration: * * <pre> * static public short SERIAL_VERSION_ID = { versionId }; * </pre> * * The modifier <em>final</em> is normally used but not strictly required. * <p> * * The versionId associated with a Class is cached. * <p> * * @param cl * The Class whose instance is being serialized (required). * * @return The versionId or zero if the object is unversioned. * * @exception IOException * * @see #VERSION_FIELD_NAME * @see #invalidateVersionIdCache(Class cl) */ public short getVersionId(Class cl) throws IOException; /** * Return the recid of the {@link Serializer}to be fetched and used to * (de-)serialize the object or zero (0L) if there is no serializer instance * to be used. A class may choose to report a non-zero <code>serializerId</code> * by implementing the {@link SerializerIdProtocol} interface. * * @param obj * The object being serialized. (The serializerId is read from a * binary header during deserialization.) * * @return The recid of the {@link Serializer}to be fetched or 0L if there * is no per-instance persistent serializer. * * @exception IOException */ public long getSerializerId(long recid, Object obj) throws IOException; /** * Return the #of registered classes. Classes may be explicitly * registered against one or more serializers or may be implicitly * registered as they are encountered during serialization. * * @return The #of registered classes. */ public int getClassCount(); /** * Return a unique classId for the object. The class name for the classId * may be obtained using {@link #getClassName( int classId)}. If the class * was not already registered, then it is registered now. * * @param cl * The class (required). * * @return A classId. Note that <code>classId == 0</code> is reserved to * indicate a <code>null</code> reference. */ public int getClassId(Class cl) throws IOException; /** * Registers a class. This operation does not affect the serializer(s) * registered for that class. It just assures that a classId has been * assigned for the class. * * @param cl * The class. * * @return true iff the state of the serializer was changed by this * registration. */ public boolean registerClass(Class cl) throws IOException; /** * Registers a serializer against an unversioned class. * * @param cl * The class. * * @param serializer * The class which implements the serializer for <i>cl </i>. This * class MUST have a public zero argument constructor and MUST * NOT have persistent state, i.e., it should declare the * {@link Stateless}interface. * * @return true iff the state of the serializer was changed by this * registration. */ public boolean registerSerializer(Class cl, Class serializerClass) throws IOException; /** * Registers a serializer against a class. When the <i>versionId </i> is * non-zero, then the serializer only applies to that version of the class. * The version information is stored in the data header of the record. An * unversioned class does not store a versionId. A bit is reserved to mark a * record written using a serializer specific to a class version. When the * bit is set, then versionId is read and the correct serialized for that * class version is used to deserialize the record. * * @param cl * The class. * * @param serializer * The class which implements the serializer for <i>cl </i>. This * class MUST have a public zero argument constructor and MUST * NOT have persistent state, i.e., it should declare the * {@link Stateless}interface. * * @param versionId * The versionId begins at one. The value of zero (0) is reserved * to indicate a class that does not have a version (a zero * versionId is exactly equivilent to an unversioned class). An * unversioned class may be promoted to a versioned class at any * time. Likewise, a class may be reverted to an earlier version * or to the "unversioned" version. * * @return true iff the state of the serializer was changed by this * registration. */ public boolean registerSerializer(Class cl, Class serializerClass, short versionId) throws IOException; /** * Decodes a classId into the class name. * * @param classId * A classId. * * @return The name of the class or <code>null</code> iff <i>classId == * {@link NativeType#NULL}</i>. * * @see #getClassId( Class cl ) * * @exception IllegalArgumentException * if <i>classId </i> was not registered. */ public String getClassName(int classId) throws IOException; /** * Return the {@link Class} given the classId. * * @param classId The classId. * * @return The class. * * @throws IOException */ public Class getClass(int classId) throws IOException; /** * Return the {@link ISerializer} registered against <i>classId </i>. * * @param classId * The classId. * * @return The serializer or <code>null</code> if no serializer is * ... [truncated message content] |