db-jdo-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From m..@apache.org
Subject svn commit: r158176 [25/79] - in incubator/jdo/trunk/ri11: ./ src/ src/conf/ src/java/ src/java/org/ src/java/org/apache/ src/java/org/apache/jdo/ src/java/org/apache/jdo/ejb/ src/java/org/apache/jdo/enhancer/ src/java/org/apache/jdo/impl/ src/java/org/apache/jdo/impl/enhancer/ src/java/org/apache/jdo/impl/enhancer/classfile/ src/java/org/apache/jdo/impl/enhancer/core/ src/java/org/apache/jdo/impl/enhancer/generator/ src/java/org/apache/jdo/impl/enhancer/meta/ src/java/org/apache/jdo/impl/enhancer/meta/model/ src/java/org/apache/jdo/impl/enhancer/meta/prop/ src/java/org/apache/jdo/impl/enhancer/meta/util/ src/java/org/apache/jdo/impl/enhancer/util/ src/java/org/apache/jdo/impl/fostore/ src/java/org/apache/jdo/impl/jdoql/ src/java/org/apache/jdo/impl/jdoql/jdoqlc/ src/java/org/apache/jdo/impl/jdoql/scope/ src/java/org/apache/jdo/impl/jdoql/tree/ src/java/org/apache/jdo/impl/model/ src/java/org/apache/jdo/impl/model/java/ src/java/org/apache/jdo/impl/model/java/runtime/ src/java/org/apache/jdo/impl/model/jdo/ src/java/org/apache/jdo/impl/model/jdo/caching/ src/java/org/apache/jdo/impl/model/jdo/util/ src/java/org/apache/jdo/impl/model/jdo/xml/ src/java/org/apache/jdo/impl/pm/ src/java/org/apache/jdo/impl/sco/ src/java/org/apache/jdo/impl/state/ src/java/org/apache/jdo/jdoql/ src/java/org/apache/jdo/jdoql/tree/ src/java/org/apache/jdo/model/ src/java/org/apache/jdo/model/java/ src/java/org/apache/jdo/model/jdo/ src/java/org/apache/jdo/pm/ src/java/org/apache/jdo/sco/ src/java/org/apache/jdo/state/ src/java/org/apache/jdo/store/ src/java/org/apache/jdo/util/ test/ test/conf/ test/enhancer/ test/enhancer/sempdept/ test/enhancer/sempdept/src/ test/enhancer/sempdept/src/empdept/ test/fsuid2/ test/fsuid2/org/ test/fsuid2/org/apache/ test/fsuid2/org/apache/jdo/ test/fsuid2/org/apache/jdo/pc/ test/java/ test/java/org/ test/java/org/apache/ test/java/org/apache/jdo/ test/java/org/apache/jdo/impl/ test/java/org/apache/jdo/impl/fostore/ test/java/org/apache/jdo/pc/ test/java/org/apache/jdo/pc/appid/ test/java/org/apache/jdo/pc/empdept/ test/java/org/apache/jdo/pc/serializable/ test/java/org/apache/jdo/pc/xempdept/ test/java/org/apache/jdo/test/ test/java/org/apache/jdo/test/query/ test/java/org/apache/jdo/test/util/ test/jdo/ test/jdo/org/ test/jdo/org/apache/ test/jdo/org/apache/jdo/ test/jdo/org/apache/jdo/pc/ test/jdo/org/apache/jdo/pc/appid/ test/jdo/org/apache/jdo/pc/empdept/ test/jdo/org/apache/jdo/pc/serializable/ test/jdo/org/apache/jdo/pc/xempdept/ xdocs/
Date Sat, 19 Mar 2005 01:06:03 GMT
Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/ObjectTranscriber.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/ObjectTranscriber.java?view=auto&rev=158176
==============================================================================
--- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/ObjectTranscriber.java (added)
+++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/ObjectTranscriber.java Fri Mar 18 17:02:29 2005
@@ -0,0 +1,1858 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+ */
+
+package org.apache.jdo.impl.fostore;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.lang.reflect.Array;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.Collection;
+import java.util.Calendar;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.TimeZone;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.Vector;
+
+import javax.jdo.JDOHelper;
+import javax.jdo.JDOUserException;
+import javax.jdo.spi.PersistenceCapable;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.apache.jdo.impl.sco.Freezer;
+import org.apache.jdo.pm.PersistenceManagerInternal;
+import org.apache.jdo.sco.SCOCollection;
+import org.apache.jdo.sco.SCOMap;
+import org.apache.jdo.state.StateManagerInternal;
+import org.apache.jdo.store.Transcriber;
+import org.apache.jdo.util.I18NHelper;
+
+//
+// Transcribers for non-primitives.  ObjectTranscriber is, like the primitive
+// transcribers, a singleton.  Lexically within it is an AbstractTranscriber,
+// which is the base of other transcribers for e.g. Bytes and arrays.
+//
+
+/**
+* Transcribes all non-primitive, non-String values.  This includes immutable
+* types (e.g. Boolean).  Values which are object references are represented
+* by their OID's, except for values which are Collections.  These are
+* represented out 'inline', that is, information about the kind of collection
+* is first transcribed (e.g., hashtable vs. vector, etc.) and then the values
+* in the collection themselves are transcribed.
+*
+* @author Dave Bristor
+* @version 1.0.1
+*/
+class ObjectTranscriber extends FOStoreTranscriber {
+    // PM on whose behalf we are storing an object, and potentially an object
+    // graph.  Used to get an OID for a PersistenceCapable.  Set by
+    // storeObject.
+    private PersistenceManagerInternal pm;
+
+    // Offsets of provisonal OID's stored.  The ArrayList is created and
+    // destroyed by one of the storeObject methods.
+    protected ArrayList offsets;
+    
+    // A different transcriber for each immutable object type
+    private static HashMap transcribers = new HashMap();
+
+    // Support for transcribing arrays of PersistenceCapables.
+    private static /*final*/ ObjArrayTranscriber objArrayTranscriber;
+
+    // Support for transcribing SCO's and their non-SCO equivalents
+    private static /*final*/ DateTranscriber dateTranscriber;
+    private static /*final*/ ArrayListTranscriber arrayListTranscriber;
+    private static /*final*/ VectorTranscriber vectorTranscriber;
+    private static /*final*/ HashSetTranscriber hashSetTranscriber;
+    private static /*final*/ TreeSetTranscriber treeSetTranscriber;
+    private static /*final*/ LinkedListTranscriber linkedListTranscriber;
+    private static /*final*/ HashMapTranscriber hashMapTranscriber;
+    private static /*final*/ HashtableTranscriber hashtableTranscriber;
+    private static /*final*/ TreeMapTranscriber treeMapTranscriber;
+
+    /** I18N support. */
+    private static final I18NHelper msg = I18NHelper.getInstance(I18N.NAME);
+
+    /** Logger */
+    static final Log logger = LogFactory.getFactory().getInstance(
+        "org.apache.jdo.impl.fostore"); // NOI18N
+
+    /** Default value for allow nulls in SCO collections and maps. */
+    private static final boolean DEFAULT_ALLOW_NULLS = true;
+
+    /** Default value for element, key, and value types in SCO collections
+    * and maps. */
+    private static final String DEFAULT_TYPE = "java.lang.Object"; // NOI18N
+
+    // We would like to do this static-ally, but member classes cannot be
+    // created in a static block in the class of which they are members.
+    ObjectTranscriber() {
+        objArrayTranscriber = new ObjArrayTranscriber();
+        dateTranscriber = new DateTranscriber();
+        arrayListTranscriber = new ArrayListTranscriber();
+        vectorTranscriber = new VectorTranscriber();
+        hashSetTranscriber = new HashSetTranscriber();
+        treeSetTranscriber = new TreeSetTranscriber();
+        linkedListTranscriber = new LinkedListTranscriber();
+        hashMapTranscriber = new HashMapTranscriber();
+        hashtableTranscriber = new HashtableTranscriber();
+        treeMapTranscriber = new TreeMapTranscriber();
+
+        // Keep this list in sync with the list in in CLID.java.  (No code
+        // should assume that, but it makes keeping both lists up-to-date just
+        // that much easier.)
+
+        // Immutables
+        transcribers.put(Boolean.class,    new ImmutableBooleanTranscriber());
+        transcribers.put(Character.class,  new ImmutableCharacterTranscriber());
+        transcribers.put(Byte.class,       new ImmutableByteTranscriber());
+        transcribers.put(Short.class,      new ImmutableShortTranscriber());
+        transcribers.put(Integer.class,    new ImmutableIntegerTranscriber());
+        transcribers.put(Long.class,       new ImmutableLongTranscriber());
+        transcribers.put(Float.class,      new ImmutableFloatTranscriber());
+        transcribers.put(Double.class,     new ImmutableDoubleTranscriber());
+
+        // String
+        transcribers.put(String.class,     new ImmutableStringTranscriber());
+
+        // Collections for which we don't have an SCO equivalent
+
+        // Maps for which we don't have an SCO equivalent
+        //transcribers.put(TreeMap.class,    new TreeMapTranscriber());
+
+        // Numbers
+        transcribers.put(BigDecimal.class, new BigDecimalTranscriber());
+        transcribers.put(BigInteger.class, new BigIntegerTranscriber());
+
+        // BitSet
+        transcribers.put(BitSet.class,     new BitSetTranscriber());
+
+        // Locale
+        transcribers.put(Locale.class,     new LocaleTranscriber());
+
+        // Arrays of primitives & String
+        transcribers.put(CLID.booleanArray.getClass(),
+                         new BooleanArrayTranscriber());
+        transcribers.put(CLID.charArray.getClass(),
+                         new CharArrayTranscriber());
+        transcribers.put(CLID.byteArray.getClass(),
+                         new ByteArrayTranscriber());
+        transcribers.put(CLID.shortArray.getClass(),
+                         new ShortArrayTranscriber());
+        transcribers.put(CLID.intArray.getClass(),
+                         new IntArrayTranscriber());
+        transcribers.put(CLID.longArray.getClass(),
+                         new LongArrayTranscriber());
+        transcribers.put(CLID.floatArray.getClass(),
+                         new FloatArrayTranscriber());
+        transcribers.put(CLID.doubleArray.getClass(),
+                         new DoubleArrayTranscriber());
+        transcribers.put(CLID.StringArray.getClass(),
+                         new StringArrayTranscriber());
+
+        // Simple SCO's and their non-SCO equivalents
+        transcribers.put(org.apache.jdo.impl.sco.Date.class, dateTranscriber);
+        transcribers.put(java.util.Date.class, dateTranscriber);
+        transcribers.put(org.apache.jdo.impl.sco.SqlDate.class, dateTranscriber);
+        transcribers.put(java.sql.Date.class, dateTranscriber);
+        // Calendars use date as their representation,
+        transcribers.put(java.util.Calendar.class, dateTranscriber);
+
+        // Collection SCO's and their non-SCO equivalents
+        transcribers.put(java.util.ArrayList.class, arrayListTranscriber);
+        transcribers.put(org.apache.jdo.impl.sco.ArrayList.class,
+                         arrayListTranscriber);
+        transcribers.put(java.util.Vector.class, vectorTranscriber);
+        transcribers.put(org.apache.jdo.impl.sco.Vector.class,
+                         vectorTranscriber);
+        transcribers.put(java.util.HashSet.class, hashSetTranscriber);
+        transcribers.put(org.apache.jdo.impl.sco.HashSet.class,
+                         hashSetTranscriber);
+        transcribers.put(java.util.TreeSet.class, treeSetTranscriber);
+        transcribers.put(org.apache.jdo.impl.sco.TreeSet.class,
+                         treeSetTranscriber);
+        transcribers.put(java.util.LinkedList.class, linkedListTranscriber);
+        transcribers.put(org.apache.jdo.impl.sco.LinkedList.class,
+                         linkedListTranscriber);
+        transcribers.put(java.util.HashMap.class, hashMapTranscriber);
+        transcribers.put(org.apache.jdo.impl.sco.HashMap.class,
+                         hashMapTranscriber);
+        transcribers.put(java.util.Hashtable.class, hashtableTranscriber);
+        transcribers.put(org.apache.jdo.impl.sco.Hashtable.class,
+                         hashtableTranscriber);
+        transcribers.put(java.util.TreeMap.class, treeMapTranscriber);
+        transcribers.put(org.apache.jdo.impl.sco.TreeMap.class,
+                         treeMapTranscriber);
+
+        initSupported();
+    }
+    
+
+    // We can't treat this in the "normal" fashion; when we try we get a
+    // NullPointerException in creating the Immutable* transcribers.
+    static ObjectTranscriber getInstance() {
+        return FOStoreTranscriber.objectTranscriber;
+    }
+    
+    /**
+     * Stores an object on the given FOStoreOutput by delegating to the other
+     * storeObject method after stashing away pm.
+     */
+    // XXX PERF syncronized to protect from MT access to the "offsets" field,
+    // but we do *not* want synchronization here.
+    synchronized int[] storeObject(Object value, FOStoreOutput out,
+                      PersistenceManagerInternal pm) throws IOException {
+        // pm could be null if, for example, value is-a String.
+        this.pm = pm;
+
+        offsets = new ArrayList();
+
+        int rc[] = storeObject(value, out);
+
+        offsets = null; // Allow GC to reclaim.
+
+        return rc;
+    }
+
+    /**
+    * Stores an object on the given FOStoreOutput.  An object is always
+    * stored by first storing it's CLID.  If the value is null, instead of
+    * the OID, we write CLID.nullOID, followed by an integer 0...this is OK,
+    * because metadata will tell us type of thing that is null.  If it's not
+    * null...well, it writes the object's CLID and value.
+    * @return null if there were no provisional OID's stored while storing
+    * this object, otherwise an array of offsets into the given output
+    * stream.  The array will have at least one element.
+    */
+    // This MUST be kept in sync with fetchObject!!
+    synchronized protected int[] storeObject(Object value, FOStoreOutput out)
+        throws IOException {
+
+        if (null == value) {
+            // Object's value is null
+            CLID.nullCLID.write(out);
+            out.writeInt(0);
+        } else {
+            // Value is not null, class could be 'known', as per above table
+            Class cls = value.getClass();
+            AbstractTranscriber t = (AbstractTranscriber)transcribers.get(cls);
+            if (null != t) {
+                // If we've got an AbstractTranscriber it *must* be a known
+                // type.
+                CLID.writeForKnown(cls, out);
+                t.store(value, out);
+                
+            } else if (value instanceof PersistenceCapable) {
+                // The value is-a PersistenceCapable.  Write it's OID.
+                CLID.forOID.write(out);
+
+                OID oid = (OID)pm.getInternalObjectId(value);
+
+                if (oid.isProvisional()) {
+                    offsets.add(new Integer(out.getPos()));
+                    if (logger.isDebugEnabled()) {
+                        logger.debug("FOT.sO: " + oid + " pos=" + // NOI18N
+                                       out.getPos());
+                    }
+                }
+                oid.write(out);
+                
+            } else if (cls.isArray()) {
+                // It could be an "unknown" array, that is, one not directly
+                // supported by the above table of transcribers.
+                //
+                // For now, at least, we only support arrays of the above, and
+                // of PersistenceCapable objects, by storing OIDs.
+                // XXX TBD Model: Add ability to embed PC objects.
+                Class componentType = cls.getComponentType();
+                if (isSupportedArrayType(componentType)) {
+                    if (logger.isDebugEnabled()) {
+                        logger.debug("FOT.sO: objArray " + cls.getName()); // NOI18N
+                    }
+                    CLID.forOIDArray.write(out);
+                    out.writeUTF(componentType.getName());
+                    objArrayTranscriber.store(value, out);
+                } else {
+                    throw new FOStoreUnsupportedException(
+                        msg.msg("EXC_UnsupportedArrayType", // NOI18N
+                             componentType.getName()));
+                }
+                
+            } else {
+                // What IS this thing???
+                throw new FOStoreFatalInternalException(
+                    this.getClass(), "storeObject", // NOI18N
+                    msg.msg("ERR_NoTranscriberForClass", cls)); // NOI18N
+            }
+        }
+        int size = 0;
+        if (null != offsets) {
+            size = offsets.size();
+        }
+        int rc[] = null;
+        if (size > 0) {
+            rc = new int[size];
+            for (int i = 0; i < size; i++) {
+                rc[i] = ((Integer)offsets.get(i)).intValue();
+            }
+        }
+        return rc;
+    }            
+
+    //
+    // Putting this declaration and static block here is probably heresy by
+    // someone's Java coding standards.  But!  This is *only* used by
+    // isSupportedArrayType, and Java does not support function-local statics
+    // (which good ol' C does).  If (when?) Java does support that capability,
+    // move these into that function.
+    //
+    private static final HashSet supported = new HashSet();
+    private static boolean initSupported = false;
+
+    // This would be a static block, except that Java does not support static
+    // blocks inside inner classes.  It is called from ObjectTranscriber().
+    private void initSupported() {
+        if (! initSupported) {
+            initSupported = true;
+            
+            supported.add(Boolean.class);
+            supported.add(Character.class);
+            supported.add(Byte.class);
+            supported.add(Short.class);
+            supported.add(Integer.class);
+            supported.add(Long.class);
+            supported.add(Float.class);
+            supported.add(Double.class);
+
+            // String
+            supported.add(String.class);
+
+            supported.add(java.math.BigDecimal.class);
+            supported.add(java.math.BigInteger.class);
+            supported.add(java.util.BitSet.class);
+            supported.add(java.util.Date.class);
+            supported.add(java.util.Locale.class);
+            supported.add(org.apache.jdo.impl.sco.Date.class);
+
+            supported.add(ArrayList.class);
+            supported.add(HashMap.class);
+            supported.add(Hashtable.class);
+            supported.add(HashSet.class);
+            supported.add(LinkedList.class);
+            supported.add(TreeMap.class);
+            supported.add(TreeSet.class);
+            supported.add(Vector.class);
+        }
+    }
+    
+    // Returns true if cls is one we can support as an element of an array
+    //
+    private boolean isSupportedArrayType(Class cls) {
+        boolean rc =
+            PersistenceCapable.class.isAssignableFrom(cls);
+        if ( !rc) {
+            rc = supported.contains(cls);
+        }
+        return rc;
+    }
+    
+    /**
+    * Retrieves an object from the given DataInput by delegating to the other
+    * fetchObject method after stashing away pm
+    */
+    Object fetchObject(DataInput in, Object owner, int fieldNum,
+                       PersistenceManagerInternal pm)
+        throws IOException, Exception {
+
+        this.pm = pm;
+        
+        return fetchObject(in, owner, fieldNum);
+    }
+
+    /**
+    * Retrieves an object from the given DataInput.  If it is an SCO, then the
+    * SCO's owner is set to the given owner.
+    */
+    // This MUST be kept in sync with storeObject!
+    protected Object fetchObject(DataInput in, Object owner, int fieldNum)
+        throws IOException, Exception {
+
+        Object rc = null;
+        
+        CLID clid = CLID.read(in);
+        if (logger.isDebugEnabled()) {
+            logger.debug("OT.fetchObject: " + clid); // NOI18N
+        }
+        
+        if (CLID.nullCLID.equals(clid)) {
+            // Object's value is null
+            in.readInt();
+
+        } else if (CLID.forOID.equals(clid)) {
+            // Object is-a PersistenceCapable.  Return a hollow PC.
+            OID oid = OID.read(in);
+            FOStorePMF pmf = (FOStorePMF)pm.getPersistenceManagerFactory();
+            rc = pm.getStateManager(oid, oid.getPCClass(pmf)).getObject();
+            if (logger.isDebugEnabled()) {
+                logger.debug("OT.fetchObject: " + oid); // NOI18N
+            }
+
+        } else if (CLID.forOIDArray.equals(clid)) {
+            String clsName = in.readUTF();
+            Object obj = ((StateManagerInternal)owner).getObject();
+            objArrayTranscriber.setComponentType(
+                loadClass(clsName, obj));
+            rc = objArrayTranscriber.fetch(in, owner, fieldNum);
+
+        } else {
+            // Object could be of a 'known' type.  Note that this doesn't use
+            // the above table!
+            Class cls = CLID.getKnownType(clid);
+            if (logger.isDebugEnabled()) {
+                logger.debug("OT.fetchObject known: " + cls.getName()); // NOI18N
+            }
+
+            if (null != cls) {
+                AbstractTranscriber t =
+                    (AbstractTranscriber)transcribers.get(cls);
+                
+                if (null != t) {
+                    rc = t.fetch(in, owner, fieldNum);
+                } else {
+                    throw new FOStoreUnsupportedException(
+                        msg.msg("EXC_ClassNotTranscribable", cls)); // NOI18N
+                }
+            }
+        }
+        return rc;
+    }
+
+    /**
+    * Skips an object's bytes from the given DataInput.  
+    */
+    protected void skip(DataInput in)
+        throws IOException {
+
+        skipObject(in);
+    }
+
+    /**
+    * Skips an object's bytes from the given DataInput.  
+    */
+    // This MUST be kept in sync with storeObject!
+    protected void skipObject(DataInput in)
+        throws IOException {
+
+        CLID clid = CLID.read(in);
+        if (logger.isDebugEnabled()) {
+            logger.debug("OT.skip: " + clid); // NOI18N
+        }
+        
+        if (CLID.nullCLID.equals(clid)) {
+            // Object's value is null
+            in.readInt();
+
+        } else if (CLID.forOID.equals(clid)) {
+            // Object is-a PersistenceCapable.  Read OID bytes only.
+            OID.skip(in);
+
+        } else if (CLID.forOIDArray.equals(clid)) {
+            in.readUTF(); // clsName
+            objArrayTranscriber.skip(in);
+
+        } else {
+            // Object could be of a 'known' type.  Note that this doesn't use
+            // the above table!
+            Class cls = CLID.getKnownType(clid);
+            if (logger.isDebugEnabled()) {
+                logger.debug("OT.skipObject known: " + cls.getName()); // NOI18N
+            }
+
+            if (null != cls) {
+                AbstractTranscriber t =
+                    (AbstractTranscriber)transcribers.get(cls);
+                
+                if (null != t) {
+                    t.skip(in);
+                } else {
+                    throw new FOStoreUnsupportedException(
+                        msg.msg("EXC_ClassNotTranscribable", cls)); // NOI18N
+                }
+            }
+        }
+    }
+    /**
+    * An AbstractTranscriber knows how to transcribe one (and only one) kind
+    * of object.  This is abstract class instead of interface to avoid
+    * 'publicity' of methods.
+    */
+    abstract class AbstractTranscriber implements Transcriber {
+        abstract void store(Object value, FOStoreOutput out)
+            throws IOException;
+
+        abstract Object fetch(DataInput in, Object owner, int fieldNum)
+            throws Exception;
+
+        abstract void skip(DataInput in)
+            throws IOException;
+    }
+
+    //
+    // Following are Transcribers for immutables.
+    //
+    
+    abstract class ImmutableTranscriber extends AbstractTranscriber {
+        Object fetch(DataInput in, Object owner, int fieldNum)
+            throws Exception{
+
+                return fetch(in);
+        }
+
+        // Immutables *never* need owner, nor fieldNum
+        abstract Object fetch(DataInput in) throws Exception;
+
+        abstract void skip(DataInput in) throws IOException;
+    }
+
+    class ImmutableBooleanTranscriber extends ImmutableTranscriber {
+        void store(Object value, FOStoreOutput out) throws IOException {
+            out.writeBoolean(((Boolean)value).booleanValue());
+        }
+
+        Object fetch(DataInput in) throws IOException {
+            return new Boolean(in.readBoolean());
+        }
+
+        void skip(DataInput in) throws IOException {
+            in.readBoolean();
+        }
+    }
+
+    class ImmutableCharacterTranscriber extends ImmutableTranscriber {
+        void store(Object value, FOStoreOutput out) throws IOException {
+            out.writeChar(((Character)value).charValue());
+        }
+
+        Object fetch(DataInput in) throws IOException {
+            return new Character(in.readChar());
+        }
+
+        void skip(DataInput in) throws IOException {
+            in.readChar();
+        }
+    }
+
+    class ImmutableByteTranscriber extends ImmutableTranscriber {
+        void store(Object value, FOStoreOutput out) throws IOException {
+            out.writeByte(((Byte)value).byteValue());
+        }
+
+        Object fetch(DataInput in) throws IOException {
+            return new Byte(in.readByte());
+        }
+
+        void skip(DataInput in) throws IOException {
+            in.readByte();
+        }
+    }
+
+    class ImmutableShortTranscriber extends ImmutableTranscriber {
+        void store(Object value, FOStoreOutput out) throws IOException {
+            out.writeShort(((Short)value).shortValue());
+        }
+
+        Object fetch(DataInput in) throws IOException {
+            return new Short(in.readShort());
+        }
+
+        void skip(DataInput in) throws IOException {
+            in.readShort();
+        }
+    }
+
+    class ImmutableIntegerTranscriber extends ImmutableTranscriber {
+        void store(Object value, FOStoreOutput out) throws IOException {
+            out.writeInt(((Integer)value).intValue());
+        }
+
+        Object fetch(DataInput in) throws IOException {
+            return new Integer(in.readInt());
+        }
+
+        void skip(DataInput in) throws IOException {
+            in.readInt();
+        }
+    }
+
+    class ImmutableLongTranscriber extends ImmutableTranscriber {
+        void store(Object value, FOStoreOutput out) throws IOException {
+            out.writeLong(((Long)value).longValue());
+        }
+
+        Object fetch(DataInput in) throws IOException {
+            return new Long(in.readLong());
+        }
+
+        void skip(DataInput in) throws IOException {
+            in.readLong();
+        }
+    }
+
+    class ImmutableFloatTranscriber extends ImmutableTranscriber {
+        void store(Object value, FOStoreOutput out) throws IOException {
+            out.writeFloat(((Float)value).floatValue());
+        }
+
+        Object fetch(DataInput in) throws IOException {
+            return new Float(in.readFloat());
+        }
+
+        void skip(DataInput in) throws IOException {
+            in.readFloat();
+        }
+    }
+
+    class ImmutableDoubleTranscriber extends ImmutableTranscriber {
+        void store(Object value, FOStoreOutput out) throws IOException {
+            out.writeDouble(((Double)value).doubleValue());
+        }
+
+        Object fetch(DataInput in) throws IOException {
+            return new Double(in.readDouble());
+        }
+
+        void skip(DataInput in) throws IOException {
+            in.readDouble();
+        }
+    }
+
+    class ImmutableStringTranscriber extends ImmutableTranscriber {
+        void store(Object value, FOStoreOutput out) throws IOException {
+            out.writeUTF((String)value);
+        }
+
+        public Object fetch(DataInput in) throws IOException {
+            return in.readUTF();
+        }
+
+        void skip(DataInput in) throws IOException {
+            in.readUTF();
+        }
+    }
+
+    //
+    // Following are Transcribers for arrays
+    //
+    // Each is similar: write/read the size of the array, followed by the
+    // elements.
+    //
+
+    /**
+     * Abstract class which provides support for transcribing arrays of any
+     * type. For each type of array, there should be a subclass.  
+     * @see ObjectTranscriber.IntArrayTranscriber
+     */
+    // Note that lack of symmetry between store/storeElement and
+    // fetch/fetchElements.  This is intentional.
+    //
+    // We can have the array indexing loop in store, and have storeElement
+    // just write out the data value immediately, whereby subclasses don't
+    // have to each implement the loop.  We cannot, however, do the same with
+    // the fetch methods, because the subclass itself has to create the array
+    // of the appropriate type, and then read the values using type-specific
+    // methods.
+    //
+    // So what you can say about the abstract methods, is that they do the
+    // type-specific things.
+    //
+    // Note too that this uses java.lang.reflect.Array.  It may be that we
+    // have a big loss of performance here, and that we'd be better off by
+    // having each array transcriber type do all the work itself, and pay the
+    // costs of code size and maintenance.
+    //
+    abstract class ArrayTranscriber extends AbstractTranscriber {
+        private Object owner;
+        private int fieldNum;
+
+        protected Object getOwner() {
+            return owner;
+        }
+
+        protected int getFieldNum() {
+            return fieldNum;
+        }
+        
+        /**
+         * Stores the entire array by delegating the storing of each element
+         * to the storeElement method, which is implemented by a subclass.
+         */
+        final void store(Object value, FOStoreOutput out) throws IOException {
+            try {
+                int length = Array.getLength(value);
+                if (logger.isDebugEnabled()) {
+                    logger.debug(this.getClass().getName()
+                                   + ".store: length=" + length // NOI18N
+                                   + " starting at=" + out.getPos()); // NOI18N
+                }
+                out.writeInt(length);
+                for (int i = 0; i < length; i++) {
+                    storeElement(value, out, i);
+                }
+            } catch (IllegalArgumentException ex) {
+                throw new FOStoreFatalInternalException(
+                    this.getClass(), "store", // NOI18N
+                    msg.msg("ERR_ShouldNotHappen", ex)); // NOI18N
+            } catch (ArrayIndexOutOfBoundsException ex) {
+                throw new FOStoreFatalInternalException(
+                    this.getClass(), "store", // NOI18N
+                    msg.msg("ERR_ShouldNotHappen", ex)); // NOI18N
+            }
+        }
+
+        /**
+         * Stores a single element of an array.
+         * @param value An array of some type.  The type of the array is
+         * conditional on the class which is implementing this method.
+         * @param out Where the value should be stored
+         * @param index Index into the value which should be stored.
+         */
+        abstract void storeElement(Object value, FOStoreOutput out, int index)
+            throws IOException, IllegalArgumentException,
+            ArrayIndexOutOfBoundsException;
+
+        /**
+         * Fetches the entire array by delegating to fetchElements.
+         */
+        final Object fetch(DataInput in, Object owner, int fieldNum)
+            throws Exception {
+
+            this.owner = owner;
+            this.fieldNum = fieldNum;
+            
+            Object rc = null;
+            try {
+                int length = in.readInt();
+                if (logger.isDebugEnabled()) {
+                    logger.debug(this.getClass().getName()
+                                   + ".fetch: length=" + length); // NOI18N
+                }
+                rc = fetchElements(in, length);
+            } catch (IllegalArgumentException ex) {
+                throw new FOStoreFatalInternalException(
+                    this.getClass(), "fetch", // NOI18N
+                    msg.msg("ERR_ShouldNotHappen", ex)); // NOI18N
+            } catch (ArrayIndexOutOfBoundsException ex) {
+                throw new FOStoreFatalInternalException(
+                    this.getClass(), "fetch", // NOI18N
+                    msg.msg("ERR_ShouldNotHappen", ex)); // NOI18N
+            }
+            return rc;
+        }
+
+        /**
+         * Skips the entire array by delegating to skipElements.
+         */
+        final void skip(DataInput in)
+            throws IOException {
+
+            try {
+                int length = in.readInt();
+                if (logger.isDebugEnabled()) {
+                    logger.debug(this.getClass().getName()
+                                   + ".skip: length=" + length); // NOI18N
+                }
+                skipElements(in, length);
+            } catch (IllegalArgumentException ex) {
+                throw new FOStoreFatalInternalException(
+                    this.getClass(), "skip", // NOI18N
+                    msg.msg("ERR_ShouldNotHappen", ex)); // NOI18N
+            } catch (ArrayIndexOutOfBoundsException ex) {
+                throw new FOStoreFatalInternalException(
+                    this.getClass(), "skip", // NOI18N
+                    msg.msg("ERR_ShouldNotHappen", ex)); // NOI18N
+            }
+        }
+
+        /**
+         * Creates an array of some type and returns it, after reading in all
+         * the array's element's values.  The type of the array that should be
+         * created is conditional on the class which is implementing this
+         * method. 
+         * @param in Place from where the array's values should be read
+         * @param length Length of the array to create.
+         */
+        abstract Object fetchElements(DataInput in, int length)
+            throws Exception, IllegalArgumentException,
+            ArrayIndexOutOfBoundsException;
+
+        /**
+         * Skips an array of some type after skipping all the array's element's values.
+         * @param in Place from where the array's values should be read
+         * @param length Length of the array.
+         */
+        abstract void skipElements(DataInput in, int length)
+            throws IOException;
+    }
+
+
+    //
+    // Following are Transcribers for arrays of individual types.
+    //
+    
+    class BooleanArrayTranscriber extends ArrayTranscriber {
+        void storeElement(Object value, FOStoreOutput out, int index)
+            throws IOException, IllegalArgumentException,
+            ArrayIndexOutOfBoundsException {
+
+            out.writeBoolean(Array.getBoolean(value, index));
+        }
+
+        Object fetchElements(DataInput in, int length)
+            throws Exception, IllegalArgumentException, 
+            ArrayIndexOutOfBoundsException {
+
+            boolean rc[] = new boolean[length];
+            for (int i = 0; i < length; i++) {
+                rc[i] = in.readBoolean();
+            }
+            return rc;
+        }
+
+        void skipElements(DataInput in, int length) throws IOException {
+
+            for (int i = 0; i < length; i++) {
+                in.readBoolean();
+            }
+        }
+    }
+
+    class CharArrayTranscriber extends ArrayTranscriber {
+        void storeElement(Object value, FOStoreOutput out, int index)
+            throws IOException, IllegalArgumentException,
+            ArrayIndexOutOfBoundsException {
+
+            out.writeChar(Array.getChar(value, index));
+        }
+
+        Object fetchElements(DataInput in, int length)
+            throws IOException {
+
+            char rc[] = new char[length];
+            for (int i = 0; i < length; i++) {
+                rc[i] = in.readChar();
+            }
+            return rc;
+        }
+
+        void skipElements(DataInput in, int length) throws IOException {
+
+            for (int i = 0; i < length; i++) {
+                in.readChar();
+            }
+        }
+    }
+
+    class ByteArrayTranscriber extends ArrayTranscriber {
+        void storeElement(Object value, FOStoreOutput out, int index)
+            throws IOException, IllegalArgumentException,
+            ArrayIndexOutOfBoundsException {
+
+            out.writeByte(Array.getByte(value, index));
+        }
+
+        Object fetchElements(DataInput in, int length)
+            throws IOException {
+
+            byte rc[] = new byte[length];
+            for (int i = 0; i < length; i++) {
+                rc[i] = in.readByte();
+            }
+            return rc;
+        }
+
+        void skipElements(DataInput in, int length) throws IOException {
+
+            for (int i = 0; i < length; i++) {
+                in.readByte();
+            }
+        }
+    }
+
+    class ShortArrayTranscriber extends ArrayTranscriber {
+        void storeElement(Object value, FOStoreOutput out, int index)
+            throws IOException, IllegalArgumentException,
+            ArrayIndexOutOfBoundsException {
+
+            out.writeShort(Array.getShort(value, index));
+        }
+
+        Object fetchElements(DataInput in, int length)
+            throws IOException {
+
+            short rc[] = new short[length];
+            for (int i = 0; i < length; i++) {
+                rc[i] = in.readShort();
+            }
+            return rc;
+        }
+
+        void skipElements(DataInput in, int length) throws IOException {
+
+            for (int i = 0; i < length; i++) {
+                in.readShort();
+            }
+        }
+    }
+
+    class IntArrayTranscriber extends ArrayTranscriber {
+        void storeElement(Object value, FOStoreOutput out, int index)
+            throws IOException, IllegalArgumentException,
+            ArrayIndexOutOfBoundsException {
+
+            out.writeInt(Array.getInt(value, index));
+        }
+
+        Object fetchElements(DataInput in, int length)
+            throws IOException {
+
+            int rc[] = new int[length];
+            for (int i = 0; i < length; i++) {
+                rc[i] = in.readInt();
+            }
+            return rc;
+        }
+
+        void skipElements(DataInput in, int length) throws IOException {
+
+            for (int i = 0; i < length; i++) {
+                in.readInt();
+            }
+        }
+    }
+
+    class LongArrayTranscriber extends ArrayTranscriber {
+        void storeElement(Object value, FOStoreOutput out, int index)
+            throws IOException, IllegalArgumentException,
+            ArrayIndexOutOfBoundsException {
+
+            out.writeLong(Array.getLong(value, index));
+        }
+
+        Object fetchElements(DataInput in, int length)
+            throws IOException {
+
+            long rc[] = new long[length];
+            for (int i = 0; i < length; i++) {
+                rc[i] = in.readLong();
+            }
+            return rc;
+        }
+
+        void skipElements(DataInput in, int length) throws IOException {
+
+            for (int i = 0; i < length; i++) {
+                in.readLong();
+            }
+        }
+    }
+
+    class FloatArrayTranscriber extends ArrayTranscriber {
+        void storeElement(Object value, FOStoreOutput out, int index)
+            throws IOException, IllegalArgumentException,
+            ArrayIndexOutOfBoundsException {
+
+            out.writeFloat(Array.getFloat(value, index));
+        }
+
+        Object fetchElements(DataInput in, int length)
+            throws IOException {
+
+            float rc[] = new float[length];
+            for (int i = 0; i < length; i++) {
+                rc[i] = in.readFloat();
+            }
+            return rc;
+        }
+
+        void skipElements(DataInput in, int length) throws IOException {
+
+            for (int i = 0; i < length; i++) {
+                in.readFloat();
+            }
+        }
+    }
+
+    class DoubleArrayTranscriber extends ArrayTranscriber {
+        void storeElement(Object value, FOStoreOutput out, int index)
+            throws IOException, IllegalArgumentException,
+            ArrayIndexOutOfBoundsException {
+
+            out.writeDouble(Array.getDouble(value, index));
+        }
+
+        Object fetchElements(DataInput in, int length)
+            throws IOException {
+
+            double rc[] = new double[length];
+            for (int i = 0; i < length; i++) {
+                rc[i] = in.readDouble();
+            }
+            return rc;
+        }
+
+        void skipElements(DataInput in, int length) throws IOException {
+
+            for (int i = 0; i < length; i++) {
+                in.readDouble();
+            }
+        }
+    }
+
+    class StringArrayTranscriber extends ArrayTranscriber {
+        void storeElement(Object value, FOStoreOutput out, int index)
+            throws IOException, IllegalArgumentException,
+            ArrayIndexOutOfBoundsException {
+
+            out.writeUTF((String)Array.get(value, index));
+        }
+
+        Object fetchElements(DataInput in, int length)
+            throws IOException {
+
+            String rc[] = new String[length];
+            for (int i = 0; i < length; i++) {
+                rc[i] = in.readUTF();
+            }
+            return rc;
+        }
+
+        void skipElements(DataInput in, int length) throws IOException {
+
+            for (int i = 0; i < length; i++) {
+                in.readUTF();
+            }
+        }
+    }
+
+    class ObjArrayTranscriber extends ArrayTranscriber {
+        private Class componentType;
+
+        void setComponentType(Class componentType) {
+            this.componentType = componentType;
+        }
+
+        void storeElement(Object value, FOStoreOutput out, int index)
+            throws IOException, IllegalArgumentException,
+            ArrayIndexOutOfBoundsException {
+
+            Object o = Array.get(value, index);
+            storeObject(o, out);
+        }
+
+        Object fetchElements(DataInput in, int length)
+            throws Exception {
+
+            if (null == componentType) {
+                throw new FOStoreFatalInternalException(
+                    this.getClass(), "fetchElements", // NOI18N
+                    msg.msg("ERR_NullComponentType"));  // NOI18N
+            }
+            if (logger.isDebugEnabled()) {
+                logger.debug("PCAT.fetchElements: componentType=" // NOI18N
+                               + componentType.getName());
+            }
+            
+            Object rc = Array.newInstance(componentType, length);
+            for (int i = 0; i < length; i++) {
+                Array.set(rc, i, fetchObject(in, getOwner(), getFieldNum()));
+            }
+            return rc;
+        }
+
+        void skipElements(DataInput in, int length)
+            throws IOException {
+
+            if (null == componentType) {
+                throw new FOStoreFatalInternalException(
+                    this.getClass(), "skipElements", // NOI18N
+                    msg.msg("ERR_NullComponentType"));  // NOI18N
+            }
+            if (logger.isDebugEnabled()) {
+                logger.debug("PCAT.skipElements: componentType=" // NOI18N
+                               + componentType.getName());
+            }
+            
+            for (int i = 0; i < length; i++) {
+                skipObject(in);
+            }
+        }
+    }
+
+    //
+    // Following are Transcribers for Collections.
+    //
+    // Each is similar: write/read out the size of the collection, then its
+    // elements.
+    //
+
+
+    /**
+    * Transcribe Collections.
+    */
+    abstract class CollectionTranscriber extends AbstractTranscriber {
+        /**
+        * Writes information for Collections, particularly for SCO
+        * Collections.
+        * @param obj Collection (possibly SCO) for which information in
+        * written. 
+        * @param out Output to which information is written.
+        * @throws IOException if there are problems writing information.
+        */
+        protected void writeInfo(Collection obj, FOStoreOutput out)
+            throws IOException {
+            
+            if ((obj instanceof SCOCollection)) {
+                SCOCollection sco = (SCOCollection)obj;
+                out.writeUTF(sco.getElementType().getName());
+                out.writeBoolean(sco.allowNulls());
+            } else {
+                out.writeUTF(DEFAULT_TYPE);
+                out.writeBoolean(DEFAULT_ALLOW_NULLS);
+            }
+        }
+        
+        /** Store the elements of the collection. Freeze the elements,
+         * then iterate over them.
+         */
+        protected void storeCollection(Collection obj, FOStoreOutput out)
+                throws IOException {
+            FOStoreTranscriberFactory factory =
+                FOStoreTranscriberFactory.getInstance();
+            FOStoreTranscriber t;
+            Iterator iterator = null;
+            if (obj instanceof SCOCollection) {
+                iterator = ((SCOCollection)obj).frozenIterator();
+            } else {
+                iterator = obj.iterator();
+            }
+            while (iterator.hasNext()) {
+                Object elem = iterator.next();
+                t = (FOStoreTranscriber)factory.getTranscriber(elem.getClass())[0];
+                t.storeObject(elem, out);
+            }
+        }
+
+       /**
+        * Skips elements of a Collection.
+        * @param in Place from where the array's values should be read
+        * @throws IOException if there are problems writing information.
+        */
+        void skip(DataInput in)
+            throws IOException {
+
+            int size = in.readInt();
+            in.readUTF(); // elementType
+            in.readBoolean(); // allowNulls
+
+            for (int i = 0; i < size; i++) {
+                skip(in);
+            }
+        }
+    }
+    
+    /**
+    * Transcribe ArrayLists.
+    */
+    class ArrayListTranscriber extends CollectionTranscriber {
+        void store(Object value, FOStoreOutput out) throws IOException {
+            ArrayList obj = (ArrayList)value;
+            int size = obj.size();
+            out.writeInt(size);
+            writeInfo(obj, out);
+
+            storeCollection(obj, out);
+        }
+        
+        Object fetch(DataInput in, Object owner, int fieldNum)
+            throws Exception {
+
+            Object obj = ((StateManagerInternal)owner).getObject();
+
+            int size = in.readInt();
+            Class elementType = loadClass(in.readUTF(), obj);
+            boolean allowNulls = in.readBoolean();
+
+            org.apache.jdo.impl.sco.ArrayList rc = 
+                new org.apache.jdo.impl.sco.ArrayList(
+                    elementType, allowNulls, size);
+            for (int i = 0; i < size; i++) {
+                rc.addInternal(fetchObject(in, owner, fieldNum));
+            }
+            rc.setOwner(owner, fieldNum);
+            return rc;
+        }
+    }
+
+    // Sigh: ArrayList and Vector are sooooo close, yet different, and these
+    // methods are small, so that it's hardly worth it to abstract out the
+    // differences.  You wind up with more lines of code than by keeping them
+    // completely separate!
+
+    /**
+    * Transcribe Vectors
+    */
+    class VectorTranscriber extends CollectionTranscriber {
+        void store(Object value, FOStoreOutput out) throws IOException {
+            Vector obj = (Vector)value;
+            int size = obj.size();
+            out.writeInt(size);
+            writeInfo(obj, out);
+
+            FOStoreTranscriberFactory factory =
+                FOStoreTranscriberFactory.getInstance();
+            for (int i = 0; i < size; i++) {
+                Object o = obj.elementAt(i);
+                FOStoreTranscriber t =
+                    (FOStoreTranscriber)factory.getTranscriber(o.getClass())[0];
+                t.storeObject(o, out);
+            }
+        }
+
+        Object fetch(DataInput in, Object owner, int fieldNum)
+            throws Exception {
+
+            Object obj = ((StateManagerInternal)owner).getObject();
+
+            int size = in.readInt();
+            Class elementType = loadClass(in.readUTF(), obj);
+            boolean allowNulls = in.readBoolean();
+
+            org.apache.jdo.impl.sco.Vector rc = 
+                new org.apache.jdo.impl.sco.Vector(
+                    elementType, allowNulls);
+            for (int i = 0; i < size; i++) {
+                rc.addInternal(fetchObject(in, owner, fieldNum));
+            }
+            rc.setOwner(owner, fieldNum);
+            return rc;
+        }
+    }
+
+    /**
+    * Transcribe LinkedList.
+    */
+    class LinkedListTranscriber extends CollectionTranscriber {
+        void store(Object value, FOStoreOutput out) throws IOException {
+            LinkedList obj = (LinkedList)value;
+            int size = obj.size();
+            out.writeInt(size);
+            writeInfo(obj, out);
+
+            storeCollection(obj, out);
+        }
+
+        Object fetch(DataInput in, Object owner, int fieldNum)
+            throws Exception {
+
+            Object obj = ((StateManagerInternal)owner).getObject();
+
+            int size = in.readInt();
+            Class elementType = loadClass(in.readUTF(), obj);
+            boolean allowNulls = in.readBoolean();
+
+            org.apache.jdo.impl.sco.LinkedList rc =
+                new org.apache.jdo.impl.sco.LinkedList(
+                    elementType, allowNulls);
+
+            for (int i = 0; i < size; i++) {
+                rc.addInternal(fetchObject(in, owner, fieldNum));
+            }
+            rc.setOwner(owner, fieldNum);
+            return rc;
+        }
+    }
+
+    /**
+    * Transcribe TreeSets.
+    */
+    class TreeSetTranscriber extends CollectionTranscriber {
+       void store(Object value, FOStoreOutput out) throws IOException {
+
+            TreeSet obj = (TreeSet)value;
+            int size = obj.size();
+            out.writeInt(size);
+            writeInfo(obj, out);
+
+            Comparator c = obj.comparator();
+            if (c != null) {
+                out.writeBoolean(true);
+                out.writeUTF(c.getClass().getName());
+            } else {
+                out.writeBoolean(false);
+            }
+
+            storeCollection(obj, out);
+        }
+ 
+        Object fetch(DataInput in, Object owner, int fieldNum)
+            throws Exception {
+
+            Object obj = ((StateManagerInternal)owner).getObject();
+
+            int size = in.readInt();
+            Class elementType = loadClass(in.readUTF(), obj);
+            boolean allowNulls = in.readBoolean();
+
+            boolean nonNullComparator = in.readBoolean();
+            Comparator c = null;
+
+            if (nonNullComparator) {
+                String clsName = in.readUTF();
+                Class cls = loadClass(clsName, obj);
+                c = (Comparator) cls.newInstance();
+            }
+
+            org.apache.jdo.impl.sco.TreeSet rc = new 
+                org.apache.jdo.impl.sco.TreeSet(
+                    elementType, allowNulls, c);
+
+            Object[] frozen = new Object[size];
+            for (int i = 0; i < size; i++) {
+                Object elem = fetchObject(in, owner, fieldNum);
+                frozen[i] = elem;
+            }
+            rc.setFrozen(frozen);
+            rc.setOwner(owner, fieldNum);
+            return rc;
+        }
+
+        void skip(DataInput in)
+            throws IOException {
+
+            int size = in.readInt();
+            in.readUTF(); // elementType
+            in.readBoolean(); // allowNulls
+
+            boolean nonNullComparator = in.readBoolean();
+            if (nonNullComparator) {
+                in.readUTF(); // clsName
+            }
+
+            for (int i = 0; i < size; i++) {
+                skipObject(in);
+            }
+        }
+    }
+
+
+    /**
+    * Transcribe HashSets.
+    */
+    // XXX TBD Model: Use elementType, allowNulls when available.
+    class HashSetTranscriber extends CollectionTranscriber {
+        void store(Object value, FOStoreOutput out) throws IOException {
+            HashSet obj = (HashSet)value;
+            int size = obj.size();
+            out.writeInt(size);
+            writeInfo(obj, out);
+
+            storeCollection(obj, out);
+        }
+
+        Object fetch(DataInput in, Object owner, int fieldNum)
+            throws Exception {
+
+            Object obj = ((StateManagerInternal)owner).getObject();
+
+            int size = in.readInt();
+            Class elementType = loadClass(in.readUTF(), obj);
+            boolean allowNulls = in.readBoolean();
+
+            org.apache.jdo.impl.sco.HashSet rc = 
+                new org.apache.jdo.impl.sco.HashSet(
+                    elementType, allowNulls);
+            Object[] frozen = new Object[size];
+            for (int i = 0; i < size; i++) {
+                Object elem = fetchObject(in, owner, fieldNum);
+                frozen[i] = elem;
+            }
+            rc.setFrozen(frozen);
+            rc.setOwner(owner, fieldNum);
+            return rc;
+        }
+    }
+
+    /**
+    * Transcribe Maps.
+    */
+    abstract class MapTranscriber extends AbstractTranscriber {
+        void storeMap(Map obj, FOStoreOutput out) throws IOException {
+            int size = obj.size();
+            out.writeInt(size);
+            writeInfo(obj, out);
+
+            writeExtras(obj, out);
+            
+            FOStoreTranscriberFactory factory =
+                FOStoreTranscriberFactory.getInstance();
+            FOStoreTranscriber tk, tv;
+            Iterator iterator;
+            if (obj instanceof SCOMap) {
+                iterator = ((SCOMap)obj).frozenIterator();
+            } else {
+                iterator = Freezer.frozenIterator(obj, obj.size());
+            }
+            while (iterator.hasNext()) {
+                Map.Entry mapEntry = (Map.Entry)iterator.next();
+                Object key = mapEntry.getKey();
+                Object value = mapEntry.getValue();
+                tk = (FOStoreTranscriber)factory.getTranscriber(key.getClass())[0];
+                tv = (FOStoreTranscriber)factory.getTranscriber(value.getClass())[0];
+                tk.storeObject(key, out);
+                tv.storeObject(value, out);
+            }                
+        }
+
+        void writeExtras(Map obj, FOStoreOutput out) 
+            throws IOException {
+                // the basic Map doesn't have any extras; see TreeMap
+        }
+        
+        Object fetchMap(SCOMap rc, int size, DataInput in, Object owner,
+                        int fieldNum) throws Exception { 
+
+            Map.Entry[] frozen = new Map.Entry[size];
+            Map absoluteMap = Freezer.createAbsoluteOrderMap();
+            for (int i = 0; i < size; i++) {
+                Object key = fetchObject(in, owner, fieldNum);
+                Object val = fetchObject(in, owner, fieldNum);
+                absoluteMap.put(key, val);
+            }
+            rc.setFrozen((Map.Entry[])absoluteMap.entrySet().toArray(frozen));
+            rc.setOwner(owner, fieldNum);
+            return rc;
+        }
+
+        protected void writeInfo(Map obj, FOStoreOutput out)
+            throws IOException {
+
+            if (obj instanceof SCOMap) {
+                SCOMap map = (SCOMap) obj;
+                out.writeUTF(map.getKeyType().getName());
+                out.writeUTF(map.getValueType().getName());
+                out.writeBoolean(map.allowNulls());
+            } else {
+                out.writeUTF(DEFAULT_TYPE);
+                out.writeUTF(DEFAULT_TYPE);
+                out.writeBoolean(DEFAULT_ALLOW_NULLS);
+            }
+        }
+
+        void skip(DataInput in)
+            throws IOException {
+
+            int size = in.readInt();
+            in.readUTF(); // keyType
+            in.readUTF(); // valueType
+            in.readBoolean(); // allowNulls
+
+            for (int i = 0; i < size; i++) {
+                skipObject(in); // key
+                skipObject(in); // value
+            }
+        }
+    }
+
+    /**
+    * Transcribe HashMaps.
+    */
+    class HashMapTranscriber extends MapTranscriber {
+        void store(Object value, FOStoreOutput out) throws IOException {
+
+            storeMap((Map)value, out);
+        }
+
+        Object fetch(DataInput in, Object owner, int fieldNum)
+            throws Exception {
+
+            Object obj = ((StateManagerInternal)owner).getObject();
+
+            int size = in.readInt();
+            Class keyType = loadClass(in.readUTF(), obj);
+            Class valueType = loadClass(in.readUTF(), obj);
+            boolean allowNulls = in.readBoolean();
+
+            org.apache.jdo.impl.sco.HashMap rc = new 
+                org.apache.jdo.impl.sco.HashMap(
+                    keyType, valueType, allowNulls, size);
+            return fetchMap(rc, size, in, owner, fieldNum);
+        }
+    }
+
+
+    /**
+    * Transcribe Hashtable, including sco.Hashtable
+    */
+    class HashtableTranscriber extends MapTranscriber {
+        void store(Object value, FOStoreOutput out) throws IOException {
+            storeMap((Map)value, out);
+        }                                                 
+ 
+        Object fetch(DataInput in, Object owner, int fieldNum)
+            throws Exception {
+ 
+            Object obj = ((StateManagerInternal)owner).getObject();
+
+            int size = in.readInt();
+            Class keyType = loadClass(in.readUTF(), obj);
+            Class valueType = loadClass(in.readUTF(), obj);
+            boolean allowNulls = in.readBoolean();
+            org.apache.jdo.impl.sco.Hashtable rc = new
+                org.apache.jdo.impl.sco.Hashtable(
+                    keyType, valueType, allowNulls);
+            return fetchMap(rc, size, in, owner, fieldNum);
+        }
+    }   
+
+    /**
+    * Transcribe TreeMap, including sco.TreeMap.
+    */
+    class TreeMapTranscriber extends MapTranscriber {
+       void store(Object value, FOStoreOutput out) throws IOException {
+            storeMap((Map)value, out);
+        }
+ 
+       void writeExtras(Map obj, FOStoreOutput out) 
+            throws IOException {
+            Comparator c = ((SortedMap)obj).comparator();
+            if (c != null) {
+                out.writeBoolean(true);
+                out.writeUTF(c.getClass().getName());
+            } else {
+                out.writeBoolean(false);
+            }
+       }
+
+        Object fetch(DataInput in, Object owner, int fieldNum)
+            throws Exception {
+
+            Object obj = ((StateManagerInternal)owner).getObject();
+
+            int size = in.readInt();
+            Class keyType = loadClass(in.readUTF(), obj);
+            Class valueType = loadClass(in.readUTF(), obj);
+            boolean allowNulls = in.readBoolean();
+
+            boolean nonNullComparator = in.readBoolean();
+            Comparator c = null;
+
+            if (nonNullComparator) {
+                String clsName = in.readUTF();
+                Class cls = loadClass(clsName, obj);
+                c = (Comparator) cls.newInstance();
+            }
+
+            org.apache.jdo.impl.sco.TreeMap rc = new 
+                org.apache.jdo.impl.sco.TreeMap(
+                    keyType, valueType, allowNulls, c);
+
+            return fetchMap (rc, size, in, owner, fieldNum);
+        }
+
+        void skip(DataInput in)
+            throws IOException {
+
+            int size = in.readInt();
+            in.readUTF(); // keyType
+            in.readUTF(); // valueType
+            in.readBoolean(); // allowNulls
+
+            boolean nonNullComparator = in.readBoolean();
+            if (nonNullComparator) {
+                in.readUTF(); // clsName
+            }
+
+            for (int i = 0; i < size; i++) {
+                skipObject(in); // key
+                skipObject(in); // value
+            }
+        }
+    }
+
+    /**
+    * Transcribe Date.
+    */
+    class DateTranscriber extends AbstractTranscriber {
+        void store(Object value, FOStoreOutput out) throws IOException {
+            boolean sqlDate = false;
+            if (value instanceof java.sql.Date ||
+                value instanceof org.apache.jdo.impl.sco.SqlDate) {
+                sqlDate = true;
+            }
+            out.writeBoolean(sqlDate);
+                
+            Date date = (Date)value;
+            out.writeLong(date.getTime());
+        }
+
+        Object fetch(DataInput in, Object owner, int fieldNum)
+            throws Exception {
+
+            org.apache.jdo.sco.SCO rc = null;
+
+            boolean sqlDate = in.readBoolean();
+
+            if (sqlDate) {
+                rc = new org.apache.jdo.impl.sco.SqlDate(in.readLong());
+            } else {
+                rc = new org.apache.jdo.impl.sco.Date(in.readLong());
+            }
+            rc.setOwner(owner, fieldNum);
+            return rc;
+        }
+
+        void skip(DataInput in)
+            throws IOException {
+
+            in.readBoolean(); // sqlDate
+            in.readLong(); // time
+        }
+    }
+    /**
+    * Transcribe Calendar.
+    */
+    class CalendarTranscriber extends AbstractTranscriber {
+
+        void store(Object value, FOStoreOutput out) throws IOException {
+            Calendar calendar = (Calendar)value;
+            TimeZone tz = calendar.getTimeZone();
+            String tzid = tz.getID();
+            Date date = ((Calendar)value).getTime();
+
+            out.writeUTF(calendar.getClass().getName());
+            out.writeUTF(tzid);
+            out.writeLong(date.getTime());
+        }
+
+        Object fetch(DataInput in, Object owner, int fieldNum)
+            throws Exception {
+
+            Calendar rc = null;
+
+            String className = in.readUTF();
+            Object obj = ((StateManagerInternal)owner).getObject();
+            Class c = loadClass(className, obj);
+            rc = (Calendar)c.newInstance();
+
+            String tzid = in.readUTF();
+            rc.setTimeZone(TimeZone.getTimeZone(tzid));
+
+            org.apache.jdo.impl.sco.Date date =
+                new org.apache.jdo.impl.sco.Date(in.readLong());
+            date.setOwner(owner, fieldNum);
+            rc.setTime(date);
+
+            return rc;
+        }
+
+        void skip(DataInput in)
+            throws IOException {
+
+            in.readInt(); // type
+            in.readLong(); // time
+        }
+    }
+    
+    /**
+    * Transcribe BigDecimal.
+    */
+    // We use the string representation instead of some other alternatives
+    // (e.g. serialization) because BigDecimal's javadoc says toString is
+    // compatible with the String constructor, which I take to mean that no
+    // information is lost.
+    class BigDecimalTranscriber extends AbstractTranscriber {
+        void store(Object value, FOStoreOutput out) throws IOException {
+            BigDecimal val = (BigDecimal)value;
+            out.writeUTF(val.toString());
+        }
+
+        Object fetch(DataInput in, Object owner, int fieldNum)
+            throws Exception {
+
+            return new BigDecimal(in.readUTF());
+        }
+
+        void skip(DataInput in)
+            throws IOException {
+
+            in.readUTF(); 
+        }
+    }
+    
+    /**
+    * Transcribe BigInteger.
+    */
+    // Ditto the comments above for BigDecimal.
+    class BigIntegerTranscriber extends AbstractTranscriber {
+        void store(Object value, FOStoreOutput out) throws IOException {
+            BigInteger val = (BigInteger)value;
+            out.writeUTF(val.toString());
+        }
+
+        Object fetch(DataInput in, Object owner, int fieldNum)
+            throws Exception {
+
+            return new BigInteger(in.readUTF());
+        }
+
+        void skip(DataInput in)
+            throws IOException {
+
+            in.readUTF(); 
+        }
+    }
+
+    /**
+     * Transcribe BitSet.
+     */
+    class BitSetTranscriber extends AbstractTranscriber {
+        final static int BYTE = 8;
+        final static byte LEAST_SIGNIFICANT = 1;
+
+        void store(Object value, FOStoreOutput out) throws IOException {
+            BitSet bitSet = (BitSet)value;
+            int length = bitSet.length() / BYTE;
+
+            // if necessary, enlarge buffer
+            if (bitSet.length() % BYTE  > 0) {
+                length++;
+            }
+            byte[] buffer = new byte[length];
+
+            // set bits in byte array according to BitSet object
+            for (int i = 0; i < length; i++) {
+                byte b = 0;
+
+                for (int j = 0; j < BYTE; j++) {
+                    int index = i * BYTE + j;
+                    if (index < bitSet.length() && bitSet.get(index)) {
+                        b |= LEAST_SIGNIFICANT << j;
+                    }
+                }
+                buffer[i] = b;
+
+            }
+
+            out.writeInt(length);
+            out.write(buffer);
+        }
+
+        Object fetch(DataInput in, Object owner, int fieldNum)
+            throws Exception {
+
+            int length = in.readInt();
+            byte[] buffer = new byte[length];
+            BitSet rc = new BitSet(length * BYTE);
+            
+            in.readFully(buffer);
+            for (int i = 0; i < length; i++) {
+                byte b = buffer[i];
+
+                // set bits in BitSet according to byte array values
+                for (int j = 0; j < BYTE; j++) {
+                    int index = i * BYTE + j;
+                    byte pos = (byte)(LEAST_SIGNIFICANT << j);
+
+                    if ((b & pos) != 0) {
+                        rc.set(index);
+                    }
+                }
+            }
+
+            return rc;
+        }
+
+        void skip(DataInput in)
+            throws IOException {
+
+            int length = in.readInt();
+            in.skipBytes(length);
+        }
+    }
+
+    /**
+    * Transcribe Locale.
+    */
+    class LocaleTranscriber extends AbstractTranscriber {
+        void store(Object value, FOStoreOutput out) throws IOException {
+            Locale val = (Locale)value;
+            out.writeUTF(val.getLanguage());
+            out.writeUTF(val.getCountry());
+            out.writeUTF(val.getVariant());
+        }
+
+        Object fetch(DataInput in, Object owner, int fieldNum)
+            throws Exception {
+
+            String language = in.readUTF();
+            String country = in.readUTF();
+            String variant = in.readUTF();
+            return new Locale(language, country, variant);
+        }
+
+        void skip(DataInput in)
+            throws IOException {
+
+            in.readUTF(); // language
+            in.readUTF(); // country
+            in.readUTF(); // variant
+        }
+    }
+
+    /**
+    * Returns a class for the given name.
+    * @param name Name of the Class to return.
+    * @throws JDOFatalUserException if the named Class cannot be loaded.
+    */
+    private Class loadClass(String name, Object obj) {
+        Class rc = null;
+        try {
+            rc = pm.loadClass(name, obj.getClass().getClassLoader());
+        } catch (ClassNotFoundException ex) {
+            throw new JDOUserException(
+                msg.msg("EXC_CannotLoadClass", name)); // NOI18N
+        }
+        return rc;
+    }
+}

Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/Reply.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/Reply.java?view=auto&rev=158176
==============================================================================
--- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/Reply.java (added)
+++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/Reply.java Fri Mar 18 17:02:29 2005
@@ -0,0 +1,388 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+ */
+
+package org.apache.jdo.impl.fostore;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.HashMap;
+
+import javax.jdo.JDOFatalUserException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.apache.jdo.util.I18NHelper;
+
+/**
+* Represents the result of processing a request.
+*
+* @author Dave Bristor
+*/
+class Reply implements DataOutput {
+    // Id of the request to which this Reply corresponds.
+    private final RequestId requestId;
+
+    // Output to which reply data is written.
+    private final FOStoreOutput out;
+
+    // Status value of this Reply
+    private Status status;
+    
+    // Position in Reply's buffer at which Status is written.
+    private final int statusPosition;
+
+    // Position in Reply's buffer after at which the Reply's actual data
+    // starts.
+    private final int replyDataPosition;
+
+    // Once closed, disallow further writes.  A Reply closes once status is
+    // set on it.
+    private boolean closed = false;
+
+    /**  The version number of the current protocol.  In future, this version
+     * number can be used to identify mismatches in protocol.  The format is
+     * (short)major; (byte)minor; (byte)patch Only use major for compatibility
+     * checks; always bump major when incompatibly changing protocol.
+     * <p>
+     * Note that this version number corresponds to that used in the entire
+     * stream of reply data, not for an individual reply.
+     */
+    private static final int VERSION_NUMBER = 0x00010000; // version 1.0.0
+
+    /** I18N support. */
+    private static final I18NHelper msg = I18NHelper.getInstance(I18N.NAME);
+
+    /** Logger */
+    static final Log logger = LogFactory.getFactory().getInstance(
+        "org.apache.jdo.impl.fostore"); // NOI18N
+
+    // If the setStatus(Status, Throwable) is invoked and verbose is false,
+    // include the Throwable's toString(); if true include it's
+    // printStackTrace().
+    private static boolean verbose = false;
+
+    static {
+        try {
+            String property = (String)AccessController.doPrivileged(
+                new PrivilegedAction () {
+                    public Object run () {
+                        return System.getProperty("status.verbose"); // NOI18N
+                    }
+                }
+                );
+            verbose = Boolean.valueOf(property).booleanValue();
+        } catch (SecurityException ex) {
+            // cannot read verbose flag => log warning
+            if (logger.isWarnEnabled())
+                logger.warn(msg.msg("MSG_CannotGetSystemProperty", //NOI18N
+                    "status.verbose", ex.toString())); //NOI18N
+        }
+    }
+
+    Reply(RequestId requestId, FOStoreOutput out) throws IOException {
+        this.requestId = requestId;
+        this.out = out;
+        
+        requestId.write(out);
+
+        // Save position in stream where we will write status, length.  We
+        // will replace these with the real values in setStatus().
+        this.statusPosition = out.getPos();
+
+        Status.initialize(this);
+        
+        // Will write position of Reply's error message here.  If 0, then
+        // there is no message.
+        out.writeInt(0x10badbad);
+        
+        // will write Reply's length here.  This is of the reply-specific
+        // data, and does not include the length of the message.
+        out.writeInt(0x10badbad);
+
+        this.replyDataPosition = out.getPos();
+    }
+
+    /**
+     * Indicate whether status reported to client is to be verbose or not.
+     */
+    static String getExceptionMessage(Throwable t) {
+        String rc = ""; // NOI18N
+        if (null != t) {
+            if (true) {
+                StringWriter sw = new StringWriter();
+                PrintWriter pw = new PrintWriter(sw);
+                t.printStackTrace(pw);
+                rc = sw.toString();
+            } else {
+                rc = t.toString();
+            }
+        }
+        return rc;
+    }
+
+    /**
+    * Sets the status of this reply.  Status can be set only one time.
+    * Once it has been set, further write methods will throw a 
+    * FOStoreFatalInternalException.
+    * @param status Indication of result of processing a request.
+    */
+    void setStatus(Status status) throws IOException {
+        setStatus(status, (String)null);
+    }
+
+    /**
+    * Sets the status of this reply.  Status can be set only one time.
+    * Once it has been set, further write methods will throw a
+    * FOStoreFatalInternalException.
+    * @param status Indication of result of processing a request.
+    * @param t Detail on cause of errors.
+    */
+    void setStatus(Status status, Throwable t) throws IOException {
+        String message = getExceptionMessage(t);
+        setStatus(status, message);
+    }
+
+    /**
+    * Sets the status of this reply.  Status can be set only one time.
+    * Once it has been set, further write methods will throw a
+    * FOStoreFatalInternalException.
+    * @param status Indication of result of processing a request.
+    * @param message detailed message.
+    * @param t Detail on cause of errors.
+    */
+    void setStatus(Status status, String message, Throwable t)
+        throws IOException {
+        String throwableMessage = getExceptionMessage(t);
+        setStatus(status, message+throwableMessage);
+    }
+
+    /**
+    * Sets the status of this reply.  Status can be set only one time.
+    * Once it has been set, further write methods will throw a
+    * FOStoreFatalInternalException.
+    * @param status Indication of result of processing a request.
+    * @param message Detail on cause of errors.
+    */
+    void setStatus(Status status, String message) throws IOException {
+
+        assertNotClosed();
+        closed = true;
+
+        this.status = status;
+
+        // Save end-of-stream position
+        int savedPos = out.getPos();
+
+        // Write status, message position, and reply data length, as was
+        // provided for in constructor.
+        out.setPos(statusPosition);
+
+        // Status
+        status.write(out);
+
+        // Message length
+        if (null == message) {
+            out.writeInt(0);
+        } else {
+            out.writeInt(message.length());
+        }
+
+        // Reply data length
+        int dataLength = savedPos - replyDataPosition;
+        out.writeInt(dataLength);
+
+        // Seek back to the end of the reply data, and write message
+        out.setPos(savedPos);
+        if (null != message) {
+            out.writeUTF(message);
+        }
+        
+        if (logger.isDebugEnabled()) {
+            logger.debug("Reply: Created for " + requestId + // NOI18N
+                           ", length=" + dataLength + // NOI18N
+                           ", status=" + status + // NOI18N
+                           ", message=" + message); // NOI18N
+        }
+    }
+
+    /**
+    * @return The Status value of the reply.  May return null.
+    */
+    Status getStatus() {
+        return status;
+    }
+
+    /**
+     * Write the version number at the current position.
+     */
+    static void writeVersionNumber(DataOutput out) throws IOException {
+        out.writeInt(VERSION_NUMBER);
+    }
+
+    /**
+     * Verify the Reply version number.
+     * @throws JDOFatalUserException if the version number does not match
+     * that in the caller's JVM.
+     */
+    static void verifyVersionNumber(DataInput in) throws IOException {
+        int verNum = in.readInt();
+        if (VERSION_NUMBER != verNum) {
+            throw new JDOFatalUserException(
+                msg.msg("EXC_ReplyVersionMismatch", // NOI18N
+                        new Integer(verNum), new Integer(VERSION_NUMBER)));
+        }
+    }
+
+    /**
+    * Writes an OID in this reply at the current position.
+    * @param oid The OID which is written.
+    */
+    void writeOID(OID oid) throws IOException {
+        assertNotClosed();
+        oid.write(out);
+    }
+
+    /**
+    * Writes a CLID in this reply at the current position.
+    * @param clid The CLID which is written.
+    */
+    void writeCLID(CLID clid) throws IOException {
+        assertNotClosed();
+        clid.write(out);
+    }
+
+    /**
+    * @see FOStoreOutput#beginStash
+    */
+    int beginStash() throws IOException {
+        return out.beginStash();
+    }
+
+    /**
+    * @see FOStoreOutput#endStash
+    */
+    void endStash(int length, int pos) throws IOException {
+        out.endStash(length, pos);
+    }
+    
+    //
+    // Allow seeking in output
+    //
+
+    /** @return Current position in Reply's output stream.
+     */
+    int getPos() {
+        return out.getPos();
+    }
+
+    /** @param pos New postion in Reply's output stream.
+     */
+    void setPos(int pos) throws IOException {
+        out.setPos(pos);
+    }
+
+    //
+    // Implement DataOutput
+    //
+
+    public void write(byte[] b) throws IOException {
+        assertNotClosed();
+        out.write(b);
+    }
+
+    public void write(int b) throws IOException {
+        assertNotClosed();
+        out.write(b);
+    }
+
+    public void write(byte[] b, int off, int len) throws IOException {
+        assertNotClosed();
+        out.write(b, off, len);
+    }
+
+    public void writeBoolean(boolean v) throws IOException {
+        assertNotClosed();
+        out.writeBoolean(v);
+    }
+
+    public void writeByte(int v) throws IOException {
+        assertNotClosed();
+        out.writeByte(v);
+    }
+
+    public void writeBytes(String s) throws IOException {
+        assertNotClosed();
+        out.writeBytes(s);
+    }
+
+    public void writeChar(int v) throws IOException {
+        assertNotClosed();
+        out.writeChar(v);
+    }
+
+    public void writeChars(String s) throws IOException {
+        assertNotClosed();
+        out.writeChars(s);
+    }
+
+    public void writeDouble(double v) throws IOException {
+        assertNotClosed();
+        out.writeDouble(v);
+    }
+
+    public void writeFloat(float v) throws IOException {
+        assertNotClosed();
+        out.writeFloat(v);
+    }
+
+    public void writeInt(int v) throws IOException {
+        assertNotClosed();
+        out.writeInt(v);
+    }
+
+    public void writeLong(long v) throws IOException {
+        assertNotClosed();
+        out.writeLong(v);
+    }
+
+    public void writeShort(int v) throws IOException {
+        assertNotClosed();
+        out.writeShort(v);
+    }
+
+    public void writeUTF(String str) throws IOException {
+        assertNotClosed();
+        out.writeUTF(str);
+    }   
+
+    //
+    // Private implementation methods
+    //
+    
+    private void assertNotClosed() {
+        if (closed) {
+            throw new FOStoreFatalInternalException(
+                getClass(), "assertNotClosed", // NOI18N
+                msg.msg("ERR_Closed")); // NOI18N
+        }
+    }
+}



Mime
View raw message