You are viewing a plain text version of this content. The canonical link for it is here.
Posted to jdo-commits@db.apache.org by mb...@apache.org on 2005/05/22 20:40:21 UTC

svn commit: r171355 [8/31] - in /incubator/jdo/trunk/fostore20: ./ src/ src/conf/ src/java/ src/java/org/ src/java/org/apache/ src/java/org/apache/jdo/ src/java/org/apache/jdo/impl/ src/java/org/apache/jdo/impl/fostore/ test/ test/conf/ 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/

Added: incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/GetExtentHandler.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/GetExtentHandler.java?rev=171355&view=auto
==============================================================================
--- incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/GetExtentHandler.java (added)
+++ incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/GetExtentHandler.java Sun May 22 11:40:13 2005
@@ -0,0 +1,254 @@
+/*
+ * 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.util.HashSet;
+import java.util.Iterator;
+
+/**
+* Process GetExtent requests.
+*
+* @author Dave Bristor
+*/
+// This is server-side code.  It does not need to live in the client.
+class GetExtentHandler extends RequestHandler {
+
+    private GetExtentHandler(Reply reply, int length,
+                         FOStoreServerConnection con) {
+
+        super(reply, length, con);
+    }
+    
+    public static final HandlerFactory factory =
+        new HandlerFactory() {
+                public RequestHandler getHandler(Reply reply, int length,
+                                             FOStoreServerConnection con) {
+                return new GetExtentHandler(reply, length, con);
+            }};
+
+    /**
+    * The desired extent's class can be specified either by CLID (i.e., the
+    * class's CLID was already loaded from store to the client) or classname
+    * and FSUID (in case the CLID wasn't known).  In the latter case, look
+    * up the CLID.
+    * <br>
+    * With the CLID, get the set of extents: it will be only one if
+    * subclasses is false, an aribtrary number otherwise.
+    * <br>
+    * Iterate over the extents, writing the items into the reply.
+    * @see RequestHandler#handleRequest
+    * @see GetExtentRequest#doRequestBody
+    */
+    RequestFinisher handleRequest()
+        throws IOException, FOStoreDatabaseException {
+
+        FOStoreInput in = con.getInputFromClient();
+        FOStoreDatabase db = con.getDatabase();
+        HashSet dbExtents = null;
+
+        // true => resulting extent to include subclasses of indicated class.
+        boolean subclasses;
+
+        int maxInstances = in.readInt();
+
+        // By CLID or by classname/fsuid?
+        boolean isCLID = in.readBoolean();
+
+        CLID clid = null;
+        if (isCLID) {
+            clid = CLID.read(in);
+            subclasses = in.readBoolean();
+
+        } else {
+            // Find the clid for the given name/fsuid.
+            
+            String name = in.readUTF();
+            FOStoreSchemaUID fsuid = FOStoreSchemaUID.read(in);
+            subclasses = in.readBoolean();
+
+            if (logger.isDebugEnabled()) {
+                logger.debug(
+                    "GetExtentHandler for name=" + name); // NOI18N
+            }
+
+            for (Iterator i = db.getDBInfo().getDBClasses(); i.hasNext();) {
+                DBClass dbClass = (DBClass)i.next();
+                if (fsuid.equals(dbClass.getFSUID()) &&
+                    name.equals(dbClass.getName())) {
+                    clid = dbClass.getCLID();
+                    // break because there can be only one match.
+                    break;
+                }
+            }
+        }
+
+        // Get the set of CLIDs of extents
+        if (null != clid) {
+            dbExtents = getDBExtents(clid, subclasses, db);
+        }
+
+        if (logger.isDebugEnabled()) {
+            if (null == dbExtents) {
+                logger.debug("GetExtentHandler.hr: no extents"); // NOI18N
+            } else {
+                for (Iterator i = dbExtents.iterator(); i.hasNext();) {
+                    logger.debug(
+                        "GetExtentHandler.hr: extent=" + i.next()); // NOI18N
+                }
+            }
+        }
+
+        Status status = null;
+        int extentSize = 0;
+        int numInstances = 0;
+        int numOIDs = 0;
+        
+        // Write instances into the reply
+        if (null == dbExtents) {
+            reply.writeInt(0);
+            reply.writeInt(0);
+            reply.writeInt(0);
+            status = Status.OK;
+            
+        } else {
+            // Save space for writing various counts in the reply.
+            int extentSizePos = reply.beginStash();
+            int numInstancesPos = reply.beginStash();
+            int numOIDsPos = reply.beginStash();
+
+            for (Iterator i = dbExtents.iterator(); i.hasNext();) {
+                DBExtent extent = (DBExtent)i.next();
+        
+                if (null != extent && extent.size() > 0) {
+
+                    // Fetch some of the instances from the store.
+                    // If we fail to get an object, continue, but set status
+                    // to WARN.
+                    for (Iterator j = extent.iterator(); j.hasNext();) {
+                        OID oid = (OID)j.next();
+                        try {
+                            reply.writeOID(oid);
+                            if (logger.isDebugEnabled()) {
+                                logger.debug(
+                                    "GetExtentHandler.hR/2: " + // NOI18N
+                                    oid  + " " + // NOI18N
+                                    Tester.toHex(oid.oid, 16));
+                            }
+
+                            if (numInstances < maxInstances) {                    
+                                Block block = (Block)db.get(oid);
+                                if (logger.isTraceEnabled()) {
+                                    block.dump();
+                                }
+
+                                byte data[] = block.getData();
+                                reply.writeInt(data.length);
+                                reply.write(data);
+                                numInstances++;
+                            } else {
+                                numOIDs++;
+                            }
+                            extentSize++;
+                        } catch (FOStoreDatabaseException ex) {
+                            status = Status.WARN;
+                        }
+                    }
+                }
+            }
+
+            // Write counts.
+            reply.endStash(extentSize, extentSizePos);
+            reply.endStash(numInstances, numInstancesPos);
+            reply.endStash(numOIDs, numOIDsPos);
+            
+            if (null == status) {
+                status = Status.OK;
+            }
+        }
+        reply.setStatus(status);
+
+        if (logger.isDebugEnabled()) {
+            logger.debug(
+                "GetExtentHandler.hR/3: " + // NOI18N
+                "extentSize=" + extentSize + // NOI18N
+                ", numInstances=" + numInstances + // NOI18N
+                ", numOIDs=" + numOIDs + " " + status); // NOI18N
+        }
+        return null;
+    }
+
+    /**
+    * Get a set of CLIDs of extents for the given clid.  The set will have at
+    * most one element if subclasses is false, or an arbitrary number
+    * otherwise.
+    * @param clid The CLID of the class whose extent is wanted.
+    * @param subclasses If true, then include extents for all subclasses of
+    * the class corresponding to CLID.
+    * @param db Database in which to find extents.
+    * @return Set of extents of clid (and possibly its subclasses).
+    * @throws FOStoreDatabaseException if a database error occurs.
+    */
+    HashSet getDBExtents(CLID clid, boolean subclasses, FOStoreDatabase db)
+        throws FOStoreDatabaseException {
+
+        HashSet rc = null;
+        
+        if (logger.isDebugEnabled()) {
+            logger.debug(
+                "GetExtentHandler.getExtents: for " + clid); // NOI18N
+        }
+        OID oid = db.getDBInfo().getExtentOID(clid);
+        DBExtent extent = (DBExtent)db.getIfExists(oid);
+        if (null != extent) {
+            rc = new HashSet();
+            rc.add(extent);
+        }
+        
+        if (logger.isDebugEnabled()) {
+            logger.debug(
+                "GetExtentHandler.getExtents: got " + extent); // NOI18N
+        }
+        
+        if (subclasses) {
+            OID ssOID = DBInfo.getSubclassSetOID(clid);
+            SubclassSet ss = (SubclassSet)db.getIfExists(ssOID);
+            if (null != ss) {
+                for (Iterator i = ss.iterator(); i.hasNext();) {
+                    CLID subCLID = (CLID)i.next();
+                    OID subExtentOID = DBInfo.getExtentOID(subCLID);
+                    DBExtent subExtent =
+                        (DBExtent)db.getIfExists(subExtentOID);
+                    if (null != subExtent) {
+                        if (logger.isDebugEnabled()) {
+                            logger.debug(
+                                "GetExtentHandler.getExtents: "+ // NOI18N
+                                "subclass " + subExtent); // NOI18N
+                        }
+                        if (null == rc) {
+                            rc = new HashSet();
+                        }
+                        rc.add(subExtent);
+                    }
+                }
+            }
+        }
+        return rc;
+    }
+}

