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 [20/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:01 GMT
Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreConnectionFactory.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreConnectionFactory.java?view=auto&rev=158176
==============================================================================
--- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreConnectionFactory.java (added)
+++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreConnectionFactory.java Fri Mar 18 17:02:29 2005
@@ -0,0 +1,715 @@
+/*
+ * 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.PrintWriter;
+import java.io.Serializable;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.UnknownHostException;
+import java.net.ConnectException;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import javax.jdo.JDOFatalException;
+import javax.jdo.JDOFatalInternalException;
+import javax.jdo.JDOFatalDataStoreException;
+import javax.jdo.JDOUserException;
+import javax.jdo.JDOFatalUserException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.apache.jdo.pm.Accessor;
+import org.apache.jdo.util.I18NHelper;
+import org.apache.jdo.util.Pool;
+
+/**
+ * A connection factory for FOStore.  Allows both same- and remote-address
+ * space connections.  For the same address space-connections, the URL must
+ * not include the Host (Server) parameter.  For remote address space
+ * connections, the URL's protocol is ignored.
+ * <p>
+ * This class is <code>public</code> so that clients can create instances of it
+ * with <code>new</code>.
+ *
+ * @author Dave Bristor
+ */
+public class FOStoreConnectionFactory implements Serializable {
+    private String url;
+    private String userName;
+    private String password;
+    private String driverName;
+    private boolean create;
+    
+    private FOStorePMF pmf;
+
+    private int loginTimeout;
+
+    private transient PrintWriter logWriter;
+    
+    /** Connections are created by the FOStoreURLStreamHandler.
+     */
+    private final FOStoreURLStreamHandler streamHandler = 
+        FOStoreURLStreamHandler.getInstance();
+
+    /** Connections are pooled.  Each unique combination of url, 
+     * user, password has its own pool.  The hashmap associates 
+     * a FOStoreConnectionId with its pool of connections.
+     */
+    private final HashMap connectionMap = new HashMap();
+    
+    /** For now, set the pool size to 1.
+     */
+    // XXX this needs to be configurable...
+    private static final int poolSize = 1;
+
+    private FOStoreConnectionId defaultConnectionId;
+    
+    private FOStoreConnectionId userConnectionId;
+
+    /** True until setConfigured has been invoked.  Allows properties to be
+     * set if true.
+     */
+    private boolean configurable = true;
+
+    /** This table maps from names to CFAccessors.  The names are the same as the
+     * persistence manager factory's property names, but with 
+     * org.apache.jdo.FOStoreConnectionFactory.option prepended.
+     */
+    protected static HashMap CFpropsAccessors = new HashMap(9);
+
+    /** 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
+
+    /**
+     * First time a FOStoreConnectionFactory is created, initialize accessors
+     * which are used to store/save instances via JNDI.
+     */
+    public FOStoreConnectionFactory() {
+        if (logger.isDebugEnabled()) logger.debug("FOCF()"); // NOI18N
+            initPropsAccessors();
+    }
+    
+    /** Set the url, user, and password into the ConnectionIds for this
+     * connection factory.
+     */
+    private void setConfigured() {
+        if (logger.isDebugEnabled()) {
+            logger.debug("FOCF.setConfigured: URL: " + url); // NOI18N
+        }
+        configurable = false;
+        defaultConnectionId =
+            new FOStoreConnectionId(url, userName, password, create);
+        userConnectionId = new FOStoreConnectionId(url, null, null, false);
+    }
+    
+    private void assertConfigurable() {
+        if (configurable) return;
+        throw new JDOUserException (
+            msg.msg("EXC_AssertConfigurableFailure")); // NOI18N
+    }
+
+    /**
+     * Provides a connection to the database using the given userName and
+     * password.  The first time a connection is made, the
+     * factory can no longer be configured.
+     * @return A FOStoreClientConnection
+     */
+    public synchronized FOStoreClientConnection getConnection(
+            String user, String password) {
+        setConfigured(); // initializes userConnectionId with url.
+        FOStoreConnection rc = null;
+
+        if (logger.isDebugEnabled()) {
+            logger.debug("FOCF.getConnection(" + user + ", " + 
+                           password + "): " + hashCode()); // NOI18N
+        }
+        // We reuse the same userConnectionId until we need to create a new
+        // Pool for it.  The we create a new one for next time.
+        FOStoreConnectionId connectionId = userConnectionId;
+        connectionId.setUser (user);
+        connectionId.setPassword (password);
+        
+        // Try to find the existing connection in the pool.
+        // First time we get here, database is not yet open and connections
+        // are not yet created/in-pool.
+        Pool pool = (Pool) connectionMap.get (connectionId);
+        if (null == pool) {
+            pool = createPool (connectionId);
+            userConnectionId = new FOStoreConnectionId (url, null, null);
+        }
+        try {
+            // blocks until a connection is available.
+            return (FOStoreClientConnection) pool.get(); 
+        } catch (InterruptedException ex) {
+            throw new JDOFatalInternalException(
+                msg.msg("ERR_PoolGet"), ex); // NOI18N
+        }
+    }
+
+    /** Create a new pool of connections for this combination of url, user,
+     * and password.  This might be either the default or for a specific user.
+     */
+     Pool createPool (FOStoreConnectionId id) {
+        Pool pool = new Pool(poolSize);
+        if (connectionMap.put (id, pool) != null) {
+            throw new JDOFatalInternalException (
+                msg.msg("ERR_DuplicatePool")); // NOI18N
+        }
+        try {
+            if (logger.isDebugEnabled()) {
+                logger.debug("FOCF: first time; filling pool"); // NOI18N
+            }
+            for (int i = 0; i < poolSize; i++) {
+                FOStoreClientConnection connection =
+                    createConnection(id);
+                pool.put(connection);
+            }
+        } catch (InterruptedException ex) {
+            throw new JDOFatalInternalException(
+                msg.msg("ERR_PoolPutFill"), ex); // NOI18N
+        }
+        return pool;
+        }
+
+    /**
+     * Provides a connection to the database using the configured userName,
+     * password, and url.  The first time a connection is made, the
+     * factory can no longer be configured.
+     * @return A FOStoreClientConnection
+     */
+    public synchronized FOStoreClientConnection getConnection() {
+        setConfigured();
+        FOStoreConnection rc = null;
+
+        if (logger.isDebugEnabled()) {
+            logger.debug("FOCF.getConnection(): " + hashCode()); // NOI18N
+        }
+
+        // First time we get here, database is not yet open and connections
+        // are not yet created/in-pool.
+        
+        Pool pool = (Pool) connectionMap.get (defaultConnectionId);
+        if (null == pool) {
+            pool = createPool (defaultConnectionId);
+        }
+        try {
+            // blocks until a connection is available.
+            return (FOStoreClientConnection) pool.get(); 
+        } catch (InterruptedException ex) {
+            throw new JDOFatalInternalException(
+                msg.msg("ERR_PoolGet"), ex); // NOI18N
+        }
+    }
+            
+    /** 
+     * This method requires permission to perform the following requests:
+     * Create new URL with the specified StreamHandler.
+     * Delete old database id create flag is set to true.
+     */
+    private FOStoreClientConnection createConnection(
+        final FOStoreConnectionId id) {
+        final FOStoreConnectionFactory cf = this;
+        return (FOStoreClientConnection) AccessController.doPrivileged (
+            new PrivilegedAction () {
+                public Object run () {
+                    URL uRL = null;
+                    try {
+                        uRL = new URL (null, url, streamHandler);
+                        FOStoreClientConnection connection =
+                            (FOStoreClientConnection) streamHandler.openConnection(uRL);
+                        connection.setConnectionFactory(cf);
+                        connection.setConnectionId(id);
+                        connection.connect();
+                        return connection;
+                    } catch (SecurityException se) {
+                        throw new JDOFatalUserException(
+                            msg.msg("EXC_CannotSpecifyStreamHandler"), se); //NOI18N
+                    } catch (UnknownHostException ioe) {
+                        throw new JDOFatalUserException (
+                        msg.msg("EXC_UnknownHostException", uRL.getHost()), ioe); // NOI18N
+                    } catch (ConnectException ioe) {
+                        int port = uRL.getPort();
+                        if (port == -1) 
+                            port = FOStoreRemoteConnection.DEFAULT_PORT;
+                        throw new JDOFatalUserException(
+                            msg.msg("EXC_ConnectException", // NOI18N
+                                    uRL.getHost(), new Integer(port)),
+                            ioe); 
+                    } catch (IOException ioe) {
+                        throw new JDOFatalUserException (
+                        msg.msg("EXC_CannotCreateConnection", url), ioe); // NOI18N
+                    }
+                }
+            }
+        );
+    }
+         
+
+    /**
+     * Returns a connection to the pool
+     * @param connection Connection to be returned to the pool.
+     */
+    void closeConnection(FOStoreClientConnection connection) {
+        FOStoreConnectionId id = connection.getConnectionId();
+        Pool pool = (Pool) connectionMap.get(id);
+        try {
+            pool.put(connection);
+        } catch (InterruptedException ex) {
+            throw new JDOFatalInternalException(
+                msg.msg("ERR_CloseConnectionpoolPut"), ex); // NOI18N
+        }
+    }
+
+    /**
+     * Close the database.  This really means close all connections that
+     * have been opened.  Closing the last connection on a database actually 
+     * closes the database, whether local or remote.
+     */
+    public synchronized void closeDatabase() {
+        Object timer = Tester.startTime();
+        try {
+            for (Iterator hmi = connectionMap.values().iterator();
+                 hmi.hasNext();) {
+                
+                Pool dbPool = (Pool) hmi.next();
+                // we know that there are poolSize entries in each pool
+                for (int i = 0; i < poolSize; ++i) {
+                    FOStoreClientConnection focci =
+                        (FOStoreClientConnection) dbPool.get();
+                    focci.closeDatabase();
+                }
+            }
+            if (logger.isTraceEnabled()) {
+                Tester.printTime(timer, "Time to close database"); // NOI18N
+            }
+        } catch (FOStoreDatabaseException ex) {
+            throw new FOStoreFatalInternalException(
+                this.getClass(),
+                "close", msg.msg("ERR_CannotClose", url), ex); // NOI18N
+        } catch (IOException ex) {
+            throw new FOStoreFatalInternalException(
+                this.getClass(),
+                "close", msg.msg("ERR_CannotClose", url), ex); // NOI18N
+        } catch (InterruptedException ex) {
+            throw new FOStoreFatalInternalException(
+                this.getClass(),
+                "close", msg.msg("ERR_CannotClose", url), ex); // NOI18N
+        }
+        if (logger.isDebugEnabled()) {
+            logger.debug("FOCF: closed " + url); // NOI18N
+        }
+    }
+
+    /**
+    * Sets name of the driver for connections
+    * @param driverName driver name
+    */
+    public void setDriverName(String driverName){
+        assertConfigurable();
+        this.driverName = driverName;
+    }
+
+    /**
+    * Provides PersistenceManagerFactory for connections
+    * @return PMF
+    */
+    public FOStorePMF getPMF() {
+        return pmf;
+    }
+  
+    /**
+    * Sets PersistenceManagerFactory for connections
+    * @param pmf PersistenceManagerFactory
+    */
+    public void setPMF(FOStorePMF pmf){
+        assertConfigurable();
+        this.pmf = pmf;
+    }
+
+    /**
+    * Provides name of driver used for connections
+    * @return driver name
+    */
+    public String getDriverName() {
+        return driverName;
+    }
+  
+    /**
+    * Sets connection URL
+    * @param url connection URL
+    */
+    public void setURL(String url) {
+        assertConfigurable();
+        this.url = url;
+    }
+
+    /**
+    * Returns connection URL
+    * @return      connection URL
+    */
+    public String getURL() {
+        return url;
+    }
+  
+    /**
+    * Sets database user
+    * @param userName      database user
+    */
+    public void setUserName(String userName) {
+        assertConfigurable();
+        this.userName = userName;
+    }
+
+    /**
+    * Returns database user name
+    * @return      current database user name
+    */
+    public String getUserName() {
+        return userName;
+    }
+  
+    /**
+    * Sets database user password
+    * @param password      database user password
+    */
+    public void setPassword(String password) {
+        assertConfigurable();
+        this.password = password;
+    }
+  
+    /**
+    * Sets minimum number of connections in the connection pool
+    * @param minPool       minimum number of connections
+    */
+    public void setMinPool(int minPool) { 
+        assertConfigurable();
+    }
+
+    /**
+    * Returns minimum number of connections in the connection pool
+    * @return      connection minPool
+    */
+    public int getMinPool() {
+        return 1;
+    }
+  
+    /**
+    * Sets maximum number of connections in the connection pool
+    * @param maxPool       maximum number of connections
+    */
+    public void setMaxPool(int maxPool) {
+        assertConfigurable();
+    }
+
+    /**
+    * Returns maximum number of connections in the connection pool
+    * @return      connection maxPool
+    */
+    public int getMaxPool() {
+        return 1;
+    }
+  
+    /**
+    * Sets the amount of time, in milliseconds, between the connection
+    * manager's attempts to get a pooled connection.
+    * @param msInterval    the interval between attempts to get a database
+    *                      connection, in milliseconds.
+    *
+    */
+    public void setMsInterval(int msInterval) { }
+
+    /**
+    * Returns the amount of time, in milliseconds, between the connection
+    * manager's attempts to get a pooled connection.
+    * @return      the length of the interval between tries in milliseconds
+    */
+    public int getMsInterval() {
+        return 0;
+    }
+  
+    /**
+    * Sets the number of milliseconds to wait for an available connection
+    * from the connection pool before throwing an exception
+    * @param msWait        number in milliseconds
+    */
+    public void setMsWait(int msWait) { 
+        assertConfigurable();
+    }
+
+    /**
+    * Returns the number of milliseconds to wait for an available connection
+    * from the connection pool before throwing an exception
+    * @return      number in milliseconds
+    */
+    public int getMsWait() {
+        return 0;
+    }
+  
+    /**
+    * Sets the LogWriter to which messages should be sent
+    * @param logWriter            logWriter
+    */
+    public void setLogWriter(PrintWriter logWriter) {
+        this.logWriter = logWriter;
+    }
+
+    /**
+    * Returns the LogWriter to which messages should be sent
+    * @return      logWriter
+    */
+    public PrintWriter getLogWriter() {
+        return logWriter;
+    }
+ 
+    /**
+    * Sets the number of seconds to wait for a new connection to be
+    * established to the data source
+    * @param loginTimeout           wait time in seconds
+    */
+    public void setLoginTimeout(int loginTimeout) {
+        assertConfigurable();
+        this.loginTimeout = loginTimeout;
+    }
+
+    /**
+    * Returns the number of seconds to wait for a new connection to be
+    * established to the data source
+    * @return      wait time in seconds
+    */
+    public int getLoginTimeout() {
+        return loginTimeout;
+    }
+
+    /**
+    * Sets whether to create the database.
+    * @param create whether to create the database.
+    */
+    public void setCreate(boolean create) {
+        assertConfigurable();
+        this.create = create;
+    }
+
+    /**
+    * Sets whether to create the database.
+    * @param create whether to create the database.
+    */
+    public void setCreate(String create) {
+        assertConfigurable();
+        this.create = Boolean.valueOf (create).booleanValue();
+    }
+
+    /**
+    * Returns whether to create the database.
+    * @return whether to create the database
+    */
+    public boolean getCreate() {
+        return create;
+    }
+
+    //
+    // Support for JNDI: we want to save/restore a FOStoreConnectionFactory
+    // via JNDI, and have the stored representation be via properties.
+    //
+
+    /** CFAccessor implementation instances allow copying values to/from a
+     * FOStoreConnectionFactory
+     * and a Properties.  They do the proper type translation too.
+     */
+    interface CFAccessor extends Accessor {
+        /** @return String form of a value in a FOStoreConnectionFactory.
+         */
+        public String get(FOStoreConnectionFactory focf);
+
+        /** @return String form of a value in a FOStoreConnectionFactory if
+         * is not a default value.
+         */
+        public String getNonDefault(FOStoreConnectionFactory focf);
+
+        /** @param s String form of a value in a FOStoreConnectionFactory.
+         */
+        public void set(FOStoreConnectionFactory focf, String s);
+    }
+
+    // Initialize the property accessors map.
+    protected static void initPropsAccessors() {
+        synchronized (CFpropsAccessors) {
+            if (CFpropsAccessors.size() == 0) {
+
+                CFpropsAccessors.put(
+                    "org.apache.jdo.FOStoreConnectionFactory.option.URL", // NOI18N
+                    new CFAccessor() {
+                    public String get(FOStoreConnectionFactory focf) { return focf.getURL(); }
+                    public String getNonDefault(FOStoreConnectionFactory focf) { return focf.getURL(); }
+                    public String getDefault() {return null;}
+                    public void set(FOStoreConnectionFactory focf, String s) { focf.setURL(s); }
+                });
+                CFpropsAccessors.put(
+                    "org.apache.jdo.FOStoreConnectionFactory.option.UserName", // NOI18N
+                    new CFAccessor() {
+                    public String get(FOStoreConnectionFactory focf) { return focf.getUserName(); }
+                    public String getNonDefault(FOStoreConnectionFactory focf) { return focf.getUserName(); }
+                    public String getDefault() {return null;}
+                    public void set(FOStoreConnectionFactory focf, String s) { focf.setUserName(s); }
+                });
+                CFpropsAccessors.put(
+                    "org.apache.jdo.FOStoreConnectionFactory.option.Password", // NOI18N
+                    new CFAccessor() {
+                    public String get(FOStoreConnectionFactory focf) { return FOStorePMF.doEncrypt(focf.password); }
+                    public String getNonDefault(FOStoreConnectionFactory focf) { return FOStorePMF.doEncrypt(focf.password); }
+                    public String getDefault() {return null;}
+                    public void set(FOStoreConnectionFactory focf, String s) { focf.setPassword(FOStorePMF.doDecrypt(s)); }
+                });
+                CFpropsAccessors.put(
+                    "org.apache.jdo.FOStoreConnectionFactory.option.DriverName", // NOI18N
+                    new CFAccessor() {
+                    public String get(FOStoreConnectionFactory focf) { return focf.getDriverName(); }
+                    public String getNonDefault(FOStoreConnectionFactory focf) { return focf.getDriverName(); }
+                    public String getDefault() {return null;}
+                    public void set(FOStoreConnectionFactory focf, String s) { focf.setDriverName(s); }
+                });
+                CFpropsAccessors.put(
+                    "org.apache.jdo.FOStoreConnectionFactory.option.LoginTimeout", // NOI18N
+                    new CFAccessor() {
+                    public String get(FOStoreConnectionFactory focf) { return focf.getDriverName(); }
+                    public String getNonDefault(FOStoreConnectionFactory focf) { return focf.getDriverName(); }
+                    public String getDefault() {return null;}
+                    public void set(FOStoreConnectionFactory focf, String s) { focf.setDriverName(s); }
+                });
+                CFpropsAccessors.put(
+                    "javax.jdo.FOStoreConnectionFactory.option.MinPool", // NOI18N
+                    new CFAccessor() {
+                    public String get(FOStoreConnectionFactory focf) { return Integer.toString(focf.getMinPool()); }
+                    public String getNonDefault(FOStoreConnectionFactory focf) { return (focf.getMinPool()==1)?null:Integer.toString(focf.getMinPool()); }
+                    public String getDefault() { return "1"; } // NOI18N
+                    public void set(FOStoreConnectionFactory focf, String s) { focf.setMinPool(toInt(s)); }
+                });
+                CFpropsAccessors.put(
+                    "javax.jdo.FOStoreConnectionFactory.option.MaxPool", // NOI18N
+                    new CFAccessor() {
+                    public String get(FOStoreConnectionFactory focf) { return Integer.toString(focf.getMaxPool()); }
+                    public String getNonDefault(FOStoreConnectionFactory focf) { return (focf.getMaxPool()==1)?null:Integer.toString(focf.getMaxPool()); }
+                    public String getDefault() { return "1"; } // NOI18N
+                    public void set(FOStoreConnectionFactory focf, String s) { focf.setMaxPool(toInt(s)); }
+                });
+                CFpropsAccessors.put(
+                    "javax.jdo.FOStoreConnectionFactory.option.MsWait", // NOI18N
+                    new CFAccessor() {
+                    public String get(FOStoreConnectionFactory focf) { return Integer.toString(focf.getMsWait()); }
+                    public String getNonDefault(FOStoreConnectionFactory focf) { return (focf.getMsWait()==0)?null:Integer.toString(focf.getMsWait()); }
+                    public String getDefault() { return "0"; } // NOI18N
+                    public void set(FOStoreConnectionFactory focf, String s) { focf.setMsWait(toInt(s)); }
+                });
+                CFpropsAccessors.put(
+                    "javax.jdo.FOStoreConnectionFactory.option.Create", // NOI18N
+                    new CFAccessor() {
+                    public String get(FOStoreConnectionFactory focf) { return new Boolean(focf.getCreate()).toString(); }
+                    public String getNonDefault(FOStoreConnectionFactory focf) { return (!focf.getCreate())?null:"true"; } // NOI18N
+                    public String getDefault() { return "false"; } // NOI18N
+                    public void set(FOStoreConnectionFactory focf, String s) { focf.setCreate(Boolean.valueOf(s).booleanValue()); }
+                });
+            }
+        }
+    }
+
+    /**
+     * It should *never* be the case that our translation process encounters
+     * a NumberFormatException.  If so, tell the user in the JDO-approved
+     * manner.
+     */ 
+    private static int toInt(String s) {
+        int rc = 0;
+        try {
+            rc = new Integer(s).intValue();
+        } catch (NumberFormatException ex) {
+            throw new JDOFatalInternalException(
+                msg.msg("ERR_Badformat")); // NOI18N
+        }
+        return rc;
+    }
+
+    /**
+     * Sets properties as per the property values in the connection factory.
+     * For each CFAccessor in the given HashMap, gets the corresponding value
+     * from the FOStoreConnectionFactory and puts it in the given 
+     * Properties object.
+     */
+    void setProperties(Properties p) {
+        Set s = CFpropsAccessors.entrySet();
+        for (Iterator i = s.iterator(); i.hasNext();) {
+            Map.Entry e = (Map.Entry)i.next();
+            String key = (String)e.getKey();
+            CFAccessor a = (CFAccessor)e.getValue();
+            String value = (String)a.getNonDefault(this);
+            if (null != value) {
+                p.put(key, value);
+            }
+        }
+    }
+
+    /**
+     * Configures a FOStoreConnectionFactory from the given Properties.
+     * For each Accessor in the given HashMap, gets the corresponding value
+     * from the Properties and sets that value in the PMF.
+     * This is public so that a test program can create a
+     * FOSToreConnectionFactory, and configure it from a Properties object.
+     */
+    public void setFromProperties(Properties p) {
+        Set s = CFpropsAccessors.entrySet();
+        for (Iterator i = s.iterator(); i.hasNext();) {
+            Map.Entry e = (Map.Entry)i.next();
+            String key = (String)e.getKey();
+            String value = p.getProperty(key);
+            if (null != value) {
+                CFAccessor a = (CFAccessor)e.getValue();
+                if (logger.isDebugEnabled()) {
+                    logger.debug("FOStoreConnectionFactory setting property: " + key + " to: " + value); // NOI18N
+                }
+                a.set(this, value);
+            }
+        }
+    }
+    
+    /**
+     * Returns true if this connection factory has been configured with a URL.
+     */
+    public boolean isConfigured() {
+        if (logger.isDebugEnabled()) 
+            logger.debug("FOStoreConnectionFactory url is: " + url); // NOI18N
+        return (url != null);
+    }
+
+    public String toString() {
+        return "" + // NOI18N
+            "FOCF.url: " + url + "\n" + // NOI18N
+            "FOCF.userName: " + userName + "\n" + // NOI18N
+            "FOCF.password: " + password + "\n" + // NOI18N
+            "FOCF.driverName: " + driverName + "\n" + // NOI18N
+            "FOCF.loginTimeout: " + loginTimeout; // NOI18N
+   }        
+}

Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreConnectionId.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreConnectionId.java?view=auto&rev=158176
==============================================================================
--- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreConnectionId.java (added)
+++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreConnectionId.java Fri Mar 18 17:02:29 2005
@@ -0,0 +1,180 @@
+/*
+ * 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.
+ */
+
+/*
+ * FOStoreConnectionId.java
+ *
+ * Created on June 15, 2001, 1:30 PM
+ */
+
+package org.apache.jdo.impl.fostore;
+
+/**
+ * Represents the information required to connect to a database.
+ * @author  Craig Russell
+ * @version 1.0
+ */
+class FOStoreConnectionId {
+    
+    /** The URL of this connection.  Must not be null.
+     */    
+    private String url;
+    
+    /** The user id of this connection.  May be null.
+     */    
+    private String user;
+    
+    /** The password of this connection.  May be null.
+     */    
+    private String password;
+    
+    /** The flag telling whether to create.
+     */
+    private boolean create;
+
+    /** Creates new FOStoreConnectionId.
+     * @param url the URL of the connection.
+     * @param user the user id of the connection.
+     * @param password the password of the connection.
+     * @param create the flag whether to create the database.
+     */
+    public FOStoreConnectionId(String url, String user, String password, boolean create) {
+        if (url == null) {
+            throw new NullPointerException();
+        }
+        this.url = url;
+        this.user = user;
+        this.password = password;
+        this.create = create;
+    }
+    
+
+    /** Creates new FOStoreConnectionId.
+     * @param url the URL of the connection.
+     * @param user the user id of the connection.
+     * @param password the password of the connection.
+     */
+    public FOStoreConnectionId(String url, String user, String password) {
+        if (url == null) {
+            throw new NullPointerException();
+        }
+        this.url = url;
+        this.user = user;
+        this.password = password;
+        this.create = false;
+    }
+    
+    public void setUrl (String url) {
+        if (url == null) {
+            throw new NullPointerException();
+        }
+        this.url = url;
+    }
+    
+    public String getUrl () {
+        return url;
+    }
+    
+    public void setUser (String user) {
+        this.user = user;
+    }
+    
+    public String getUser() {
+        return user;
+    }
+    
+    public void setPassword (String password) {
+        this.password = password;
+    }
+    
+    public String getPassword () {
+        return password;
+    }
+    
+    public void setCreate (boolean create) {
+        this.create = create;
+    }
+    
+    public boolean getCreate() {
+        return create;
+    }
+
+    /** Combine the hashCodes of URL, user, and password.
+     * @return the combined hashCode.
+     * Note that the create flag is not part of the hashCode.
+     */    
+    public int hashCode () {
+        int urlHashCode = url.hashCode();
+        int userHashCode = user==null?0:user.hashCode();
+        int passwordHashCode = password==null?0:password.hashCode();
+        return urlHashCode + userHashCode + passwordHashCode;
+    }
+    
+    /** Returns true if this represents the same URL,
+     * user, and password as the other.
+     * @param other another connection id.
+     * @return true if this represents the same URL,
+     * user, and password as the other.
+     * Note that the create flag is not part of the identity.
+     */    
+    public boolean equals (Object other) {
+        if (this.getClass() != other.getClass()) return false;
+        FOStoreConnectionId foci = (FOStoreConnectionId) other;
+        return this.url.equals(foci.url) 
+            & ((this.user!=null&foci.user!=null)?this.user.equals(foci.user):this.user==foci.user)
+            & ((this.password!=null&foci.password!=null)?this.password.equals(foci.password):this.password==foci.password);
+    }
+    
+    // XXX this 'main' really belongs in a test class...
+    public static void main (String argv[]) {
+        FOStoreConnectionId id0 = new FOStoreConnectionId("url", null, null); // NOI18N
+        FOStoreConnectionId id1 = new FOStoreConnectionId("url", "1", null); // NOI18N
+        FOStoreConnectionId id2 = new FOStoreConnectionId("url", null, "2"); // NOI18N
+        FOStoreConnectionId id3 = new FOStoreConnectionId("url", "1", "2"); // NOI18N
+        FOStoreConnectionId id4 = new FOStoreConnectionId("url2", "1", "2"); // NOI18N
+        FOStoreConnectionId id5 = new FOStoreConnectionId("url2", "1", "2", true); // NOI18N
+        try {
+            FOStoreConnectionId id = new FOStoreConnectionId (null, null, null);
+            System.out.println ("Failure."); // NOI18N
+            return;
+        } catch (NullPointerException npe) {
+            // good catch
+        } catch (Throwable t) {
+            System.out.println ("Failure."); // NOI18N
+            return;
+        }
+        if    (!id0.equals(id1)
+            & (!id0.equals(id2))
+            & (!id0.equals(id3))
+            & (!id0.equals(id4))
+            & (!id1.equals(id0))
+            & (!id2.equals(id0))
+            & (!id3.equals(id0))
+            & (!id4.equals(id0))
+             & (id0.equals(id0))
+             & (id1.equals(id1))
+             & (id2.equals(id2))
+             & (id3.equals(id3))
+             & (id4.equals(id4))
+             & (id4.equals(id5))
+                                ) {
+            System.out.println ("Success."); // NOI18N
+        } else {
+            System.out.println ("Failure."); // NOI18N
+        }
+    }
+
+}

Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreConnector.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreConnector.java?view=auto&rev=158176
==============================================================================
--- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreConnector.java (added)
+++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreConnector.java Fri Mar 18 17:02:29 2005
@@ -0,0 +1,277 @@
+/*
+ * 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.IOException;
+
+import javax.jdo.JDOException;
+import javax.jdo.JDODataStoreException;
+import javax.jdo.JDOFatalInternalException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.apache.jdo.store.Connector;
+import org.apache.jdo.util.I18NHelper;
+
+/**
+* FOStoreConnector represents a connection to the FOStoreDatabase.
+*
+* @author Dave Bristor
+*/
+class FOStoreConnector implements Connector {
+    /** @see org.apache.jdo.store.Connector#setRollbackOnly */
+    private boolean rollbackOnly = false;
+
+    /** 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
+    
+    /**
+    * Message in which this Connector buffers requests for the store.
+    */
+    private final Message message;
+
+    /**
+    * Datasource to which this Connector writes its Message.
+    */
+    private final FOStorePMF pmf;
+
+    /**
+    * Connection for interacting with store.
+    */
+    FOStoreClientConnection connection = null;
+    
+    /**
+    * True if we can release this connection after flushing.  By default we
+    * can; affected by transactions beginning and ending and their types.
+    */
+    private boolean okToReleaseConnection = true;
+
+    /** True if flush is in progress. */
+    private boolean busy = false;
+    
+    FOStoreConnector(FOStorePMF pmf) {
+        this.pmf = pmf;
+        this.message = new Message(this);
+    }
+
+    //
+    // Implement Connector
+    //
+
+    /**
+     * @see org.apache.jdo.store.Connector#begin
+     */
+    public void begin(boolean optimistic) {
+        assertNotRollbackOnly();
+        
+        // If transaction is optimistic, then we can release the connection as
+        // soon as data is flushed.  If it's datastore, then we can't release
+        // the connection until after commit/rollback.
+        this.okToReleaseConnection = optimistic;
+        
+        if (logger.isDebugEnabled()) {
+            logger.debug(
+                "FOConnector.begin: okToReleaseConnection=" +  // NOI18N
+                okToReleaseConnection);
+        }
+
+        try {
+            RequestFactory rf = pmf.getRequestFactory();
+            BeginTxRequest request =
+                rf.getBeginTxRequest(message, pmf, optimistic);
+            request.doRequest();
+        } catch (IOException ex) {
+            throw new FOStoreFatalIOException(
+                getClass(), "update", ex); // NOI18N
+        } catch (JDOException ex) {
+            throw ex;
+        } catch (Exception ex) {
+            throw new FOStoreFatalInternalException(
+                getClass(), "update", ex); // NOI18N
+        }
+    }
+
+    /**
+     * @see org.apache.jdo.store.Connector#beforeCompletion
+     */
+    public void beforeCompletion() {
+        assertNotRollbackOnly();
+        
+        // Nothing to do.
+    }
+
+    /**
+     * Get a connection, process the message by using that connection to
+     * interact with the database, read back the reply, release the
+     connection.
+     * @see org.apache.jdo.store.Connector#flush
+     */
+    public void flush() {
+        assertNotRollbackOnly();
+        assertNotBusy("flush"); // NOI18N
+        busy = true;
+
+        try {
+        
+            if (logger.isDebugEnabled()) {
+                logger.debug(
+                  "FOConnector.flush: " + // NOI18N
+                  "okToReleaseConnection=" + okToReleaseConnection + // NOI18N
+                  ", connection=" + connection); // NOI18N
+            }
+
+            if (message.hasRequests()) {
+                if (logger.isTraceEnabled()) message.dump();
+
+                if (connection == null) {
+                    FOStoreConnectionFactory cf =
+                        (FOStoreConnectionFactory)pmf.getConnectionFactory();
+                    connection = (FOStoreClientConnection)cf.getConnection();
+                }
+
+                // Now send the message and process it in the store
+                try {
+                    message.processInStore(connection, okToReleaseConnection);
+                } finally {
+                    if (okToReleaseConnection) {
+                        connection = null;
+                    }
+                }
+            }
+        } finally {
+            busy = false;
+        }
+    }
+
+    /**
+    * Add a CommitRequest to the connector's message, and send it to the
+    * store.  Then close the connection.
+    * @see org.apache.jdo.store.Connector#commit
+    */
+    public synchronized void commit() {
+        assertNotRollbackOnly();
+        assertNotBusy("commit"); // NOI18N
+        
+        try {
+            if (logger.isDebugEnabled()) {
+                logger.debug("FOConnector.commit"); // NOI18N
+            }
+
+            RequestFactory rf = pmf.getRequestFactory();
+            CommitRequest request = rf.getCommitRequest(message, pmf);
+
+            request.doRequest();
+        } catch (IOException ex) {
+            throw new FOStoreFatalIOException(
+                this.getClass(), "commit", ex); // NOI18N
+        } catch (JDOException ex) {
+            throw ex;
+        } catch (Exception ex) {
+            throw new FOStoreFatalInternalException(
+                getClass(), "commit", ex); // NOI18N
+        } finally {
+            // Now that we've commited, we can release the connection.
+            okToReleaseConnection = true;
+            flush();
+        }
+    }
+
+    /**
+     * If rollbackOnly is set, then the store has already done a
+     * rollback, so we don't do one now (but neither do we throw an
+     * exception, as do other methds).
+     * @see org.apache.jdo.store.Connector#rollback
+     * @see org.apache.jdo.impl.fostore.ReplyHandler#processReplies
+     */
+    public synchronized void rollback() {
+        assertNotBusy("rollback"); // NOI18N
+        if (logger.isDebugEnabled()) {
+            logger.debug(
+                "FOConnector.rollback, RBO=" + rollbackOnly); // NOI18N
+        }
+        
+        if (! rollbackOnly) {
+            try {
+                RequestFactory rf = pmf.getRequestFactory();
+                RollbackRequest request = rf.getRollbackRequest(message, pmf);
+                
+                request.doRequest();
+            } catch (IOException ex) {
+                throw new FOStoreFatalIOException(
+                    this.getClass(), "rollback", ex); // NOI18N
+            } catch (JDOException ex) {
+                throw ex;
+            } catch (Exception ex) {
+                throw new FOStoreFatalInternalException(
+                    getClass(), "rollback", ex); // NOI18N
+            } finally {
+                // Now that we've rolled back, we can release the connection.
+                okToReleaseConnection = true;
+                flush();
+            }
+        }
+    }
+
+    /**
+     * @see org.apache.jdo.store.Connector#setRollbackOnly
+     */
+    public void setRollbackOnly() {
+        rollbackOnly = true;
+    }
+
+    /**
+     * @see org.apache.jdo.store.Connector#getRollbackOnly
+     */
+    public boolean getRollbackOnly() {
+        return rollbackOnly;
+    }
+
+    //
+    // Implementation
+    //
+
+    /**
+     * Provides the Message which this this connector uses to send data to the
+     * store.
+     */
+    Message getMessage() {
+        assertNotRollbackOnly();
+        assertNotBusy("getMessage"); // NOI18N
+        
+        return message;
+    }
+
+    private void assertNotRollbackOnly() {
+        if (rollbackOnly) {
+            throw new JDODataStoreException(
+                msg.msg("EXC_RollbackOnly")); // NOI18N
+        }
+    }
+
+    private void assertNotBusy(String methodName) {
+        if (busy) {
+            throw new FOStoreFatalInternalException(
+              getClass(), methodName,
+                msg.msg("EXC_Busy")); // NOI18N
+        }
+    }
+}

Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreDatabase.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreDatabase.java?view=auto&rev=158176
==============================================================================
--- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreDatabase.java (added)
+++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreDatabase.java Fri Mar 18 17:02:29 2005
@@ -0,0 +1,574 @@
+/*
+ * 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.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.File;
+import java.security.AccessController;
+import java.security.PrivilegedExceptionAction;
+import java.security.PrivilegedActionException;
+import java.util.Set;
+import java.util.HashMap;
+
+import javax.jdo.JDOFatalUserException;
+import javax.jdo.JDOFatalException;
+import javax.jdo.JDOFatalDataStoreException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.apache.jdo.util.I18NHelper;
+import org.apache.jdo.util.Pool;
+import org.netbeans.mdr.persistence.Storage;
+import org.netbeans.mdr.persistence.SinglevaluedIndex;
+import org.netbeans.mdr.persistence.StorageBadRequestException;
+import org.netbeans.mdr.persistence.StorageException;
+import org.netbeans.mdr.persistence.Streamable;
+
+/**
+* File/Object Store Database, using an underlying Btree implementation.
+*
+* @author Dave Bristor
+*/
+class FOStoreDatabase {
+    
+    /** We manage a map of pools of databases by database name.
+     */
+    private static final HashMap databaseMap = new HashMap();
+    
+    private static final int poolSize = 1;
+    
+    // We delegate all calls to this storage.  Not final, because for
+    // rollback's sake we have to close and then make a new storage.
+    private FOStoreBtreeStorage storage;
+
+    // Map from provisional IDs to real, datastore-created, durable IDs.
+    //
+    // XXX TBD Remote: Provisional CLID's are per client (PMF).
+    // That is because each client will independently generate its
+    // own set of provisional ID's.  One way to manage this might be for
+    // each client to send a "hello" message when it first connects, with
+    // something like it's IP address and process id.  Future communications
+    // from that same client will contain that same info.  A "goodbye" message
+    // would be nice, too, so that the store can remove any tables that will
+    // not ever be used again.
+    private final HashMap provisionalCLIDs = new HashMap();
+
+    // Same as above, but for OIDs.
+    private final HashMap provisionalOIDs = new HashMap();
+    
+    /** Count the number of connections open on this database.  When the last 
+     * connection closes, then really close the database.
+     */
+    private int openConnections = 0;
+    
+    private DBInfo dbInfo = null;
+    /** Pool for this database.
+     */
+    private Pool pool = null;
+
+    /** 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
+    
+    /** Find an open database of the given name.  If it is not already open,
+     * open it and put it into the pool.
+     */
+    public synchronized static FOStoreDatabase getDatabase (String dbname, 
+                                                            boolean create) 
+            throws InterruptedException, FOStoreDatabaseException {
+        Pool pool = (Pool) databaseMap.get(dbname);
+        FOStoreDatabase db = null;
+        if (pool == null) {
+            try {
+                db = new FOStoreDatabase (dbname, create);
+            } catch (FOStoreDatabaseException fode) {
+                if (logger.isDebugEnabled()) {
+                    logger.debug(
+                        "FODB:getDatabase exception for new database " + // NOI18N
+                        dbname + " create: " + create); // NOI18N
+                }
+                throw (fode);
+            }
+            pool = new Pool (poolSize);
+            databaseMap.put (dbname, pool);
+            pool.put (db);
+            db.setPool(pool);
+        }
+        if (logger.isDebugEnabled()) {
+            logger.debug("FODB:getDatabase found pool for database " + dbname); // NOI18N
+        }
+        db = (FOStoreDatabase) pool.get();
+        return db;
+    }
+    
+    /** Release the database for other connections to use.
+     */
+    public synchronized static void releaseDatabase (FOStoreDatabase db)
+        throws InterruptedException {
+
+        db.pool.put (db);
+    }
+        
+    /**
+    * Create an FODatabase and create/open the files.
+    * @param name name of database, which is used to name the files
+    * @param isNew true if the database is being created
+    */
+     FOStoreDatabase(String name, boolean isNew)
+        throws FOStoreDatabaseException {
+            // first verify that the directory exists
+            // if not, there is no way to continue
+            // Note, the filename might include a mixture of \ and / as
+            // path separator, make them all / for the lookup
+            int slashIndex = name.replace('\\', '/').lastIndexOf('/');
+            if (slashIndex != -1) { // at least one / in pathname
+                String dirName = name.substring(0, slashIndex);
+                File dir = new File(dirName); // NOI18N
+                if (!existsFile(dir)) {
+                    throw new JDOFatalDataStoreException (
+                        msg.msg("ERR_DirectoryDoesNotExist", name)); // NOI18N
+                }
+            }
+            // XXX the DBInfo is not a singleton; change this code
+            // and DBInfo to support multiple Databases in one VM.
+        if (isNew) {
+            // We must remove a database if one does exist.  This means delete
+            // both the .btd and .btx files.
+            String extensions[] = {"btd", "btx"}; // NOI18N
+            boolean found = false;
+            for (int i = 0; i < extensions.length; i++) {
+                File f = new File(name + "." + extensions[i]); // NOI18N
+                if (existsFile(f)) {
+                    if (! found) {
+                        if (logger.isDebugEnabled()) {
+                            logger.debug("FODB: Deleting existing database " +
+                                           name); // NOI18N
+                        }
+                        found = true;
+                    }
+                    deleteFile(f);
+                }
+            }
+            storage = createBtreeStorage(name, true);
+            dbInfo = new DBInfo(this);
+            dbInfo.store();
+            commitChanges();
+            if (logger.isDebugEnabled()) {
+                logger.debug("FODB: Created database " + name); // NOI18N
+            }
+        } else {
+            storage = createBtreeStorage(name, false);
+            dbInfo = DBInfo.get(this);
+            if (logger.isDebugEnabled()) {
+                logger.debug(
+                    "FODB: Opened existing database " + name); // NOI18N
+            }
+        }
+    }
+
+    /** Verify that this user is authorized to use this database.
+     */
+    public void verifyUserPassword (String user, long timestamp, byte[] secret) {
+        // XXX look up Authentication objects and verify this user is authorized.
+        addConnection();
+    }
+    
+    /** Get the DBInfo for this database.
+     */
+    public DBInfo getDBInfo() {
+        return dbInfo;
+    }
+    
+    /** Associates the specified value with the specified key in this index.
+    * @return true if there was an item in this index that was associated
+    * with the key prior to this call
+    * @param key
+    * @param value
+    * @throws FOStoreDatabaseException
+    */
+    public boolean put(OID key, Object value) throws FOStoreDatabaseException {
+        try {
+            Object keyValue = key.keyValue(storage);
+// Uncomment the next lines to simulate a fatal error during login.
+//            if (null != keyValue)
+//                throw new NullPointerException("fodb: NPE on purpose"); // YYY
+            return storage.getPrimaryIndex().put(keyValue, value);
+        } catch (StorageException ex) {
+            throw new FOStoreDatabaseException(ex);
+        }
+    }
+
+    /** Replaces the original value associated with the specified key in this
+    * index with new value. If no value was associated with this key prior
+    * to this call StorageBadRequestException is thrown.
+    * @param key
+    * @param value
+    * @throws FOStoreDatabaseException
+    */
+    public void replace(OID key, Object value)
+        throws FOStoreDatabaseException {
+
+        try {
+            Object keyValue = key.keyValue(storage);
+            storage.getPrimaryIndex().replace(keyValue, value);
+        } catch (StorageException ex) {
+            throw new FOStoreDatabaseException(ex);
+        }
+    }
+        
+    /** Returns the value to which this index maps the specified key.
+    * StorageBadRequestException is thrown if there is no value for the key.
+    * @return value associated with specified key
+    * @param key
+    * @throws FOStoreDatabaseException
+    */
+    public Object get(OID key)
+        throws FOStoreDatabaseException {
+
+        try {
+            Object keyValue = key.keyValue(storage);
+            return storage.getPrimaryIndex().get(keyValue);
+        } catch (StorageException ex) {
+            throw new FOStoreDatabaseException(ex);
+        }
+    }
+
+    /** Returns the value to which this index maps the specified key
+    * or null if there is no value for this key.
+    * @return value associated with specified key or null
+    * @param key
+    * @throws FOStoreDatabaseException
+    */
+    public Object getIfExists (OID key) throws FOStoreDatabaseException {
+        try {
+            Object keyValue = key.keyValue(storage);
+            return storage.getPrimaryIndex().getIfExists(keyValue);
+        } catch (StorageException ex) {
+            throw new FOStoreDatabaseException(ex);
+        }
+    }
+    
+    /** Returns the unique name of the index in the Storage.
+    * @return The name of this index.
+    */
+    public String getName()  {
+        return storage.getName();
+    }
+
+    /** Returns a set view of the keys contained in this index.
+    * Returned set is read only and may not be modified.
+    * @return keys contained in this index
+    * @throws FOStoreDatabaseException
+    */
+    public Set keySet() throws FOStoreDatabaseException {
+        try {
+            return storage.getPrimaryIndex().keySet();
+        } catch (StorageException ex) {
+            throw new FOStoreDatabaseException(ex);
+        }
+    }
+
+    /** Adds the specified value to values associated in this index with the
+    * specified key. If the index puts limit on number of values associated
+    * with one key and adding value would break this limit, it thorows
+    * StorageBadRequestException.
+    * @param key
+    * @param value
+    * @throws FOStoreDatabaseException
+    */
+    public void add(OID key, Object value) throws FOStoreDatabaseException {
+        try {
+            Object keyValue = key.keyValue(storage);
+            storage.getPrimaryIndex().add(keyValue, value);
+        } catch (StorageException ex) {
+            throw new FOStoreDatabaseException(ex);
+        }
+    }
+    
+    /** Removes all values assosiated in the index with specified key.
+    * @return true if this index changed as a result of this call
+    * @param key
+    * @throws FOStoreDatabaseException
+    */
+    public boolean remove (OID key) throws FOStoreDatabaseException {
+        try {
+            Object keyValue = key.keyValue(storage);
+            return storage.getPrimaryIndex().remove(keyValue);
+        } catch (StorageException ex) {
+            throw new FOStoreDatabaseException(ex);
+        }
+    }
+
+    public void commitChanges() throws FOStoreDatabaseException {
+        if (logger.isDebugEnabled()) logger.debug("FODB.commitChanges"); // NOI18N
+
+        // Need to have privileges to perform this operation.
+        final FOStoreBtreeStorage storage1 = storage;
+        try {
+            AccessController.doPrivileged (
+                new PrivilegedExceptionAction () {
+                    public Object run () throws StorageException {
+                        storage1.commitChanges();
+                        return null;
+                    }
+                }
+            );
+        } catch (PrivilegedActionException ex) {
+            throw new FOStoreDatabaseException(
+                (StorageException)ex.getException());
+        }
+
+    }
+
+    /** Increment the openConnections to allow proper close when the last
+     * connection closes the database.
+     */
+    public synchronized void addConnection() {
+        openConnections++;
+    }
+    
+    /** Decrement the open connections counter and close the database when
+     * it reaches zero.
+     */
+    public synchronized void close() throws FOStoreDatabaseException {
+        if (--openConnections > 0) {
+            if (logger.isDebugEnabled()) {
+                logger.debug("FODB.close: " + getName() +  // NOI18N
+                               " count still " + openConnections); // NOI18N
+            }
+            try {
+                releaseDatabase(this);
+            } catch (InterruptedException ex) {
+                // ignore
+            }
+            return;
+        }
+        // count has reached zero.  Now really close the database.
+        if (logger.isDebugEnabled()) {
+            logger.debug(
+                "FODB.close: count reached zero." + getName()); // NOI18N
+        }
+
+        closeBtreeStorage(storage);
+        databaseMap.remove(getName());
+        pool = null;
+    }
+    
+    public static synchronized void closeDatabase (String dbname)
+        throws FOStoreDatabaseException, InterruptedException {
+
+        Pool pool = (Pool) databaseMap.get(dbname);
+        if (pool == null) {
+            throw new JDOFatalDataStoreException (
+                msg.msg("ERR_CloseDatabase", dbname)); // NOI18N
+        }
+        FOStoreDatabase fodb = (FOStoreDatabase) pool.get();
+        fodb.close();
+    }
+
+    public void rollbackChanges() throws FOStoreDatabaseException {
+        if (logger.isDebugEnabled()) logger.debug("FODB.rollbackChanges"); // NOI18N
+
+        // The btree doesn't *really* rollback.  But closing it and
+        // getting a new one works fine.
+        final String name = storage.getName();
+        closeBtreeStorage(storage);
+        
+        storage = createBtreeStorage(name, false);
+        dbInfo = DBInfo.get(this);
+    }
+
+    static Block createBlock(FOStoreInput in, int length) {
+        return new Block(in, length);
+    }
+    
+    /**
+    * Establishes a mapping in this database from provisional to real
+    * CLIDs.  The mapping lasts as long as the server is running, that is, it
+    * is not durable.
+    * @param pCLID A provisional CLID.
+    * @param rCLID The non-provisional, datastore CLID corresponding to
+    * provCLID.
+    * @exception JDOFatalException Thrown if the given CLID is not provisional.
+    */
+    // If you change this code, please see also method of same name in FOStorePMF.
+    public synchronized void mapProvisionalCLIDToReal(
+        CLID pCLID, CLID rCLID) {
+
+        if (! pCLID.isProvisional()) {
+            throw new JDOFatalException(msg.msg("ERR_CLIDNotProv", pCLID)); // NOI18N
+        }
+        if (null == provisionalCLIDs.get(pCLID)) {
+            provisionalCLIDs.put(pCLID, rCLID);
+        }
+        if (logger.isDebugEnabled()) {
+            logger.debug(
+                "FODB.mapProvCLIDToReal: " + pCLID + " -> " + rCLID); // NOI18N
+        }
+    }
+
+    /**
+    * Provides a datastore CLID corresponding to the given provisional CLID.
+    * @param provCLID A provisional CLID for which there 
+    * @return A non-provisional, datastore CLID corresponding to provCLID, or
+    * null if the given provCLID is not mapped to a datastore CLID.
+    * @exception JDOFatalException Thrown if the given CLID is not provisional.
+    */
+    // If you change this code, see method of same name in FOStorePMF.
+    public CLID getRealCLIDFromProvisional(CLID provCLID) {
+        if (! provCLID.isProvisional()) {
+            throw new JDOFatalException(msg.msg("ERR_CLIDNotProv", provCLID)); // NOI18N
+        }
+        return (CLID)provisionalCLIDs.get(provCLID);
+    }
+
+    /**
+    * Establishes a mapping in this database from provisional to real
+    * OIDs.  The mapping lasts as long as the server is running, that is, it
+    * is not durable.
+    * @param pOID A provisional OID.
+    * @param rOID The non-provisional, datastore OID corresponding to
+    * pOID.
+    * @exception JDOFatalException Thrown if the given OID is not provisional.
+    */
+    // If you change this code, please see also method of same name in FOStorePMF.
+    synchronized void mapProvisionalOIDToReal(
+        OID pOID, OID rOID) {
+
+        if (! pOID.isProvisional()) {
+            throw new JDOFatalException(msg.msg("ERR_OIDNotProv", pOID)); // NOI18N
+        }
+        if (null == provisionalOIDs.get(pOID)) {
+            provisionalOIDs.put(pOID, rOID);
+        }
+    }
+
+    /**
+    * Provides a datastore OID corresponding to the given provisional OID.
+    * @param pOID A provisional OID for which there 
+    * @return A non-provisional, datastore OID corresponding to pOID or null
+    * if the given pOID is not mapped to a datastore OID.
+    * @exception JDOFatalException Thrown if the given OID is not provisional.
+    */
+    // If you change this code, see method of same name in FOStorePMF.
+    OID getRealOIDFromProvisional(OID pOID) {
+        if (! pOID.isProvisional()) {
+            throw new JDOFatalException(msg.msg("ERR_OIDNotProv", pOID)); // NOI18N
+        }
+        return (OID)provisionalOIDs.get(pOID);
+    }
+    
+    private void setPool (Pool pool) {
+        this.pool = pool;
+    }
+
+    /**
+     * Helper method to create a BtreeStorage. This method excutes the
+     * storage operation in a doPrivileged block and handles possible
+     * exceptions.  
+     * @param name name of database, which is used to name the files
+     * @param isNew true if the database is being created
+     * @return new database
+     * @exception FOStoreDatabaseException wraps a StorageException thrown
+     * by the create call.
+     * @exception JDOFatalUserException wraps a possible SecurityException.
+     */
+    private FOStoreBtreeStorage createBtreeStorage(final String name, 
+                                                   final boolean isNew)
+        throws FOStoreDatabaseException, JDOFatalUserException
+    {
+        try {
+            return (FOStoreBtreeStorage) AccessController.doPrivileged (
+                new PrivilegedExceptionAction () {
+                    public Object run () throws StorageException {
+                        return new FOStoreBtreeStorage(name, isNew);
+                    }
+                });
+        } catch (SecurityException ex) {
+            throw new JDOFatalUserException(msg.msg( 
+                "EXC_SecurityExceptionOnCreateBtreeStorage"), ex); //NOI18N
+        } catch (PrivilegedActionException ex) {
+            throw new FOStoreDatabaseException(
+                (StorageException)ex.getException());
+        } 
+    }
+
+    /** 
+     * Helper method to close a BtreeStorage. 
+     * @param storage the database to be closed
+     * @exception FOStoreDatabaseException wraps a StorageException thrown
+     * by the close call.
+     */
+    private void closeBtreeStorage(final FOStoreBtreeStorage storage)
+        throws FOStoreDatabaseException
+    {
+        try {
+            AccessController.doPrivileged (
+                new PrivilegedExceptionAction () {
+                    public Object run () throws StorageException {
+                        storage.shutDown();
+                        storage.close();
+                        return null;
+                    }
+                });
+        } catch (SecurityException ex) {
+            throw new JDOFatalUserException(msg.msg( 
+                "EXC_SecurityExceptionOnCloseBtreeStorage"), ex); //NOI18N
+        } catch (PrivilegedActionException ex) {
+            throw new FOStoreDatabaseException(
+                (StorageException)ex.getException());
+        } 
+    }
+
+    /** 
+     * Helper method to check whether a file exists. This method delegates
+     * to File.exists and handles possible SecurityExceptions.
+     * @param file the file to be checked
+     * @return <code>true</code> if the specified file exists.
+     */ 
+    private boolean existsFile(File file) {
+        try {
+            return file.exists();
+        } catch (SecurityException ex) {
+            throw new JDOFatalUserException(msg.msg(
+                "EXC_CannotReadFile", file.getName()), ex); //NOI18N
+        }
+    }
+
+    /** 
+     * Helper method to delete a file. This method delegates to File.delete
+     * and handles possible SecurityExceptions.
+     * @param file the file to be deleted
+     */
+    private void deleteFile(File file) {
+        try {
+            file.delete();
+        } catch (SecurityException ex) {
+            throw new JDOFatalUserException(msg.msg(
+                "EXC_CannotDeleteFile", file.getName()), ex); //NOI18N
+        }
+    }
+}

Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreDatabaseException.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreDatabaseException.java?view=auto&rev=158176
==============================================================================
--- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreDatabaseException.java (added)
+++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreDatabaseException.java Fri Mar 18 17:02:29 2005
@@ -0,0 +1,56 @@
+/*
+ * 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 org.netbeans.mdr.persistence.StorageException;
+
+/**
+* This provides an insulation layer between BtreeDatabase and FOStore.
+*
+* @author Dave Bristor
+*/
+class FOStoreDatabaseException extends StorageException {
+    private final StorageException ex;
+
+    FOStoreDatabaseException(StorageException ex) {
+        this.ex = ex;
+    }
+
+    public String getLocalizedMessage() {
+        return ex.getLocalizedMessage();
+    }
+
+    public String getMessage() {
+        return ex.getMessage();
+    }
+
+    public void printStackTrace() {
+        ex.printStackTrace();
+    }
+
+    public void printStackTrace(java.io.PrintStream s) {
+        ex.printStackTrace(s);
+    }
+
+    public void printStackTrace(java.io.PrintWriter s) {
+        ex.printStackTrace(s);
+    }
+
+    public String toString() {
+        return ex.toString();
+    }
+}

Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreExtent.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreExtent.java?view=auto&rev=158176
==============================================================================
--- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreExtent.java (added)
+++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreExtent.java Fri Mar 18 17:02:29 2005
@@ -0,0 +1,304 @@
+/*
+ * 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 java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+import javax.jdo.Extent;
+import javax.jdo.JDOHelper;
+import javax.jdo.JDOException;
+import javax.jdo.JDOUserException;
+import javax.jdo.PersistenceManager;
+import javax.jdo.Transaction;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.apache.jdo.pm.PersistenceManagerInternal;
+import org.apache.jdo.state.StateManagerInternal;
+import org.apache.jdo.util.I18NHelper;
+
+/**
+ * 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.
+//
+/**
+ * This is an in-memory extent.
+ */
+class FOStoreExtent implements Extent {
+private final FOStoreConnector connector;
+private final RequestFactory rf;
+
+    /** Iterators requested by user. */
+    private final HashSet iterators = new HashSet();
+
+    /** Class specified by user. */
+    private final Class cls;
+
+    /** If true, extent includes subclasses of user's class. */
+    private final boolean subclasses;
+
+    /** Persistence manager on which getExtent was invoked by user. */
+    private final PersistenceManagerInternal pm;
+
+    /** 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
+
+    FOStoreExtent(Class cls, boolean subclasses,
+                  PersistenceManagerInternal pm,
+                  RequestFactory rf,
+                  FOStoreConnector connector) {
+
+         this.cls = cls;
+         this.subclasses = subclasses;
+         this.pm = pm;
+         this.rf = rf;
+         this.connector = connector;
+    }
+
+    //
+    // Implement Extent
+    //
+
+    /**
+     * @see javax.jdo.Extent#iterator
+     */
+    public Iterator iterator() {
+        pm.assertReadAllowed();
+        Iterator rc = new FOStoreExtentIterator(this);
+        iterators.add(rc);
+        return rc;
+    }
+
+    /**
+     * @see javax.jdo.Extent#hasSubclasses
+     */
+    public boolean hasSubclasses() {
+        return subclasses;
+    }
+
+    /**
+     * @see javax.jdo.Extent#getCandidateClass
+     */
+    public Class getCandidateClass() {
+        return cls;
+    }
+
+    /**
+     * @see javax.jdo.Extent#getPersistenceManager
+     */
+    public PersistenceManager getPersistenceManager() {
+        return pm.getCurrentWrapper();
+    }
+
+    /**
+     * @see javax.jdo.Extent#closeAll
+     */
+    public void closeAll() {
+        for (Iterator i = iterators.iterator(); i.hasNext();) {
+            Iterator extentIterator = (Iterator)i.next();
+            if (logger.isDebugEnabled()) {
+                logger.debug("Extent.closeAll: removing " + extentIterator); // NOI18N
+            }
+            i.remove(); // remove first because close also removes it
+            close(extentIterator);
+        }
+    }
+
+    /**
+     * @see javax.jdo.Extent#close
+     */
+    public void close(Iterator it) {
+        if (it instanceof FOStoreExtentIterator) {
+            FOStoreExtentIterator fit = (FOStoreExtentIterator)it;
+            fit.close();
+            if (iterators.contains(fit)) {
+                if (logger.isDebugEnabled()) {
+                    logger.debug("Extent.close: removing " + fit); // NOI18N
+                }
+                // this will be true only if not executing closeAll.
+                iterators.remove(fit);
+            }
+        }
+    }
+
+    /**
+     * Iterates over the elements in a FOStoreExtent.
+     */
+    class FOStoreExtentIterator implements Iterator {
+        /** Instances that have been retrieved from store. */
+        // We have our own copy and do not use those from the enclosing
+        // FOStoreExtent, because we use a GetInstancesRequest to re-fill
+        // the ArrayList if needed.
+        private ArrayList instances;
+        private ArrayList oids;
+        private int maxInstances;
+
+        /** Index into instances. */
+        private int instanceIndex = 0;
+
+        /** Index into oids. */
+        private int oidsIndex = 0;
+
+        /** Index into extent as a whole.*/
+        private int index = 0;
+    
+        /** Size of extent (number of instances + number of oids). */
+        private final int size;
+
+        /** If false, then can get next object, otherwise 
+         * next() always throws NoSuchElementException and 
+         * hasNext() always returns false. */
+        private boolean closed = false;
+
+        private Object nextObject = null;
+
+        FOStoreExtentIterator(FOStoreExtent extent) {
+            try {
+                Message message = connector.getMessage();
+                GetExtentRequest request =
+                    rf.getGetExtentRequest(extent, cls, subclasses, message, pm);
+                request.doRequest();
+                connector.flush();
+                instances = request.getInstances();
+                oids = request.getOIDs();
+                maxInstances = request.getMaxInstances();
+            } catch (IOException ex) {
+                throw new FOStoreFatalIOException(
+                    getClass(), "init", ex); // NOI18N
+            } catch (JDOException ex) {
+                throw ex;
+            } catch (Exception ex) {
+                throw new FOStoreFatalInternalException(
+                    getClass(), "init", ex); // NOI18N
+            }
+    
+            Collection insertedInstances = pm.getInsertedInstances();
+            for (Iterator it = insertedInstances.iterator(); it.hasNext();) {
+                Object o = it.next();
+                Class clz = o.getClass();
+                if (cls.equals(clz) || (subclasses && cls.isAssignableFrom(clz))) {
+                    instances.add(o);
+                }
+            }
+
+            if (logger.isDebugEnabled()) {
+                logger.debug(
+                    "FOStoreExtentIterator.<init>: cls=" + cls.getName() + // NOI18N
+                    ", numInstances=" + instances.size()); // NOI18N
+            }
+
+            this.size = instances.size() + oids.size();
+            if (size == 0) {
+                close();
+            }
+        }
+
+        /**
+         * @see java.util.Iterator#hasNext
+         */
+        public boolean hasNext() {
+            // This code advances to the next not deleted
+            // instance, or until the iterator is closed.
+            // Iterator is closed in getNext() if there
+            // are no more instances available. nextObject
+            // is null at the beginning and after close().
+            while (! closed && (nextObject == null || 
+                                JDOHelper.isDeleted(nextObject))) {
+                getNext();
+            }
+            return (nextObject != null);
+        }
+
+        /**
+         * @see java.util.Iterator#next
+         */
+        public Object next() {
+            if (nextObject == null && !hasNext()) {
+                throw new NoSuchElementException();
+            } 
+
+            Object rc = nextObject;
+            nextObject = null;
+            return rc;
+       }
+
+       /** Get the next instance. Close the iterator if there are 
+        * no more instances available.
+        */
+       private void getNext() {
+            if (index < size) {
+                if (instanceIndex >= instances.size()) {
+                    if (logger.isDebugEnabled()) {
+                        logger.debug(
+                            "FOStoreExtentIterator.next get new instances"); // NOI18N
+                    }
+                    FOStoreStoreManager srm =
+                        (FOStoreStoreManager)pm.getStoreManager();
+                    instances = srm.getInstances(
+                        oids, oidsIndex, maxInstances, pm, cls);
+                    oidsIndex += instances.size();
+                    if (logger.isDebugEnabled()) {
+                        logger.debug(
+                            "FOStoreExtent.next got " + // NOI18N
+                            instances.size() + " instances"); // NOI18N
+                    }
+                    instanceIndex = 0;
+                }
+                nextObject = instances.get(instanceIndex);
+                instanceIndex++;
+                index++;
+
+            } else {
+                close();
+            }
+        }
+
+        /**
+         * Always throws UnsupportedOperationException.
+         */
+        public void remove() {
+            throw new UnsupportedOperationException(
+                msg.msg("EXC_RemoveNotSupported")); // NOI18N
+        }
+
+        /**
+         * Disallow getting further objects from this iterator.
+         */
+        void close() {
+            closed = true;
+            instances = null;
+            index = size;
+            nextObject = null;
+        }
+    }
+}

Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreFatalIOException.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreFatalIOException.java?view=auto&rev=158176
==============================================================================
--- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreFatalIOException.java (added)
+++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreFatalIOException.java Fri Mar 18 17:02:29 2005
@@ -0,0 +1,35 @@
+/*
+ * 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;
+
+/**
+* This is an exception which _should_ never be thrown, as it indicates an
+* error in I/O traffic between client and server.  It most likely indicates a
+* bug in the implementation.
+*
+* @author Dave Bristor
+*/
+public class FOStoreFatalIOException extends FOStoreFatalInternalException {
+    /**
+     * @param clz Class in which the exception is thrown.
+     * @param methodName Name of the method from which the exception is
+     * thrown.
+     */
+    FOStoreFatalIOException(Class clz, String methodName, Exception nested) {
+        super(clz, methodName, nested);
+    }
+}

Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreFatalInternalException.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreFatalInternalException.java?view=auto&rev=158176
==============================================================================
--- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreFatalInternalException.java (added)
+++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreFatalInternalException.java Fri Mar 18 17:02:29 2005
@@ -0,0 +1,61 @@
+/*
+ * 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 javax.jdo.JDOFatalInternalException;
+
+/**
+* This is an exception which _should_ never be thrown, as it indicates an
+* error in the implementation, such as a bug that has been found.
+*
+* @author Dave Bristor
+*/
+public class FOStoreFatalInternalException extends JDOFatalInternalException {
+    /**
+     * @param clz Class in which the exception is thrown.
+     * @param methodName Name of the method from which the exception is
+     * thrown.
+     * @param msg The exception message.
+     */
+    FOStoreFatalInternalException(Class clz, String methodName, String msg) {
+        super(clz.getName() + "." + methodName + ": " + msg); // NOI18N
+    }
+
+    /**
+     * @param clz Class in which the exception is thrown.
+     * @param methodName Name of the method from which the exception is
+     * thrown.
+     */
+    FOStoreFatalInternalException(Class clz, String methodName,
+                                  Exception nested) {
+        super(clz.getName() + "." + methodName, // NOI18N
+              new Exception[] {nested}); // NOI18N
+    }
+
+    /**
+     * @param clz Class in which the exception is thrown.
+     * @param methodName Name of the method from which the exception is
+     * thrown.
+     * @param msg The exception message.
+     */
+    FOStoreFatalInternalException(Class clz, String methodName, String msg,
+                                  Exception nested) {
+
+        super(clz.getName() + "." + methodName + ": " + msg, // NOI18N
+              new Exception[] {nested}); // NOI18N
+    }
+}

Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreInput.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreInput.java?view=auto&rev=158176
==============================================================================
--- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreInput.java (added)
+++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreInput.java Fri Mar 18 17:02:29 2005
@@ -0,0 +1,135 @@
+/*
+ * 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.ByteArrayInputStream;
+import java.io.DataInput;
+import java.io.DataInputStream;
+import java.io.IOException;
+
+import org.apache.jdo.util.I18NHelper;
+
+
+/**
+* Extend ByteArrayInputStream so that we can get ahold of the byte array
+* and current position, and can change the current position.
+*
+* @author Dave Bristor
+*/
+class FOStoreInput extends ByteArrayInputStream implements DataInput {
+    private final DataInputStream dis;
+
+    /** I18N support. */
+    private static final I18NHelper msg = I18NHelper.getInstance(I18N.NAME);
+    
+    FOStoreInput(byte data[], int off, int len) {
+        super(data, off, len);
+        dis = new DataInputStream(this);
+    }
+
+    byte[] getBuf() {
+        return buf;
+    }
+
+    int getPos() {
+        return pos;
+    }
+
+    void setPos(int pos) {
+        if (pos < 0 || pos > buf.length) {
+            throw new FOStoreFatalInternalException(
+                this.getClass(), "setPos", // NOI18N
+                msg.msg("ERR_InvalidSeekPos", // NOI18N
+                        new Integer(pos), new Integer(buf.length)));
+        }
+        this.pos = pos;
+    }
+
+    // Advance pos by len, but don't break invariant required by
+    // ByteArrayInputStream (see ByteArrayInputStrea.pos's javadoc).
+    void advance(int len) {
+        if (pos + len <= count) {
+            pos += len;
+        } else {
+            pos = count;
+        }
+    }
+
+    //
+    // Implement DataInput
+    //
+
+    public boolean readBoolean() throws IOException {
+        return dis.readBoolean();
+    }
+
+    public byte readByte() throws IOException {
+        return dis.readByte();
+    }
+
+    public char readChar() throws IOException {
+        return dis.readChar();
+    }
+
+    public double readDouble() throws IOException {
+        return dis.readDouble();
+    }
+
+    public float readFloat() throws IOException {
+        return dis.readFloat();
+    }
+
+    public void readFully(byte[] b) throws IOException {
+        dis.readFully(b);
+    }
+
+    public void readFully(byte[] b, int off, int len) throws IOException {
+        dis.readFully(b, off, len);
+    }
+
+    public int readInt() throws IOException {
+        return dis.readInt();
+    }
+
+    public String readLine() throws IOException {
+        return dis.readLine();
+    }
+
+    public long readLong() throws IOException {
+        return dis.readLong();
+    }
+
+    public short readShort() throws IOException {
+        return dis.readShort();
+    }
+
+    public int readUnsignedByte() throws IOException {
+        return dis.readUnsignedByte();
+    }
+
+    public int readUnsignedShort() throws IOException {
+        return dis.readUnsignedShort();
+    }
+
+    public String readUTF() throws IOException {
+        return dis.readUTF();
+    }
+
+    public int skipBytes(int n) throws IOException {
+        return dis.skipBytes(n);
+    }
+}



Mime
View raw message