Added: incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/GetExtentRequest.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/GetExtentRequest.java?rev=171355&view=auto
==============================================================================
--- incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/GetExtentRequest.java (added)
+++ incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/GetExtentRequest.java Sun May 22 11:40:13 2005
@@ -0,0 +1,263 @@
+/*
+ * 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.IOException;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+import javax.jdo.Extent;
+import javax.jdo.JDOHelper;
+import javax.jdo.JDOUserException;
+import javax.jdo.PersistenceManager;
+
+import org.apache.jdo.pm.PersistenceManagerInternal;
+import org.apache.jdo.state.StateManagerInternal;
+
+
+/**
+ * Represents a request to get the extent of a class and possibly its
+ * subclasses.
+ *
+ * @author Dave Bristor
+ */
+//
+// This is client-side code.  It does not need to live in the server.
+//
+class GetExtentRequest extends AbstractRequest {
+    /** The PersistenceManagerInternal that is making this request. */
+    private final PersistenceManagerInternal pm;
+    
+    /** The class of the extent sought by this request. */
+    private final Class cls;
+
+    /** If true retrieve instances of cls and its subclasses, otherwise just
+     * of cls. */
+    private final boolean subclasses;
+
+    /** Maximum number of instances that should be returned at a time. */
+    private static final int maxInstances;
+
+    /** Extent returned to user. */
+    private FOStoreExtent extent;
+
+    /** List of returned instances */
+    private ArrayList instances;
+
+    /** List of returned object Ids */
+    private ArrayList oids;
+
+    static {
+        int max = 100;
+        try {
+            String property = (String)AccessController.doPrivileged(
+                new PrivilegedAction () {
+                    public Object run () {
+                        return System.getProperty("maxInstances"); // NOI18N
+                    }
+                }
+                );
+            max = Integer.parseInt(property);
+        } catch (SecurityException ex) {
+            // cannot read maxInstances flag => log warning
+            if (logger.isWarnEnabled())
+                logger.warn(msg.msg("MSG_CannotGetSystemProperty", //NOI18N
+                    "maxInstances", ex.toString())); //NOI18N
+        } catch (Exception ex) {
+            // use default
+        }
+        maxInstances = max;
+    }
+
+    GetExtentRequest(FOStoreExtent extent, Class cls, boolean subclasses,  Message m,
+                     PersistenceManagerInternal pm) {
+
+        super(m, (FOStorePMF)pm.getPersistenceManagerFactory());
+        this.pm = pm;
+        this.cls = cls;
+        this.subclasses = subclasses;
+        this.extent = extent;
+    }
+
+    /**
+     * @see AbstractRequest#doRequestBody
+     * @see InsertRequest#doRequestBody
+     */
+    protected void doRequestBody() throws IOException {
+        //
+        // The format of this request is variable, depending on whether or not
+        // we already have in-client metadata for the given class.
+        //
+        // If we do have in-client metadata for the given class:
+        //
+        // int: maximum number of instances to return
+        // boolean: true
+        // clid of the class
+        // boolean: true if subclasses, false otherwise
+        //
+        // Otherwise:
+        //
+        // int: maximum number of instances to return
+        // boolean: flase
+        // String name of the class
+        // FOStoreSchemaUID of the class.
+        // boolean: true if subclasses, false otherwise
+        //
+
+        FOStoreModel model = pmf.getModel();
+        CLID clid = model.getCLID(cls);
+        out.writeInt(maxInstances);
+        if (null != clid && ! clid.isProvisional()) {
+            out.writeBoolean(true);
+            clid.write(out);
+            if (logger.isDebugEnabled()) {
+                logger.debug("GetExtentRequest.dRB: " + clid // NOI18N
+                               + " subclasses=" + subclasses); // NOI18N
+            }
+        } else {
+            out.writeBoolean(false);
+            out.writeUTF(cls.getName());
+            FOStoreSchemaUID fsuid = FOStoreSchemaUID.lookup(cls, model);
+            fsuid.write(out);
+            if (logger.isDebugEnabled()) {
+                logger.debug(
+                    "GetExtentRequest.dRB: " + cls.getName() // NOI18N
+                    + " subclasses=" + subclasses); // NOI18N
+            }
+        }
+        out.writeBoolean(subclasses);
+    }
+
+    /**
+     * Handles replies to GetExtentRequests.
+     * The format of the reply is:
+     * <pre>
+     * int: count of number of instances in the extent
+     * int: count of the number of instances returned
+     * int: count of the number of oids returned
+     * that many instances
+     * </pre>
+     * The number of instances returned + number of oid returned = number
+     * of instances in the extent.  This is for performance: we don't
+     * want to return *all* the instances at once: we return some, plus
+     * information so that we can get the rest, if the user requests so.
+     * <p>
+     * The status might be Status.WARN, in which case there were OID's in
+     * the database extent which were unreadable.  But the count should
+     * be for the actual number of objects returned.
+     */
+     public void handleReply(Status status, DataInput in, int length)
+         throws IOException {
+
+
+         int extentSize = in.readInt();
+         int numInstances = in.readInt();
+         int numOIDs = in.readInt();
+         if (logger.isDebugEnabled()) {
+             logger.debug(
+                 "GER.hR/1: extentSize=" + extentSize + // NOI18N
+                 ", numInstances=" + numInstances + // NOI18N
+                 ", numOIDs=" + numOIDs); // NOI18N
+         }
+
+         // Get instances for the extent
+         instances =
+             readInstances(in, numInstances, pmf.getModel(), pm, cls);
+
+         // Add OIDs for the extent
+         oids = new ArrayList(numOIDs);
+         for (int i = 0; i < numOIDs; i++) {
+             OID oid = OID.read(in);
+             if (logger.isDebugEnabled()) {
+                 logger.debug("GER.hR/4: " + oid + // NOI18N
+                                " " + Tester.toHex(oid.oid, 16)); // NOI18N
+             }
+             oids.add(oid);
+         }
+    }
+
+
+    /**
+     * Reads instances from given DataInput using a {@link FieldFetcher}.
+     * @param in DataInput from which instances are read.
+     * @param numInstances Number of instances to read from <code>in</code>.
+     * @param model Model required to by {@link FieldFetcher}.
+     * @param pm PersistenceManagerInternal required  {@link FieldFetcher}.
+     * @param cls Candidate Class for which instances are being obtained.
+     * @return ArrayList of instances read.
+     */
+    static ArrayList readInstances(DataInput in, int numInstances,
+                                   FOStoreModel model,
+                                   PersistenceManagerInternal pm,
+                                   Class cls)
+        throws IOException {
+
+         ArrayList rc = new ArrayList(numInstances);
+         for (int i = 0; i < numInstances; i++) {
+             OID oid = OID.read(in);
+             if (logger.isDebugEnabled()) {
+                 logger.debug("GER.readInstances/1: " + oid + // NOI18N
+                                " " + Tester.toHex(oid.oid, 16)); // NOI18N
+             }
+             
+             // Fill in pc's fields.
+             int objLength = in.readInt();
+             if (logger.isDebugEnabled()) {
+                 logger.debug(
+                     "GER.readInstances/2: reading " + objLength +  // NOI18N
+                     " bytes"); // NOI18N
+             }
+             byte data[] = new byte[objLength];
+             in.readFully(data);
+             FieldFetcher ff =
+                 new FieldFetcher(new FOStoreInput(data, 0, objLength),
+                                  model,
+                                  pm,
+                                  cls.getClassLoader());
+             StateManagerInternal sm = ff.fetch(oid);
+             Object pc = sm.getObject();
+             rc.add(pc);
+         }
+         return rc;
+    }
+
+    /** Returns max number of instances */
+    int getMaxInstances() {
+        return maxInstances;
+    }
+
+    /** Returns the list of instances */
+    ArrayList getInstances() {
+        return instances;
+    }
+
+    /** Returns the list of object id's */
+    ArrayList getOIDs() {
+        return oids;
+    }
+
+    /** Returns the Extent associated with this request */
+    Extent getExtent() {
+        return extent;
+    }
+
+}

Added: incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/GetInstancesHandler.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/GetInstancesHandler.java?rev=171355&view=auto
==============================================================================
--- incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/GetInstancesHandler.java (added)
+++ incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/GetInstancesHandler.java Sun May 22 11:40:13 2005
@@ -0,0 +1,101 @@
+/*
+ * 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.util.HashSet;
+import java.util.Iterator;
+
+/**
+* Process GetInstances requests.
+*
+* @author Dave Bristor
+*/
+// This is server-side code.  It does not need to live in the client.
+class GetInstancesHandler extends RequestHandler {
+
+    private GetInstancesHandler(Reply reply, int length,
+                         FOStoreServerConnection con) {
+
+        super(reply, length, con);
+    }
+    
+    public static final HandlerFactory factory =
+        new HandlerFactory() {
+                public RequestHandler getHandler(Reply reply, int length,
+                                             FOStoreServerConnection con) {
+                return new GetInstancesHandler(reply, length, con);
+            }};
+
+    /**
+     * Get some instances from the database, and return them.
+     */
+    RequestFinisher handleRequest()
+        throws IOException, FOStoreDatabaseException {
+
+        FOStoreInput in = con.getInputFromClient();
+        FOStoreDatabase db = con.getDatabase();
+
+        int numInstances = in.readInt();
+
+        Status status = null;
+
+        int numReturned = 0;
+        int numReturnedPos = reply.beginStash();
+
+        for (int i = 0; i < numInstances; i++) {
+            try {
+                OID oid = OID.read(in);
+                reply.writeOID(oid);
+                if (logger.isDebugEnabled()) {
+                    logger.debug(
+                        "GetInstancesHandler.hR/2: " + // NOI18N
+                        oid  + " " + // NOI18N
+                        Tester.toHex(oid.oid, 16));
+                }
+
+                Block block = (Block)db.get(oid);
+                if (logger.isTraceEnabled()) {
+                    block.dump();
+                }
+
+                byte data[] = block.getData();
+                reply.writeInt(data.length);
+                reply.write(data);
+                numReturned++;
+            } catch (FOStoreDatabaseException ex) {
+                status = Status.WARN;
+            }
+        }
+
+        reply.endStash(numReturned, numReturnedPos);
+            
+        if (null == status) {
+            status = Status.OK;
+        }
+        reply.setStatus(status);
+
+        if (logger.isDebugEnabled()) {
+            logger.debug(
+                "GetInstancesHandler.hR/3: " + // NOI18N
+                "numReturned=" + numReturned + ": " +status); // NOI18N
+        }
+        return null;
+    }
+}

Added: incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/GetInstancesRequest.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/GetInstancesRequest.java?rev=171355&view=auto
==============================================================================
--- incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/GetInstancesRequest.java (added)
+++ incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/GetInstancesRequest.java Sun May 22 11:40:13 2005
@@ -0,0 +1,128 @@
+/*
+ * 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.IOException;
+import java.util.ArrayList;
+
+import org.apache.jdo.pm.PersistenceManagerInternal;
+
+
+/**
+ * Represents a request to fetch a batch of instances.
+ *
+ * @author Dave Bristor
+ */
+//
+// This is client-side code.  It does not need to live in the server.
+//
+class GetInstancesRequest extends AbstractRequest {
+    /** List of oids from which we get instances. */
+    private final ArrayList oids;
+
+    /** Starting position in oids ArrayList. */
+    private final int start;
+
+    /** Number of instances to get. */
+    private final int numInstances;
+
+    /** The PersistenceManagerInternal that is making this request. */
+    private final PersistenceManagerInternal pm;
+
+    /** Candidate class for which instances are being obtained. */
+    private final Class cls;
+
+    /** ArrayList returned to user. */
+    private ArrayList instances;
+
+    GetInstancesRequest(ArrayList oids, int start, int numInstances,
+        Message m, PersistenceManagerInternal pm, Class cls) {
+
+        super(m, (FOStorePMF)pm.getPersistenceManagerFactory());
+        this.oids = oids;
+        this.start = start;
+        this.numInstances = numInstances;
+        this.pm = pm;
+        this.cls = cls;
+        
+        if (logger.isDebugEnabled()) {
+            logger.debug("GetInstancesRequest: " + // NOI18N
+                           "start=" + start + // NOI18N
+                           ", numInstances=" + numInstances); // NOI18N
+        }
+    }
+
+    ArrayList getInstances() {
+        return instances;
+    }
+
+    //
+    // Methods from AbstractRequest
+    //
+
+    protected void doRequestBody() throws IOException {
+        //
+        // The format of this request is (aside from the request header):
+        //
+        // int: numOIDs
+        // oid: OID...
+        //
+
+        int numRequested = numInstances;
+        if (start + numInstances > oids.size()) {
+            numRequested = oids.size() - start;
+        }
+
+        out.writeInt(numRequested);
+
+        if (logger.isDebugEnabled()) {
+            logger.debug(
+                "GetInstancesRequest.dRB/0: max=" + numRequested); // NOI18N
+        }
+
+        int end = start + numRequested;
+        for (int i = start; i < end; i++) {
+            OID oid = (OID)oids.get(i);
+            oid.write(out);
+        }
+    }
+
+    
+    //
+    // Methods from Request
+    //
+
+    public void handleReply(Status status, DataInput in, int length)
+        throws IOException {
+
+        //
+        // The format of this reply is
+        //
+        // int: number of instances
+        // that many instances
+        //
+
+        int numReturned = in.readInt();
+        if (logger.isDebugEnabled()) {
+            logger.debug("GetInstancesRequest.hR: numReturned=" + // NOI18N
+                           numReturned);
+        }
+        instances = GetExtentRequest.readInstances(
+            in, numReturned, pmf.getModel(), pm, cls);
+    }
+}

Added: incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/I18N.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/I18N.java?rev=171355&view=auto
==============================================================================
--- incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/I18N.java (added)
+++ incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/I18N.java Sun May 22 11:40:13 2005
@@ -0,0 +1,27 @@
+/*
+ * 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;
+
+/**
+* Provides I18N information for FOStore.
+*
+* @author Dave Bristor
+*/
+class I18N {
+    /** Name of the resource bundle for FOStore. */
+    static final String NAME = "org.apache.jdo.impl.fostore.Bundle"; // NOI18N
+}

Added: incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/InsertHandler.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/InsertHandler.java?rev=171355&view=auto
==============================================================================
--- incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/InsertHandler.java (added)
+++ incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/InsertHandler.java Sun May 22 11:40:13 2005
@@ -0,0 +1,324 @@
+/*
+ * 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 javax.jdo.JDOFatalDataStoreException;
+
+import org.apache.jdo.util.I18NHelper;
+
+/**
+* Process requests to insert objects in the datastore.
+*
+* @author Dave Bristor
+*/
+//
+// This is server-side code.  It does not need to live in the client.
+//
+class InsertHandler extends RequestHandler {
+
+    /** I18N help */
+    private static final I18NHelper msg = I18NHelper.getInstance(I18N.NAME);
+    
+    InsertHandler(Reply reply, int length,
+                          FOStoreServerConnection con) {
+
+        super(reply, length, con);
+    }
+
+    static final HandlerFactory factory =
+        new HandlerFactory() {
+            public RequestHandler getHandler(Reply reply, int length,
+                                             FOStoreServerConnection con) {
+                return new InsertHandler(reply, length, con);
+            }};
+
+
+    /**
+    * Changes all provisional OID's in an instance's in-store Block to real,
+    * datastore OID's.
+    */
+    private class InsertFinisher implements RequestFinisher {
+        private final FOStoreDatabase db;
+        
+        // This is the oid of the object in which we're going to replace the
+        // provisional OID with a real OID.
+        private final OID oid;
+
+        // Offsets into the Block mapped by OID at which provisional OID's
+        // lie.  Replace them with datastore OID's. 
+        private final int oidOffsets[];
+
+        // Offsets into the Block's CLID appendix at which provisional CLID's
+        // lie.  Replace them with datastore CLID's.
+        private final int clidOffsets[];
+
+        InsertFinisher(FOStoreDatabase db, OID oid, DataInput in) 
+            throws IOException {
+            this.db = db;
+            this.oid = oid;
+
+            // Read oidOffsets
+            int numOIDOffsets = in.readInt();
+            if (logger.isDebugEnabled()) {
+                logger.debug("InsertFinisher: numOIDOffsets=" +  // NOI18N
+                               numOIDOffsets);
+            }
+
+            this.oidOffsets = numOIDOffsets > 0 ? new int[numOIDOffsets] : null;
+            if (numOIDOffsets > 0) {
+                for (int i = 0; i < numOIDOffsets; i++) {
+                    oidOffsets[i] = in.readInt();
+                }
+            }
+
+            // Read CLID offsets
+            int numCLIDOffsets = in.readInt();
+            if (logger.isDebugEnabled()) {
+                logger.debug("InsertFinisher: numCLIDOffsets=" +  // NOI18N
+                               numCLIDOffsets);
+            }
+            this.clidOffsets = numCLIDOffsets > 0 ? new int[numCLIDOffsets] : null;
+            if (numCLIDOffsets > 0) {
+                for (int i = 0; i < numCLIDOffsets; i++) {
+                    clidOffsets[i] = in.readInt();
+                }
+            }
+        }
+
+        /**
+         * Replace all provisional OIDs in the data with real OIDs.
+         * Byte array data is the datablock containing provisional OID's which
+         * need to be converted in-place.
+         */
+        private void finishOIDOffsets(byte data[])
+            throws FOStoreDatabaseException, IOException {
+
+            FOStoreInput in =
+                new FOStoreInput(data, 0, data.length);
+            FOStoreOutput out = new FOStoreOutput();
+
+            if (null != oidOffsets) {
+                int numOIDOffsets = oidOffsets.length;
+                for (int i = 0; i < numOIDOffsets; i++) {
+                    int offset = oidOffsets[i];
+                    in.setPos(offset);
+                    OID provOID = OID.read(in);
+                    OID realOID = db.getRealOIDFromProvisional(provOID);
+                    
+                    if (logger.isDebugEnabled()) {
+                        logger.debug("InsertFinisher.finish: i=" + i // NOI18N
+                                       + " offset="+ offset); // NOI18N
+                        logger.debug("InsertFinisher.finish: prov" + provOID +
+                                       " " // NOI18N
+                                       + Tester.toHex(provOID.oid, 16));
+                        logger.debug("InsertFinisher.finish: real" + realOID +
+                                       " " // NOI18N
+                                       + Tester.toHex(realOID.oid, 16));
+                    }
+                    
+                    // Write the real OID
+                    // XXX PERF Best way to convert a long to byte array?
+                    // XXX Conversion should be done by OID itself, since only
+                    // it really knows it's representation is a long.
+                    realOID.write(out);
+                    System.arraycopy(out.getBuf(), 0, data, offset, 8);
+                    out.setPos(0); // Set for next time through.
+                }
+            }
+        }
+        
+        /**
+         * Replace all provisional CLIDs in the data with real CLIDs.
+         * Byte array data is the datablock containing provisional CLID's
+         * which need to be converted in-place.
+         */
+        private void finishCLIDOffsets(byte data[])
+            throws FOStoreDatabaseException, IOException {
+
+            FOStoreInput in =
+                new FOStoreInput(data, 0, data.length);
+            FOStoreOutput out = new FOStoreOutput();
+
+            if (null != clidOffsets) {
+                int numCLIDOffsets = clidOffsets.length;
+                for (int i = 0; i < numCLIDOffsets; i++) {
+                    int offset = clidOffsets[i];
+                    in.setPos(offset);
+                    CLID provCLID = CLID.read(in);
+                    CLID realCLID = db.getRealCLIDFromProvisional(provCLID);
+
+                    if (logger.isDebugEnabled()) {
+                        logger.debug("InsertFinisher.finish: i=" + i // NOI18N
+                                       + " offset="+ offset); // NOI18N
+                        logger.debug("InsertFinisher.finish: prov" + provCLID); // NOI18N
+                        logger.debug("InsertFinisher.finish: real" + realCLID); // NOI18N
+                    }
+
+                    if (null == realCLID) {
+                        throw new JDOFatalDataStoreException(
+                            msg.msg("ERR_NullRealCLID", provCLID)); // NOI18N
+                    }
+
+                    // Write the real CLID
+                    // XXX PERF Best way to convert an int to byte array?
+                    // XXX Conversion should be done by CLID itself, since only
+                    // it really knows its representation is an int.
+                    realCLID.write(out);
+                    System.arraycopy(out.getBuf(), 0, data, offset, 4);
+                    out.setPos(0);
+                }
+            }
+        }
+        
+        /**
+        * @see RequestFinisher#finish
+        */
+        public void finish() {
+            if (logger.isDebugEnabled()) {
+                logger.debug("InsertFinisher.finish: " + oid); // NOI18N
+            }
+
+            if (null != oidOffsets || null != clidOffsets) {
+                try {
+                    Block block = (Block)db.get(oid);
+                    byte data[] = block.getData();
+
+                    if (logger.isDebugEnabled()) {
+                        logger.debug("InsertFinisher.finish: block length=" + // NOI18N
+                                       data.length);
+                    }
+
+                    // Replace each provisional OID with a datastore OID.
+                    finishOIDOffsets(data);
+
+                    // Replace each provisional CLID with a datastore CLID.
+                    finishCLIDOffsets(data);
+
+                    if (logger.isTraceEnabled()) {
+                        logger.trace("InsertFinisher: after finalizing"); // NOI18N
+                        block.dump();
+                    }
+            
+                } catch (FOStoreDatabaseException ex) {
+                    throw new FOStoreFatalInternalException(
+                        this.getClass(), "finish", ex); // NOI18N
+                } catch (IOException ex) {
+                    throw new FOStoreFatalIOException(
+                        this.getClass(), "finish", ex); // NOI18N
+                }
+            }
+        }
+    }
+
+
+    /**
+     * @see RequestHandler#handleRequest
+     */
+    RequestFinisher handleRequest()
+        throws IOException, FOStoreDatabaseException {
+
+        RequestFinisher rc = null;
+        FOStoreInput in = con.getInputFromClient();
+        FOStoreDatabase db = con.getDatabase();
+        DBInfo dbInfo = db.getDBInfo();
+
+        OID oid = OID.read(in);
+        CLID clid = oid.getCLID();
+        if (logger.isDebugEnabled()) {
+            logger.debug("InsertHandler.hR/1: given" + oid // NOI18N
+                           + " " + Tester.toHex(oid.oid, 16)); // NOI18N
+        }
+
+        if (clid.isProvisional()) {
+            clid = db.getRealCLIDFromProvisional(clid);
+        }
+
+        OID realOID;
+        if (oid.isProvisional()) {
+            realOID = db.getRealOIDFromProvisional(oid);
+            if (null == realOID) {
+                realOID = dbInfo.newInstanceOID(clid);
+            }
+        } else {
+            realOID = oid;
+        }
+
+        if (logger.isDebugEnabled()) {
+            logger.debug("InsertHandler.hR/2: real" + realOID + " " // NOI18N
+                           + Tester.toHex(realOID.oid, 16));
+        }
+        Block block = readBlock(in);
+
+        rc = new InsertFinisher(db, realOID, in);
+
+        try {
+            updateDB(realOID, oid, block, db);
+
+            reply.writeOID(realOID);
+            reply.setStatus(Status.OK);
+
+        } catch (Exception ex) {
+            reply.writeOID(realOID);
+            reply.setStatus(Status.ERROR,
+                            msg.msg("ERR_InsertException", realOID)); // NOI18N
+        }
+        
+        return rc;
+    }
+
+    protected Block readBlock(FOStoreInput in) throws IOException {
+        int blockLength = in.readInt();
+        Block block = FOStoreDatabase.createBlock(in, blockLength);
+
+        if (logger.isDebugEnabled()) {
+            logger.debug("InsertHandler.readBlock: blockLength="+  // NOI18N
+                           blockLength);
+            if (logger.isTraceEnabled()) {
+                block.dump();
+            }
+        }
+        return block;
+    }
+
+    /**
+     * Add the block to the database, and to the database's extent.
+     * @param realOID OID to use as key in the database.
+     * @param givenOID by which object was inserted, possibly provisional.
+     * @param block Block to be inserted in database.
+     * @param db Database into which block is inserted.
+     */
+    protected void updateDB(OID realOID, OID givenOID, Block block,
+                            FOStoreDatabase db)
+        throws IOException, FOStoreDatabaseException {
+
+        db.add(realOID, block);
+        if (givenOID.isProvisional()) {
+            db.mapProvisionalOIDToReal(givenOID, realOID);
+        }
+
+        // Add instance to its extent
+        DBInfo dbInfo = db.getDBInfo();
+        OID extentOID = dbInfo.getExtentOID(realOID.getCLID());
+        DBExtent dbExtent  = (DBExtent)db.get(extentOID);
+        dbExtent.add(realOID);
+        con.addExtent(dbExtent);
+    }
+}

Added: incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/InsertRequest.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/InsertRequest.java?rev=171355&view=auto
==============================================================================
--- incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/InsertRequest.java (added)
+++ incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/InsertRequest.java Sun May 22 11:40:13 2005
@@ -0,0 +1,537 @@
+/*
+ * 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.IOException;
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.jdo.model.jdo.PersistenceModifier;
+import org.apache.jdo.pm.PersistenceManagerInternal;
+import org.apache.jdo.sco.SCOCollection;
+import org.apache.jdo.sco.SCOMap;
+import org.apache.jdo.state.FieldManager;
+import org.apache.jdo.state.StateManagerInternal;
+
+/**
+ * Represents a request to write a new object to the datastore.
+ *
+ * @author Dave Bristor
+ * @version 1.0.1
+ */
+//
+// This is client-side code.  It does not need to live in the server.
+//
+class InsertRequest extends AbstractFieldRequest {
+    // Provisional object id of object being inserted by this request.
+    private final OID oid;
+
+    // Metadata for this object.
+    private final FOStoreModel model;
+
+    private final Class cls;
+
+    // Set of CLID's of the object instances referenced by this object's
+    // fields (note that Strings are omitted).  This is sent to the store
+    // along with the object values, as an appendix, so that when
+    // reconstituting the object, information about the referenced classes is
+    // available.  Of course, metadata for the object is available (it was or
+    // will be sent to the store in an ActivateClassRequest), but that field
+    // information is about the type of referenced objects, not about their
+    // class.  See storeObjectField().
+    private Set clids = null;
+
+    // Set of int arrays of object references in this object which are
+    // provisional, as offsets of OID's in the request buffer.  See the end
+    // of doRequestBody, and storeObjectField().  Each field may add one
+    // entry to the ArrayList; each field may have any number of offsets
+    // within it.  totNumOffsets is the total number of offsets, across all
+    // arrays in the ArrayList.
+    private ArrayList oidOffsets = new ArrayList();
+    private int numOidOffsets = 0;
+
+    private int clidOffsets[];
+    private int numClidOffsets;
+
+    InsertRequest(StateManagerInternal sm, Message m, FOStorePMF pmf) {
+        super(sm, m, pmf);
+        this.oid = (OID)sm.getInternalObjectId();
+        this.model = pmf.getModel();
+        this.cls = sm.getPCClass();
+    }
+
+    //
+    // Methods from AbstractRequest
+    //
+
+    /**
+     * Provides detail about data being inserted in an InsertRequest.
+     * The format of this request is (aside from the request header):
+     * <pre>
+     * oid: OID
+     * length of data block containing classname, field values, CLID info: int
+     * className: String (fully qualified name of class of object)
+     * fostoreSchemaUID for class
+     * length of the field values part of this block: int
+     * fieldValue: Object... (repeats numFields times)
+     * number of [CLID, classname] pairs for Object fields of this object
+     * [CLID, classname]...
+     * (the following are not in the above noted length bytes of this block)
+     * number of provisional OID's written in this request
+     * OID offset...
+     * number of the above written CLIDs that are provisional
+     * CLID offset...
+     * </pre>
+     *
+     * In the case of both the OID and CLID offsets, the offset is from
+     * the beginning of the block.  In the case of the CLIDs and the OID
+     * and CLID offsets, the size of each set written may be zero but
+     * that size is always written.
+     * <p>
+     * Note that the number of CLID/classname pairs and the CLID/classname
+     * pairs themselves are part of the data block that is intended to be
+     * stored by the database server (and hence later returned upon
+     * fetch/getExtent).  That is, the size written includes those pairs.
+     * The offsets, however, are not part of the datablock; they are used
+     * by the database server and discarded.
+     * @see AbstractRequest#doRequestBody
+     */
+    protected void doRequestBody() throws IOException {
+        oid.write(out);
+
+        // Write out the values of all the fields.
+        int startPos = writeBlock(jdoClass.getPersistentFieldNumbers(), false);
+
+        // Now write the oidOffsets, so that the store can turn provisional
+        // OID's into datastore OID's.
+        if (logger.isDebugEnabled()) {
+            logger.debug("InsertRequest.dRB: numoidOffsets=" + // NOI18N
+                           numOidOffsets);
+        }
+        out.writeInt(numOidOffsets);
+        int size = oidOffsets.size();
+        for (int i = 0; i < size; i++) {
+            int fieldOffsets[] = (int[])(oidOffsets.get(i));
+            int numOffsets = fieldOffsets.length;
+            for (int j = 0; j < numOffsets; j++) {
+                // Write out offset relative to start of the data block.
+                out.writeInt(fieldOffsets[j] - startPos);
+                if (logger.isDebugEnabled()) {
+                    logger.debug(
+                        "InsertRequest.dRB: " + oid // NOI18N
+                        + " rawOffset=" + fieldOffsets[j] // NOI18N
+                        + " offset=" + // NOI18N
+                        (fieldOffsets[j] - startPos));
+                }
+            }
+        }
+
+        // Now write the offsets of the provisional CLID's
+        if (logger.isDebugEnabled()) {
+            logger.debug("InsertRequest.dRB: numClidOffsets=" + // NOI18N
+                           numClidOffsets);
+        }
+        out.writeInt(numClidOffsets);
+        for (int i = 0; i < numClidOffsets; i++) {
+            out.writeInt(clidOffsets[i]);
+        }
+    }
+
+    //
+    // Methods from Request
+    //
+
+    /**
+     * Reads the oid, and notifies the persistence manager and state manager
+     * of the new oid.
+     * @see Request#handleReply
+     */
+    public void handleReply(Status status, DataInput in, int length)
+        throws IOException {
+
+        OID replyOid = OID.read(in);
+
+        // We don't have to update the cache, because we will when the
+        // instance was made persistent, we did a CreateOIDRequest, and it's
+        // reply updated the cache.
+
+        if (logger.isDebugEnabled()) {
+            logger.debug("InsertRequest.hR: " + status + ", " + // NOI18N
+                           oid + " " + // NOI18N
+                           Tester.toHex(oid.oid, 16) +
+                           " -> " + replyOid + " " + // NOI18N
+                           Tester.toHex(replyOid.oid, 16));
+        }
+    }
+
+    //
+    // Methods from FieldManager
+    //
+
+    /**
+    * @see org.apache.jdo.state.FieldManager#storeBooleanField(int fieldNum,
+    * boolean value)
+    */
+    public void storeBooleanField(int fieldNum, boolean value) {
+        FOStoreTranscriber t = model.getTranscriber(cls, fieldNum);
+        try {
+            t.storeBoolean(value, out);
+        } catch (IOException ex) {
+            throw new FOStoreFatalIOException(
+                this.getClass(), "storeBooleanField", ex); // NOI18N
+        }
+    }
+
+    /**
+    * @see org.apache.jdo.state.FieldManager#storeCharField(int fieldNum,
+    * char value)
+    */
+    public void storeCharField(int fieldNum, char value) {
+        FOStoreTranscriber t = model.getTranscriber(cls, fieldNum);
+        try {
+            t.storeChar(value, out);
+        } catch (IOException ex) {
+            throw new FOStoreFatalIOException(
+                this.getClass(), "storeCharField", ex); // NOI18N
+        }
+    }
+
+    /**
+    * @see org.apache.jdo.state.FieldManager#storeByteField(int fieldNum,
+    * byte value)
+    */
+    public void storeByteField(int fieldNum, byte value) {
+        FOStoreTranscriber t = model.getTranscriber(cls, fieldNum);
+        try {
+            t.storeByte(value, out);
+        } catch (IOException ex) {
+            throw new FOStoreFatalIOException(
+                this.getClass(), "storeByteField", ex); // NOI18N
+        }
+    }
+
+    /**
+    * @see org.apache.jdo.state.FieldManager#storeShortField(int fieldNum,
+    * short value)
+    */
+    public void storeShortField(int fieldNum, short value) {
+        FOStoreTranscriber t = model.getTranscriber(cls, fieldNum);
+        try {
+            t.storeShort(value, out);
+        } catch (IOException ex) {
+            throw new FOStoreFatalIOException(
+                this.getClass(), "storeShortField", ex); // NOI18N
+        }
+    }
+
+    /**
+    * @see org.apache.jdo.state.FieldManager#storeIntField(int fieldNum, int value)
+    */
+    public void storeIntField(int fieldNum, int value) {
+        FOStoreTranscriber t = model.getTranscriber(cls, fieldNum);
+        try {
+            t.storeInt(value, out);
+        } catch (IOException ex) {
+            throw new FOStoreFatalIOException(
+                this.getClass(), "storeIntField", ex); // NOI18N
+        }
+    }
+
+    /**
+    * @see org.apache.jdo.state.FieldManager#storeLongField(int fieldNum,
+    * long value)
+    */
+    public void storeLongField(int fieldNum, long value) {
+        FOStoreTranscriber t = model.getTranscriber(cls, fieldNum);
+        try {
+            t.storeLong(value, out);
+        } catch (IOException ex) {
+            throw new FOStoreFatalIOException(
+                this.getClass(), "storeLongField", ex); // NOI18N
+        }
+    }
+
+    /**
+    * @see org.apache.jdo.state.FieldManager#storeFloatField(int fieldNum,
+    * float value)
+    */
+    public void storeFloatField(int fieldNum, float value) {
+        FOStoreTranscriber t = model.getTranscriber(cls, fieldNum);
+        try {
+            t.storeFloat(value, out);
+        } catch (IOException ex) {
+            throw new FOStoreFatalIOException(
+                this.getClass(), "storeFloatField", ex); // NOI18N
+        }
+    }
+
+    /**
+    * @see org.apache.jdo.state.FieldManager#storeDoubleField(int fieldNum,
+    * double value)
+    */
+    public void storeDoubleField(int fieldNum, double value) {
+        FOStoreTranscriber t = model.getTranscriber(cls, fieldNum);
+        try {
+            t.storeDouble(value, out);
+        } catch (IOException ex) {
+            throw new FOStoreFatalIOException(
+                this.getClass(), "storeDoubleField", ex); // NOI18N
+        }
+    }
+
+    /**
+    * @see org.apache.jdo.state.FieldManager#storeStringField(int fieldNum,
+    * String value)
+    */
+    public void storeStringField(int fieldNum, String value) {
+        FOStoreTranscriber t = model.getTranscriber(cls, fieldNum);
+        try {
+            // Though it is a String, we need to preserve pm value
+            // in the ObjectTranscriber in case this is request
+            // to fetch a PC (embedded or because its field is accessed.
+            PersistenceManagerInternal pm =
+                (PersistenceManagerInternal)sm.getPersistenceManager();
+            t.storeObject(value, out, pm); 
+        } catch (IOException ex) {
+            throw new FOStoreFatalIOException(
+                this.getClass(), "storeStringField", ex); // NOI18N
+        }
+    }
+
+    /**
+    * @see org.apache.jdo.state.FieldManager#storeObjectField(int fieldNum,
+    * Object value)
+    */
+    public void storeObjectField(int fieldNum, Object value) {
+        FOStoreTranscriber t = model.getTranscriber(cls, fieldNum);
+        try {
+            PersistenceManagerInternal pm =
+                (PersistenceManagerInternal)sm.getPersistenceManager();
+            int fieldOffsets[] = t.storeObject(value, out, pm);
+
+            // Add the field's object's CLID.
+            addCLID(value);
+
+            // If value is Collection, Map, or array then need to add the
+            // Class's of its elements.
+            if (null != value) {
+                if (value instanceof Collection) {
+                    addCollectionCLIDs((Collection)value);
+                } else if (value instanceof Map) {
+                    addMapCLIDs((Map)value);
+                } else {
+                    Class cls = value.getClass().getComponentType();
+                    if (null != cls) {
+                        // We have an array.  We have to add the CLIDs for all
+                        // its elements, not just for the component type,
+                        // because the class of the elements could be a
+                        // subclass or implementation of the component type.
+                        addArrayCLIDs(value);
+                    }
+                }
+            }
+
+            // Check for and store offsets.
+            if (null != fieldOffsets) {                
+                oidOffsets.add(fieldOffsets);
+                numOidOffsets += fieldOffsets.length;
+                if (logger.isDebugEnabled()) {
+                    logger.debug(
+                        "InsertRequest.sOF: fieldNum=" + fieldNum // NOI18N
+                        + " numOffsets=" + fieldOffsets.length); // NOI18N
+                }
+            }
+        } catch (IOException ex) {
+            throw new FOStoreFatalIOException(
+                this.getClass(), "storeObjectField", ex); // NOI18N
+        }
+    }
+
+    //
+    // Implementation detail
+    //
+
+    protected OID getOID() {
+        return oid;
+    }
+
+    /**
+     * Writes a data block, which consists of the values of the specified
+     * fields, plus the CLID's and corresponding class names of referenced
+     * objects.
+     * @param fields Field numbers of the fields to be written
+     * @param identifying If true, write before/flushed image fields,
+     * otherwise write current fields.
+     * @return Position in output stream at which data block starts
+     */
+    protected int writeBlock(int fields[], boolean identifying) throws IOException {    
+        // Save and overwrite the position where we later write the length of
+        // the data.
+        int dataLengthPos = out.getPos();
+        out.writeInt(LENGTH_COOKIE);
+
+        // Save start of data block
+        int startPos = out.getPos();
+
+        // Initialize list of CLIDs used by this instance
+        clids = new HashSet();
+
+        // Fully qualified class name and FOStoreSchemaUID
+        if (logger.isDebugEnabled()) {
+            logger.debug("IR: className=" + jdoClass.getName() + // NOI18N
+                           ", fsuid=" + fsuid); // NOI18N
+        }
+        out.writeUTF(jdoClass.getName());
+        fsuid.write(out);
+
+        if (logger.isDebugEnabled()) {
+            logger.debug("InsertRequest.writeBlock: classname=" + // NOI18N
+                           jdoClass.getName());
+        }
+
+        insertFields(fields, identifying);
+
+        // Write the CLID's and classnames.  Some might be provisional, so as
+        // with the OID's we must write their offsets so they can be turned
+        // into real CLID's in the store.  Here we save the offsets, to write
+        // them later, after the data block.
+        int size = clids.size();
+        clidOffsets = new int[size]; // Max num of possible provisionals
+        numClidOffsets = 0;
+        if (logger.isDebugEnabled()) {
+            logger.debug(
+                "InsertRequest.writeBlock: numCLID's=" +  // NOI18N
+                size);
+        }
+        out.writeInt(size);
+        for (Iterator i = clids.iterator(); i.hasNext();) {
+            CLID c = (CLID)i.next();
+            if (c.isProvisional()) {
+                clidOffsets[numClidOffsets++] = out.getPos() - startPos;
+            }
+            c.write(out);
+            Class clz = CLID.getKnownType(c);
+            if (null == clz) {
+                clz = model.getClass(c);
+            }
+            if (logger.isDebugEnabled()) {
+                logger.debug("InsertRequest.writeBlock: " + c); // NOI18N
+            }
+            String className = clz.getName();
+            if (logger.isDebugEnabled()) {
+                logger.debug(
+                    "InsertRequest.writeBlock: field type " + // NOI18N
+                    className);
+            }
+            out.writeUTF(className);
+            FOStoreSchemaUID fldUID = FOStoreSchemaUID.lookup(clz, model);
+            fldUID.write(out);
+        }
+
+        // Write the length of the block (data + CLID's)
+        int currentPos = out.getPos();
+        int length = currentPos - startPos;
+        if (logger.isDebugEnabled()) {
+            logger.debug("InsertRequest.dRB: length=" + length); // NOI18N
+        }
+        out.setPos(dataLengthPos);
+        out.writeInt(length);
+        out.setPos(currentPos);
+
+        return startPos;
+    }
+
+    /**
+     * Writes values of the specified fields.  If identifying is true, writes
+     * identifying fields, otherwise writes current fields.
+     */
+    private void insertFields(int[] fields, boolean identifying)
+        throws IOException {
+
+        int fieldLengthPos = out.getPos();
+        out.writeInt(LENGTH_COOKIE);
+        int fieldPos = out.getPos();
+        
+        sm.provideFields(fields, this, identifying);
+        
+        // Write the length of the field values part of the block.
+        int currentPos = out.getPos();
+        int length = currentPos - fieldPos;
+        out.setPos(fieldLengthPos);
+        out.writeInt(length);
+        out.setPos(currentPos);
+
+        if (logger.isDebugEnabled()) {
+            logger.debug("InsertRequest.dRB: field values length=" + length); // NOI18N
+        }
+    }
+
+    private void addCollectionCLIDs(Collection c) {
+        Iterator i;
+        if (c instanceof SCOCollection) {
+            SCOCollection sco = (SCOCollection)c;
+            i = sco.eitherIterator();
+        } else {
+            i = c.iterator();
+        }
+        while(i.hasNext()) {
+            addCLID(i.next());
+        }
+    }
+
+    private void addMapCLIDs(Map m) {
+        Iterator i = null;
+        if (m instanceof SCOMap) {
+            i = ((SCOMap)m).eitherIterator();
+        } else {
+            i = m.entrySet().iterator();
+        }
+        while (i.hasNext()) {
+            Map.Entry entry = (Map.Entry)i.next();
+            addCLID(entry.getKey());
+            addCLID(entry.getValue());
+        }
+    }
+
+    private void addArrayCLIDs(Object arr) {
+        try {
+            int length = Array.getLength(arr);
+            for (int i = 0; i < length; i++) {
+                Object o = Array.get(arr, i);
+                addCLID(o);
+            }
+        } catch (RuntimeException ex) {
+            throw new FOStoreFatalInternalException(
+                this.getClass(), "addArrayCLIDs", ex); // NOI18N
+        }
+    }
+
+    private void addCLID(Object o) {
+        if (null != o) {
+            Class cls = o.getClass();
+            if (! CLID.isKnown(cls)) {
+                clids.add(model.getCLID(cls));
+            }
+        }
+    }
+}

Added: incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/IntTranscriber.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/IntTranscriber.java?rev=171355&view=auto
==============================================================================
--- incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/IntTranscriber.java (added)
+++ incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/IntTranscriber.java Sun May 22 11:40:13 2005
@@ -0,0 +1,48 @@
+/*
+ * 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;
+
+/**
+* Transcribes int values.
+*
+* @author Dave Bristor
+*/
+class IntTranscriber extends FOStoreTranscriber {
+    private static IntTranscriber instance = new IntTranscriber();
+
+    private IntTranscriber() {}
+
+    static IntTranscriber getInstance() {
+        return instance;
+    }
+    
+    void storeInt(int value, DataOutput out) throws IOException {
+        out.writeInt(value);
+    }
+
+    int fetchInt(DataInput in) throws IOException {
+        return in.readInt();
+    }
+
+    void skip(DataInput in) throws IOException { 
+        in.readInt(); 
+    }
+}

Added: incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/LoginHandler.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/LoginHandler.java?rev=171355&view=auto
==============================================================================
--- incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/LoginHandler.java (added)
+++ incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/LoginHandler.java Sun May 22 11:40:13 2005
@@ -0,0 +1,109 @@
+/*
+ * 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.
+ */
+
+/*
+ * Handler for LoginRequests.
+ *
+ * LoginHandler.java
+ *
+ * Created on June 7, 2001, 4:16 PM
+ */
+
+package org.apache.jdo.impl.fostore;
+
+import java.io.IOException;
+import java.io.DataInput;
+import java.io.DataOutput;
+
+import javax.jdo.JDODataStoreException;
+import javax.jdo.JDOFatalDataStoreException;
+
+import org.apache.jdo.util.I18NHelper;
+
+
+/**
+ * Handler for LoginRequests.
+ * @author  Craig Russell
+ * @version 1.0
+ */
+class LoginHandler extends RequestHandler {
+    /** the database name
+     */    
+    String dbname;
+    
+    /** the user of the database
+     */    
+    String user;
+    
+    /** a pseudo random number
+     */    
+    long timestamp; 
+    
+    /** a message digest which is a shared secret
+     */    
+    byte[] secret;
+    
+    /** a flag to tell whether to create the database
+     */
+    boolean create;
+
+    /** Construct an instance of the LoginHandler to service this request.
+     * @param reply the reply for the request
+     * @param length the length of the request
+     * @param con the FOStoreServerConnection with the request
+     */    
+    private LoginHandler(Reply reply, int length,
+                         FOStoreServerConnection con) {
+
+        super(reply, length, con);
+    }
+    
+    /** the factory used to create the handler for this request
+     */    
+    public static final HandlerFactory factory =
+        new HandlerFactory() {
+                public RequestHandler getHandler(Reply reply, int length,
+                                             FOStoreServerConnection con) {
+                return new LoginHandler(reply, length, con);
+            }};
+
+    /** Process the request by analyzing the database and user login information
+     * from the request buffer.  This will create the database if needed, open
+     * it, and verify the user and password.
+     *
+     * @throws IOException if any problems
+     * @return null; there is no need for a finisher.
+     */            
+    RequestFinisher handleRequest()
+        throws IOException, FOStoreDatabaseException {
+        DataInput in = con.getInputFromClient();
+        // read the utf encoded user and password for verification.
+        dbname = in.readUTF();
+        user = in.readUTF();
+        timestamp = in.readLong();
+        int secretSize = in.readInt();
+        secret = new byte[secretSize];
+        in.readFully(secret);
+        create = in.readBoolean();
+        try {
+            con.openDatabase(dbname, user, timestamp, secret, create);
+        } catch (Exception e) {
+            throw new FOStoreLoginException(dbname, user, e);
+        }
+        reply.setStatus(Status.OK);
+        return null;
+    }
+}

Added: incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/LoginRequest.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/LoginRequest.java?rev=171355&view=auto
==============================================================================
--- incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/LoginRequest.java (added)
+++ incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/LoginRequest.java Sun May 22 11:40:13 2005
@@ -0,0 +1,151 @@
+/*
+ * 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.
+ */
+
+/*
+ * Request to login to a database.
+ *
+ * LoginRequest.java
+ *
+ * Created on June 7, 2001, 3:28 PM
+ */
+
+package org.apache.jdo.impl.fostore;
+
+import java.io.IOException;
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.UnsupportedEncodingException;
+import java.util.Date;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+import javax.jdo.JDODataStoreException;
+import javax.jdo.JDOFatalInternalException;
+
+import org.apache.jdo.util.I18NHelper;
+
+
+/**
+ * Request to login to a database.
+ * @author  Craig Russell
+ * @version 1.0
+ */
+class LoginRequest extends AbstractRequest {
+    /** The database name from the PMF URL property.
+     */    
+    String dbname;
+    
+    /** The user from the PMF user property.
+     */    
+    String user;
+    
+    /** The password from the PMF password property.
+     */    
+    String password;
+    
+    /** This is the Date.getTime() of the time the request
+     * was created.  It is used to construct the shared secret
+     * to verify the password at the server side, without
+     * transmitting the password in clear.
+     */    
+    long timestamp;
+    
+    /** The secret constructed from the user, timestamp, and password.
+     */    
+    byte[] secret;
+    
+    /** A flag telling whether to create the database
+     */
+    boolean create;
+    
+    /** Creates new LoginRequest
+     * @param m the Message
+     * @param pmf the PersistenceManagerFactory
+     * @param user the user
+     * @param password the password
+     */
+    public LoginRequest(Message m, FOStorePMF pmf, String dbname, String user, String password, boolean create) {
+        super (m, pmf);
+        this.dbname = dbname;
+        this.user = user;
+        this.password = password;
+        this.create = create;
+        timestamp = new Date().getTime();
+        MessageDigest md;
+        try {
+            md = MessageDigest.getInstance("MD5"); // NOI18N
+            md.update (dbname.getBytes("UTF-8")); // NOI18N
+            md.update (user.getBytes("UTF-8")); // NOI18N
+            md.update ((Long.toString(timestamp)).getBytes("UTF-8")); // NOI18N
+//            md.update (password.getBytes("UTF-8")); // XXX add back when database can look up password
+            this.secret = md.digest(); 
+        } catch (NoSuchAlgorithmException nsae) {
+            throw new JDOFatalInternalException (
+                msg.msg("ERR_NoSuchAlgorithmException", dbname, user), // NOI18N
+                new Exception[]{nsae});
+        } catch (UnsupportedEncodingException uee) {
+            throw new JDOFatalInternalException (
+                msg.msg("ERR_UnsupportedEncodingException", dbname), // NOI18N
+                new Exception[]{uee});
+        }
+    }
+
+    /**
+     * Subclasses must implement in this method the actual writing of their
+     * Request type-specific data.
+     * @throws IOException if any errors constructing the stream
+     */
+    protected void doRequestBody() throws IOException {
+        //
+        // The format of this request is (aside from the request header):
+        //
+        // dbname: the database name property (part of the URL) of the PMF
+        // user: the user property of the PMF
+        // timestamp: the current Date in milliseconds
+        // XXX change the following to be a shared secret based on the password
+        // password: the password property of the PMF 
+        // secret.length: the length of the secret
+        // secret: the secret as a byte array
+
+        if (logger.isDebugEnabled()) logger.debug("LoginRequest.dRB"); // NOI18N
+        out.writeUTF (dbname);
+        out.writeUTF (user);
+        out.writeLong (timestamp);
+        out.writeInt (secret.length);
+        out.write (secret);
+        out.writeBoolean (create);
+    }
+    
+    /**
+     * Processes the results of the effect of the request in the store.  To be
+     * invoked after the store has processed the request, and has returned
+     * information about that request, such as its status and any accompanying
+     * data.
+     * @param in
+     * @param length
+     * @param status Indication as to the success, failure, etc. of the
+     * request as handled by the store.
+     * @throws IOException
+     */
+    public void handleReply(Status status, DataInput in, int length) throws IOException {
+        if (logger.isDebugEnabled()) logger.debug("LoginRequest.hR"); // NOI18N
+
+        if (!status.equals (Status.OK)) {
+            throw new JDODataStoreException (msg.msg("EXC_CannotLogin")); // NOI18N
+        }
+    }
+}

Added: incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/LongTranscriber.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/LongTranscriber.java?rev=171355&view=auto
==============================================================================
--- incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/LongTranscriber.java (added)
+++ incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/LongTranscriber.java Sun May 22 11:40:13 2005
@@ -0,0 +1,48 @@
+/*
+ * 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;
+
+/**
+* Transcribes long values.
+*
+* @author Dave Bristor
+*/
+class LongTranscriber extends FOStoreTranscriber {
+    private static LongTranscriber instance = new LongTranscriber();
+
+    private LongTranscriber() {}
+
+    static LongTranscriber getInstance() {
+        return instance;
+    }
+    
+    void storeLong(long value, DataOutput out) throws IOException {
+        out.writeLong(value);
+    }
+
+    long fetchLong(DataInput in) throws IOException {
+        return in.readLong();
+    }
+
+    void skip(DataInput in) throws IOException { 
+        in.readLong(); 
+    }
+}