You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@velocity.apache.org by cb...@apache.org on 2012/03/09 17:23:32 UTC

svn commit: r1298906 [8/14] - in /velocity/sandbox/velosurf: ./ docs/ examples/ examples/ant-vpp/ examples/ant-vpp/lib/ examples/auth-l10n/ examples/auth-l10n/WEB-INF/ examples/auth-l10n/WEB-INF/lib/ examples/auth-l10n/WEB-INF/src/ examples/auth-l10n/e...

Added: velocity/sandbox/velosurf/src/java/org/apache/velocity/velosurf/sql/ConnectionWrapper.java.jdk5
URL: http://svn.apache.org/viewvc/velocity/sandbox/velosurf/src/java/org/apache/velocity/velosurf/sql/ConnectionWrapper.java.jdk5?rev=1298906&view=auto
==============================================================================
--- velocity/sandbox/velosurf/src/java/org/apache/velocity/velosurf/sql/ConnectionWrapper.java.jdk5 (added)
+++ velocity/sandbox/velosurf/src/java/org/apache/velocity/velosurf/sql/ConnectionWrapper.java.jdk5 Fri Mar  9 16:23:25 2012
@@ -0,0 +1,712 @@
+/*
+ * Copyright 2003 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.velocity.velosurf.sql;
+
+import java.lang.reflect.Method;
+import java.sql.*;
+import java.util.Map;
+import java.util.Properties;
+import org.apache.velocity.velosurf.util.Logger;
+
+/**
+ * Connection wrapper class. Allows the handling of a busy state
+ *
+ *  @author <a href="mailto:claude.brisson@gmail.com">Claude Brisson</a>
+ */
+
+public class ConnectionWrapper
+    implements Connection
+{
+
+    /**
+     * Constructor.
+     * @param driver infos on the driver
+     * @param connection connection to be wrapped
+     */
+    public ConnectionWrapper(DriverInfo driver,Connection connection)
+    {
+        this.driver = driver;
+        this.connection = connection;
+    }
+
+    /**
+     * Unwrap the connection.
+     * @return the unwrapped connection
+     */
+    public Connection unwrap()
+    {
+        return connection;
+    }
+
+    /**
+     * Create a statement.
+     * @return created statement
+     * @throws SQLException
+     */
+    public Statement createStatement()
+        throws SQLException
+    {
+        try
+        {
+            enterBusyState();
+            return connection.createStatement();
+        }
+        finally
+        {
+            leaveBusyState();
+        }
+    }
+
+    /**
+     * Prepare a statement.
+     * @param s SQL query
+     * @return prepared statement
+     * @throws SQLException
+     */
+    public synchronized PreparedStatement prepareStatement(String s)
+        throws SQLException
+    {
+        try
+        {
+            enterBusyState();
+            return connection.prepareStatement(s);
+        }
+        finally
+        {
+            leaveBusyState();
+        }
+    }
+
+    /**
+     * Prepare a callable statement.
+     * @param s SQL query
+     * @return prepared callable statement
+     * @throws SQLException
+     */
+    public synchronized CallableStatement prepareCall(String s)
+        throws SQLException
+    {
+        try
+        {
+            enterBusyState();
+            return connection.prepareCall(s);
+        }
+        finally
+        {
+            leaveBusyState();
+        }
+    }
+
+    /**
+     * Gets native SQL for a query.
+     * @param s query
+     * @return native SQL
+     * @throws SQLException
+     */
+    public synchronized String nativeSQL(String s)
+        throws SQLException
+    {
+        try
+        {
+            enterBusyState();
+            return connection.nativeSQL(s);
+        }
+        finally
+        {
+            leaveBusyState();
+        }
+    }
+
+    /**
+     * Set autocommit flag.
+     * @param flag autocommit
+     * @throws SQLException
+     */
+    public void setAutoCommit(boolean flag)
+        throws SQLException
+    {
+        connection.setAutoCommit(flag);
+    }
+
+    /**
+     * Get autocommit flag.
+     *
+     * @return autocommit flag
+     * @throws SQLException
+     */
+    public boolean getAutoCommit()
+        throws SQLException
+    {
+        return connection.getAutoCommit();
+    }
+
+    /**
+     * Commit.
+     *
+     * @throws SQLException
+     */
+    public synchronized void commit()
+        throws SQLException
+    {
+        try
+        {
+            enterBusyState();
+            connection.commit();
+        }
+        finally
+        {
+            leaveBusyState();
+        }
+    }
+
+    /**
+     * Rollback.
+     *
+     * @throws SQLException
+     */
+    public synchronized void rollback()
+        throws SQLException
+    {
+        try
+        {
+            enterBusyState();
+            connection.rollback();
+        }
+        finally
+        {
+            leaveBusyState();
+        }
+    }
+
+    /**
+     * Close.
+     *
+     * @throws SQLException
+     */
+    public void close()
+        throws SQLException
+    {
+        // since some sql drivers refuse to close a connection that has been interrupted,
+        // better handle this also ourselves
+        closed = true;
+        connection.close();
+    }
+
+    /**
+     * Check the closed state.
+     * @return closed state
+     * @throws SQLException
+     */
+    public boolean isClosed()
+        throws SQLException
+    {
+        return (closed || connection.isClosed());
+    }
+
+    /**
+     * Get meta data
+     * @return database meta data
+     * @throws SQLException
+     */
+    public DatabaseMetaData getMetaData()
+        throws SQLException
+    {
+        return connection.getMetaData();
+    }
+
+    /**
+     * set read-only flag
+     * @param flag read-only
+     * @throws SQLException
+     */
+    public void setReadOnly(boolean flag)
+        throws SQLException
+    {
+        connection.setReadOnly(flag);
+    }
+
+    /**
+     * Check the read-only state.
+     * @return read-only state
+     * @throws SQLException
+     */
+    public boolean isReadOnly()
+        throws SQLException
+    {
+        return connection.isReadOnly();
+    }
+
+    /**
+     * Catalog setter.
+     * @param s catalog
+     * @throws SQLException
+     */
+    public void setCatalog(String s)
+        throws SQLException
+    {
+        connection.setCatalog(s);
+    }
+
+    /**
+     * Catalog getter.
+     * @return catalog
+     * @throws SQLException
+     */
+
+    public String getCatalog()
+        throws SQLException
+    {
+        return connection.getCatalog();
+    }
+    /**
+     * Transaction isolation setter.
+     * @param i transaction isolation
+     * @throws SQLException
+     */
+
+    public void setTransactionIsolation(int i)
+        throws SQLException
+    {
+        connection.setTransactionIsolation(i);
+    }
+
+    /**
+     * Transaction isolation getter.
+     * @return transaction isolation
+     * @throws SQLException
+     */
+    public int getTransactionIsolation()
+        throws SQLException
+    {
+        return connection.getTransactionIsolation();
+    }
+
+    /**
+     * Get SQL warnings.
+     * @return next SQL Warning.
+     * @throws SQLException
+     */
+    public SQLWarning getWarnings()
+        throws SQLException
+    {
+        return connection.getWarnings();
+    }
+
+    /**
+     * Clear SQL warnings.
+     * @throws SQLException
+     */
+    public void clearWarnings()
+        throws SQLException
+    {
+        connection.clearWarnings();
+    }
+
+    /**
+     * Create a statement.
+     *
+     * @param i result set type
+     * @param j result set concurrency
+     * @return new statement
+     * @throws SQLException
+     */
+    public synchronized Statement createStatement(int i, int j)
+        throws SQLException
+    {
+        try
+        {
+            enterBusyState();
+            return connection.createStatement(i, j);
+        }
+        finally
+        {
+            leaveBusyState();
+        }
+
+    }
+
+    /**
+     * Prepare a statement.
+     * @param s SQL query
+     * @param i result set type
+     * @param j result set concurrency
+     * @return prepared statement
+     * @throws SQLException
+     */
+    public synchronized PreparedStatement prepareStatement(String s, int i, int j)
+        throws SQLException
+    {
+        try
+        {
+            enterBusyState();
+            return connection.prepareStatement(s, i, j);
+        }
+        finally
+        {
+            leaveBusyState();
+        }
+    }
+
+    /**
+     * Prepare a call.
+     * @param s SQL query
+     * @param i result set type
+     * @param j result set concurrency
+     * @return callable statement
+     * @throws SQLException
+     */
+    public synchronized CallableStatement prepareCall(String s, int i, int j)
+        throws SQLException
+    {
+        try
+        {
+            enterBusyState();
+            return connection.prepareCall(s, i, j);
+        }
+        finally
+        {
+            leaveBusyState();
+        }
+    }
+
+    /**
+     * Get type map.
+     * @return type map
+     * @throws SQLException
+     */
+    public Map getTypeMap()
+        throws SQLException
+    {
+        return connection.getTypeMap();
+    }
+
+    /**
+     * Set type map.
+     * @param map type map
+     * @throws SQLException
+     */
+    public void setTypeMap(Map map)
+        throws SQLException
+    {
+        connection.setTypeMap(map);
+    }
+
+    /**
+     * Set holdability.
+     * @param i holdability
+     * @throws SQLException
+     */
+    public void setHoldability(int i)
+        throws SQLException
+    {
+        connection.setHoldability(i);
+    }
+
+    /**
+     * Get holdability.
+     * @return holdability
+     * @throws SQLException
+     */
+    public int getHoldability()
+        throws SQLException
+    {
+        return connection.getHoldability();
+    }
+
+    /**
+     * Savepoint setter.
+     * @return save point
+     * @throws SQLException
+     */
+    public synchronized Savepoint setSavepoint()
+        throws SQLException
+    {
+        return connection.setSavepoint();
+    }
+
+    /**
+     * Set named savepoint.
+     * @param s savepoint name
+     * @return savepoint
+     * @throws SQLException
+     */
+    public synchronized Savepoint setSavepoint(String s)
+        throws SQLException
+    {
+        return connection.setSavepoint(s);
+    }
+
+    /**
+     * Rollback.
+     * @param savepoint savepoint
+     * @throws SQLException
+     */
+    public synchronized void rollback(Savepoint savepoint)
+        throws SQLException
+    {
+        connection.rollback(savepoint);
+    }
+    /**
+     * Release savepoint.
+     *
+     * @param savepoint savepoint
+     * @throws SQLException
+     */
+    public synchronized void releaseSavepoint(Savepoint savepoint)
+        throws SQLException
+    {
+        connection.releaseSavepoint(savepoint);
+    }
+
+    /**
+     * Create a statement.
+     * @param i result set type
+     * @param j result set concurrency
+     * @param k result set holdability
+     * @return created statement
+     * @throws SQLException
+     */
+    public synchronized Statement createStatement(int i, int j, int k)
+        throws SQLException
+    {
+        try
+        {
+           enterBusyState();
+            return connection.createStatement(i, j, k);
+        }
+        finally 
+        {
+            leaveBusyState();
+        }
+    }
+
+    /**
+     * Prepare a statement.
+     * @param s SQL query
+     * @param i result set type
+     * @param j result set concurrency
+     * @param k result set holdability
+     * @return prepared statement
+     * @throws SQLException
+     */
+    public synchronized PreparedStatement prepareStatement(String s, int i, int j, int k)
+        throws SQLException
+    {
+        try
+        {
+            enterBusyState();
+            return connection.prepareStatement(s, i, j, k);
+        }
+        finally
+        {
+            leaveBusyState();
+        }
+    }
+
+    /**
+     * Prepare a callable statement.
+     * @param s SQL query
+     * @param i result set type
+     * @param j result set concurrency
+     * @param k result set holdability
+     * @return prepared statement
+     * @throws SQLException
+     */
+    public synchronized CallableStatement prepareCall(String s, int i, int j, int k)
+        throws SQLException
+    {
+        try
+        {
+            enterBusyState();
+            return connection.prepareCall(s, i, j, k);
+        }
+        finally
+        {
+            leaveBusyState();
+        }
+    }
+
+    /**
+     * Prepare a statement.
+     * @param s SQL query
+     * @param i autogenerated keys
+     * @return prepared statement
+     * @throws SQLException
+     */
+    public synchronized PreparedStatement prepareStatement(String s, int i)
+        throws SQLException
+    {
+        try
+        {
+            enterBusyState();
+            return connection.prepareStatement(s, i);
+        }
+        finally
+        {
+            leaveBusyState();
+        }
+    }
+
+    /**
+     * Prepare a statement.
+     * @param s SQL query
+     * @param ai autogenerated keys column indexes
+     * @return prepared statement
+     * @throws SQLException
+     */
+    public synchronized PreparedStatement prepareStatement(String s, int ai[])
+        throws SQLException
+    {
+        try
+        {
+            enterBusyState();
+            return connection.prepareStatement(s, ai);
+        }
+        finally
+        {
+            leaveBusyState();
+        }
+    }
+
+    /**
+     * Prepare a statement.
+     * @param s SQL query
+     * @param as autogenerated keys column names
+     * @return prepared statement
+     * @throws SQLException
+     */
+    public synchronized PreparedStatement prepareStatement(String s, String as[])
+        throws SQLException
+    {
+        try     
+        {
+            enterBusyState();
+            return connection.prepareStatement(s,as);
+        }
+        finally
+        {
+            leaveBusyState();
+        }
+    }
+
+    /** 
+     * Enter busy state.
+     */
+    public void enterBusyState()
+    {
+        //Logger.trace("connection #"+toString()+": entering busy state.");
+        busy++;
+    }
+
+    /**
+     * Leave busy state.
+     */
+    public void leaveBusyState()
+    {
+        lastUse = System.currentTimeMillis();
+        busy--;
+        //Logger.trace("connection #"+toString()+": leaving busy state.");
+    }
+
+    /**
+     * Check busy state.
+     * @return busy state
+     */
+    public boolean isBusy()
+    {
+        return busy>0;
+    }
+
+    /**
+     * Get last use timestamp
+     *
+     * @return last use
+     */
+    public long getLastUse()
+    {
+      return lastUse;
+    }
+
+    /**
+     * Get last inserted ID.
+     * 
+     * @param statement
+     * @return last inserted id
+     * @throws SQLException
+     */
+    public long getLastInsertId(Statement statement) throws SQLException
+    {
+        return driver.getLastInsertId(statement);
+    }
+
+    /**
+     * Check connection.
+     *
+     * @return true if the connection is ok
+     */
+    public synchronized boolean check()
+    {
+        try
+        {
+            String checkQuery = driver.getPingQuery();
+            if (checkQuery == null)
+            {
+                // at least, call isOpen
+                if (isClosed())
+                {
+                    throw new Exception ("Connection is closed");
+                }
+            }
+            else
+            {
+                if (checkStatement == null)
+                {
+                    checkStatement = prepareStatement(checkQuery);
+                }
+                checkStatement.executeQuery();
+            }
+            return true;
+        }
+        catch (Exception e)
+        {
+            Logger.warn("Exception while checking connection!");
+            Logger.info("Refreshing...");
+            return false;
+        }
+    }
+
+    /** Infos on the driver. */
+    private DriverInfo driver = null;
+
+    /** Wrapped connection. */
+    private Connection connection = null;
+
+    /** Busy state. */
+    private int busy = 0;
+
+    /** Last use */
+    private long lastUse = System.currentTimeMillis();
+
+    /** Closed state. */
+    private boolean closed = false;
+
+    /** statement used to check connection ("select 1").
+     */
+    private PreparedStatement checkStatement = null;
+}

Added: velocity/sandbox/velosurf/src/java/org/apache/velocity/velosurf/sql/ConnectionWrapper.java.jdk6
URL: http://svn.apache.org/viewvc/velocity/sandbox/velosurf/src/java/org/apache/velocity/velosurf/sql/ConnectionWrapper.java.jdk6?rev=1298906&view=auto
==============================================================================
--- velocity/sandbox/velosurf/src/java/org/apache/velocity/velosurf/sql/ConnectionWrapper.java.jdk6 (added)
+++ velocity/sandbox/velosurf/src/java/org/apache/velocity/velosurf/sql/ConnectionWrapper.java.jdk6 Fri Mar  9 16:23:25 2012
@@ -0,0 +1,1090 @@
+/*
+ * Copyright 2003 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.velocity.velosurf.sql;
+
+import java.lang.reflect.Method;
+import java.sql.*;
+import java.util.Map;
+import java.util.Properties;
+import org.apache.velocity.velosurf.util.Logger;
+
+/**
+ * Connection wrapper class. Allows the handling of a busy state
+ *
+ *  @author <a href="mailto:claude.brisson@gmail.com">Claude Brisson</a>
+ */
+
+public class ConnectionWrapper
+    implements Connection
+{
+
+    /**
+     * Constructor.
+     * @param driver infos on the driver
+     * @param connection connection to be wrapped
+     */
+    public ConnectionWrapper(DriverInfo driver,Connection connection)
+    {
+        this.driver = driver;
+        this.connection = connection;
+    }
+
+    /**
+     * Unwrap the connection.
+     * @return the unwrapped connection
+     */
+    public Connection unwrap()
+    {
+        return connection;
+    }
+
+    /**
+     * Create a statement.
+     * @return created statement
+     * @throws SQLException
+     */
+    public Statement createStatement()
+        throws SQLException
+    {
+        try
+        {
+            enterBusyState();
+            return connection.createStatement();
+        }
+        finally
+        {
+            leaveBusyState();
+        }
+    }
+
+    /**
+     * Prepare a statement.
+     * @param s SQL query
+     * @return prepared statement
+     * @throws SQLException
+     */
+    public synchronized PreparedStatement prepareStatement(String s)
+        throws SQLException
+    {
+        try
+        {
+            enterBusyState();
+            return connection.prepareStatement(s);
+        }
+        finally
+        {
+            leaveBusyState();
+        }
+    }
+
+    /**
+     * Prepare a callable statement.
+     * @param s SQL query
+     * @return prepared callable statement
+     * @throws SQLException
+     */
+    public synchronized CallableStatement prepareCall(String s)
+        throws SQLException
+    {
+        try
+        {
+            enterBusyState();
+            return connection.prepareCall(s);
+        }
+        finally
+        {
+            leaveBusyState();
+        }
+    }
+
+    /**
+     * Gets native SQL for a query.
+     * @param s query
+     * @return native SQL
+     * @throws SQLException
+     */
+    public synchronized String nativeSQL(String s)
+        throws SQLException
+    {
+        try
+        {
+            enterBusyState();
+            return connection.nativeSQL(s);
+        }
+        finally
+        {
+            leaveBusyState();
+        }
+    }
+
+    /**
+     * Set autocommit flag.
+     * @param flag autocommit
+     * @throws SQLException
+     */
+    public void setAutoCommit(boolean flag)
+        throws SQLException
+    {
+        connection.setAutoCommit(flag);
+    }
+
+    /**
+     * Get autocommit flag.
+     *
+     * @return autocommit flag
+     * @throws SQLException
+     */
+    public boolean getAutoCommit()
+        throws SQLException
+    {
+        return connection.getAutoCommit();
+    }
+
+    /**
+     * Commit.
+     *
+     * @throws SQLException
+     */
+    public synchronized void commit()
+        throws SQLException
+    {
+        try
+        {
+            enterBusyState();
+            connection.commit();
+        }
+        finally
+        {
+            leaveBusyState();
+        }
+    }
+
+    /**
+     * Rollback.
+     *
+     * @throws SQLException
+     */
+    public synchronized void rollback()
+        throws SQLException
+    {
+        try
+        {
+            enterBusyState();
+            connection.rollback();
+        }
+        finally
+        {
+            leaveBusyState();
+        }
+    }
+
+    /**
+     * Close.
+     *
+     * @throws SQLException
+     */
+    public void close()
+        throws SQLException
+    {
+        // since some sql drivers refuse to close a connection that has been interrupted,
+        // better handle this also ourselves
+        closed = true;
+        connection.close();
+    }
+
+    /**
+     * Check the closed state.
+     * @return closed state
+     * @throws SQLException
+     */
+    public boolean isClosed()
+        throws SQLException
+    {
+        return (closed || connection.isClosed());
+    }
+
+    /**
+     * Get meta data
+     * @return database meta data
+     * @throws SQLException
+     */
+    public DatabaseMetaData getMetaData()
+        throws SQLException
+    {
+        return connection.getMetaData();
+    }
+
+    /**
+     * set read-only flag
+     * @param flag read-only
+     * @throws SQLException
+     */
+    public void setReadOnly(boolean flag)
+        throws SQLException
+    {
+        connection.setReadOnly(flag);
+    }
+
+    /**
+     * Check the read-only state.
+     * @return read-only state
+     * @throws SQLException
+     */
+    public boolean isReadOnly()
+        throws SQLException
+    {
+        return connection.isReadOnly();
+    }
+
+    /**
+     * Catalog setter.
+     * @param s catalog
+     * @throws SQLException
+     */
+    public void setCatalog(String s)
+        throws SQLException
+    {
+        connection.setCatalog(s);
+    }
+
+    /**
+     * Catalog getter.
+     * @return catalog
+     * @throws SQLException
+     */
+
+    public String getCatalog()
+        throws SQLException
+    {
+        return connection.getCatalog();
+    }
+    /**
+     * Transaction isolation setter.
+     * @param i transaction isolation
+     * @throws SQLException
+     */
+
+    public void setTransactionIsolation(int i)
+        throws SQLException
+    {
+        connection.setTransactionIsolation(i);
+    }
+
+    /**
+     * Transaction isolation getter.
+     * @return transaction isolation
+     * @throws SQLException
+     */
+    public int getTransactionIsolation()
+        throws SQLException
+    {
+        return connection.getTransactionIsolation();
+    }
+
+    /**
+     * Get SQL warnings.
+     * @return next SQL Warning.
+     * @throws SQLException
+     */
+    public SQLWarning getWarnings()
+        throws SQLException
+    {
+        return connection.getWarnings();
+    }
+
+    /**
+     * Clear SQL warnings.
+     * @throws SQLException
+     */
+    public void clearWarnings()
+        throws SQLException
+    {
+        connection.clearWarnings();
+    }
+
+    /**
+     * Create a statement.
+     *
+     * @param i result set type
+     * @param j result set concurrency
+     * @return new statement
+     * @throws SQLException
+     */
+    public synchronized Statement createStatement(int i, int j)
+        throws SQLException
+    {
+        try
+        {
+            enterBusyState();
+            return connection.createStatement(i, j);
+        }
+        finally
+        {
+            leaveBusyState();
+        }
+
+    }
+
+    /**
+     * Prepare a statement.
+     * @param s SQL query
+     * @param i result set type
+     * @param j result set concurrency
+     * @return prepared statement
+     * @throws SQLException
+     */
+    public synchronized PreparedStatement prepareStatement(String s, int i, int j)
+        throws SQLException
+    {
+        try
+        {
+            enterBusyState();
+            return connection.prepareStatement(s, i, j);
+        }
+        finally
+        {
+            leaveBusyState();
+        }
+    }
+
+    /**
+     * Prepare a call.
+     * @param s SQL query
+     * @param i result set type
+     * @param j result set concurrency
+     * @return callable statement
+     * @throws SQLException
+     */
+    public synchronized CallableStatement prepareCall(String s, int i, int j)
+        throws SQLException
+    {
+        try
+        {
+            enterBusyState();
+            return connection.prepareCall(s, i, j);
+        }
+        finally
+        {
+            leaveBusyState();
+        }
+    }
+
+    /**
+     * Get type map.
+     * @return type map
+     * @throws SQLException
+     */
+    public Map getTypeMap()
+        throws SQLException
+    {
+        return connection.getTypeMap();
+    }
+
+    /**
+     * Set type map.
+     * @param map type map
+     * @throws SQLException
+     */
+    public void setTypeMap(Map map)
+        throws SQLException
+    {
+        connection.setTypeMap(map);
+    }
+
+    /**
+     * Set holdability.
+     * @param i holdability
+     * @throws SQLException
+     */
+    public void setHoldability(int i)
+        throws SQLException
+    {
+        connection.setHoldability(i);
+    }
+
+    /**
+     * Get holdability.
+     * @return holdability
+     * @throws SQLException
+     */
+    public int getHoldability()
+        throws SQLException
+    {
+        return connection.getHoldability();
+    }
+
+    /**
+     * Savepoint setter.
+     * @return save point
+     * @throws SQLException
+     */
+    public synchronized Savepoint setSavepoint()
+        throws SQLException
+    {
+        return connection.setSavepoint();
+    }
+
+    /**
+     * Set named savepoint.
+     * @param s savepoint name
+     * @return savepoint
+     * @throws SQLException
+     */
+    public synchronized Savepoint setSavepoint(String s)
+        throws SQLException
+    {
+        return connection.setSavepoint(s);
+    }
+
+    /**
+     * Rollback.
+     * @param savepoint savepoint
+     * @throws SQLException
+     */
+    public synchronized void rollback(Savepoint savepoint)
+        throws SQLException
+    {
+        connection.rollback(savepoint);
+    }
+    /**
+     * Release savepoint.
+     *
+     * @param savepoint savepoint
+     * @throws SQLException
+     */
+    public synchronized void releaseSavepoint(Savepoint savepoint)
+        throws SQLException
+    {
+        connection.releaseSavepoint(savepoint);
+    }
+
+    /**
+     * Create a statement.
+     * @param i result set type
+     * @param j result set concurrency
+     * @param k result set holdability
+     * @return created statement
+     * @throws SQLException
+     */
+    public synchronized Statement createStatement(int i, int j, int k)
+        throws SQLException
+    {
+        try
+        {
+           enterBusyState();
+            return connection.createStatement(i, j, k);
+        }
+        finally 
+        {
+            leaveBusyState();
+        }
+    }
+
+    /**
+     * Prepare a statement.
+     * @param s SQL query
+     * @param i result set type
+     * @param j result set concurrency
+     * @param k result set holdability
+     * @return prepared statement
+     * @throws SQLException
+     */
+    public synchronized PreparedStatement prepareStatement(String s, int i, int j, int k)
+        throws SQLException
+    {
+        try
+        {
+            enterBusyState();
+            return connection.prepareStatement(s, i, j, k);
+        }
+        finally
+        {
+            leaveBusyState();
+        }
+    }
+
+    /**
+     * Prepare a callable statement.
+     * @param s SQL query
+     * @param i result set type
+     * @param j result set concurrency
+     * @param k result set holdability
+     * @return prepared statement
+     * @throws SQLException
+     */
+    public synchronized CallableStatement prepareCall(String s, int i, int j, int k)
+        throws SQLException
+    {
+        try
+        {
+            enterBusyState();
+            return connection.prepareCall(s, i, j, k);
+        }
+        finally
+        {
+            leaveBusyState();
+        }
+    }
+
+    /**
+     * Prepare a statement.
+     * @param s SQL query
+     * @param i autogenerated keys
+     * @return prepared statement
+     * @throws SQLException
+     */
+    public synchronized PreparedStatement prepareStatement(String s, int i)
+        throws SQLException
+    {
+        try
+        {
+            enterBusyState();
+            return connection.prepareStatement(s, i);
+        }
+        finally
+        {
+            leaveBusyState();
+        }
+    }
+
+    /**
+     * Prepare a statement.
+     * @param s SQL query
+     * @param ai autogenerated keys column indexes
+     * @return prepared statement
+     * @throws SQLException
+     */
+    public synchronized PreparedStatement prepareStatement(String s, int ai[])
+        throws SQLException
+    {
+        try
+        {
+            enterBusyState();
+            return connection.prepareStatement(s, ai);
+        }
+        finally
+        {
+            leaveBusyState();
+        }
+    }
+
+    /**
+     * Prepare a statement.
+     * @param s SQL query
+     * @param as autogenerated keys column names
+     * @return prepared statement
+     * @throws SQLException
+     */
+    public synchronized PreparedStatement prepareStatement(String s, String as[])
+        throws SQLException
+    {
+        try     
+        {
+            enterBusyState();
+            return connection.prepareStatement(s,as);
+        }
+        finally
+        {
+            leaveBusyState();
+        }
+    }
+
+    /** 
+     * Enter busy state.
+     */
+    public void enterBusyState()
+    {
+        //Logger.trace("connection #"+toString()+": entering busy state.");
+        busy++;
+    }
+
+    /**
+     * Leave busy state.
+     */
+    public void leaveBusyState()
+    {
+        lastUse = System.currentTimeMillis();
+        busy--;
+        //Logger.trace("connection #"+toString()+": leaving busy state.");
+    }
+
+    /**
+     * Check busy state.
+     * @return busy state
+     */
+    public boolean isBusy()
+    {
+        return busy>0;
+    }
+
+    /**
+     * Get last use timestamp
+     *
+     * @return last use
+     */
+    public long getLastUse()
+    {
+      return lastUse;
+    }
+
+    /**
+     * Get last inserted ID.
+     * 
+     * @param statement
+     * @return last inserted id
+     * @throws SQLException
+     */
+    public long getLastInsertId(Statement statement) throws SQLException
+    {
+        return driver.getLastInsertId(statement);
+    }
+
+    /**
+     * Check connection.
+     *
+     * @return true if the connection is ok
+     */
+    public synchronized boolean check()
+    {
+        try
+        {
+            String checkQuery = driver.getPingQuery();
+            if (checkQuery == null)
+            {
+                // at least, call isOpen
+                if (isClosed())
+                {
+                    throw new Exception ("Connection is closed");
+                }
+            }
+            else
+            {
+                if (checkStatement == null)
+                {
+                    checkStatement = prepareStatement(checkQuery);
+                }
+                checkStatement.executeQuery();
+            }
+            return true;
+        }
+        catch (Exception e)
+        {
+            Logger.warn("Exception while checking connection!");
+            Logger.info("Refreshing...");
+            return false;
+        }
+    }
+
+    /** Infos on the driver. */
+    private DriverInfo driver = null;
+
+    /** Wrapped connection. */
+    private Connection connection = null;
+
+    /** Busy state. */
+    private int busy = 0;
+
+    /** Last use */
+    private long lastUse = System.currentTimeMillis();
+
+    /** Closed state. */
+    private boolean closed = false;
+
+    /** statement used to check connection ("select 1").
+     */
+    private PreparedStatement checkStatement = null;
+
+    /*
+     * stores new 1.6 methods using reflection api to ensure backward compatibility
+     */
+
+    static Method _createClob = null;
+    static Method _createBlob = null;
+    static Method _createNClob = null;
+    static Method _createSQLXML = null;
+    static Method _isValid = null;
+    static Method _setClientInfo = null;
+    static Method _setClientInfo2 = null;
+    static Method _getClientInfo = null;
+    static Method _getClientInfo2 = null;
+    static Method _createArrayOf = null;
+    static Method _createStruct = null;
+    static Method _isWrapperFor = null;
+
+    static
+    {
+        try
+        {
+            _createClob = getConnectionMethod("createClob",new Class[]{});
+            _createBlob = getConnectionMethod("createBlob",new Class[]{});
+            _createNClob = getConnectionMethod("createNClob",new Class[]{});
+            _createSQLXML = getConnectionMethod("createSQLXML",new Class[]{});
+            _isValid = getConnectionMethod("isValid",new Class[]{int.class});
+            _setClientInfo = getConnectionMethod("setClientInfo",new Class[]{String.class,String.class});
+            _setClientInfo2 = getConnectionMethod("setClientInfo",new Class[]{Properties.class});
+            _getClientInfo = getConnectionMethod("getClientInfo",new Class[]{});
+            _getClientInfo2 = getConnectionMethod("getClientInfo",new Class[]{String.class});
+            _createArrayOf = getConnectionMethod("createArrayOf",new Class[]{String.class,Class.forName("[Ljava.lang.Object;")});
+            _createStruct = getConnectionMethod("createStruct",new Class[]{String.class,Class.forName("[Ljava.lang.Object;")});
+            _isWrapperFor = getConnectionMethod("isWrapperFor",new Class[]{Class.class});
+        }
+        catch(Exception e)
+        {
+        }
+    }
+
+    static private Method getConnectionMethod(String name,Class[] parameterTypes)
+    {
+        try
+        {
+            return Connection.class.getMethod(name,parameterTypes);
+        }
+        catch(NoSuchMethodException nsme)
+        {
+            return null;
+        }
+    }
+
+    public Clob createClob() throws SQLException
+    {
+        if(_createClob == null)
+        {
+            throw new SQLException("Unsupported method.");
+        }
+        else
+        {
+            try
+            {
+                return (Clob)_createClob.invoke(connection, new Object[] {});
+            }
+            catch(Exception e)
+            {
+                Throwable cause = e.getCause();
+                if (cause == null)
+                {
+                    cause = e;
+                }
+                if(cause instanceof SQLException)
+                {
+                    throw (SQLException)cause;
+                }
+                else
+                {
+                    throw new SQLException(cause);
+                }
+            }
+        }
+    }
+
+    public Blob createBlob() throws SQLException
+    {
+        if(_createBlob == null)
+        {
+            throw new SQLException("Unsupported method.");
+        }
+        else
+        {
+            try
+            {
+                return (Blob)_createBlob.invoke(connection, new Object[] {});
+            }
+            catch(Exception e)
+            {
+                Throwable cause = e.getCause();
+                if (cause == null)
+                {
+                    cause = e;
+                }
+                if(cause instanceof SQLException)
+                {
+                    throw (SQLException)cause;
+                }
+                else
+                {
+                    throw new SQLException(cause);
+                }
+            }
+        }
+    }
+
+    public NClob createNClob() throws SQLException
+    {
+        if(_createNClob == null)
+        {
+            throw new SQLException("Unsupported method.");
+        }   
+        else
+        {
+            try
+            {
+                return (NClob)_createNClob.invoke(connection, new Object[] {});
+            }
+            catch(Exception e)
+            {
+                Throwable cause = e.getCause();
+                if (cause == null)
+                {
+                    cause = e;
+                }
+                if(cause instanceof SQLException)
+                {
+                    throw (SQLException)cause;
+                }
+                else
+                {
+                    throw new SQLException(cause);
+                }
+            }
+        }
+    }
+
+    public SQLXML createSQLXML() throws SQLException
+    {
+        if(_createSQLXML == null)
+        {
+            throw new SQLException("Unsupported method.");
+        }
+        else
+        {
+            try
+            {
+                return (SQLXML)_createSQLXML.invoke(connection, new Object[] {});
+            }
+            catch(Exception e)
+            {
+                Throwable cause = e.getCause();
+                if (cause == null)
+                {
+                    cause = e;
+                }
+                if(cause instanceof SQLException)
+                {
+                    throw (SQLException)cause;
+                }
+                else
+                {
+                    throw new SQLException(cause);
+                }
+            }
+        }
+    }
+
+    public boolean isValid(int timeout) throws SQLException
+    {
+        if(_isValid == null)
+        {
+            throw new SQLException("Unsupported method.");
+        }
+        else
+        {
+            try
+            {
+                return (Boolean)_isValid.invoke(connection, new Object[] {timeout});
+            }
+            catch(Exception e)
+            {
+                Throwable cause = e.getCause();
+                if (cause == null)
+                {
+                    cause = e;
+                }
+                if(cause instanceof SQLException)
+                {
+                    throw (SQLException)cause;
+                }
+                else
+                {
+                    throw new SQLException(cause);
+                }
+            }
+        }
+    }
+
+    public void setClientInfo(String name,String value)
+    {
+        if(_setClientInfo == null)
+        {
+            throw new RuntimeException("Unsupported method.");
+        }
+        else
+        {
+            try
+            {
+                _setClientInfo.invoke(connection, new Object[] {name,value});
+            }
+            catch(Exception e)
+            {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    public void setClientInfo(Properties properties)
+    {
+        if(_setClientInfo2 == null)
+        {
+            throw new RuntimeException("Unsupported method.");
+        }
+        else
+        {
+            try
+            {
+                _setClientInfo2.invoke(connection, new Object[] {properties});
+            }
+            catch(Exception e)
+            {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    public Properties getClientInfo() throws SQLException
+    {
+        if(_getClientInfo == null)
+        {
+            throw new SQLException("Unsupported method.");
+        }
+        else
+        {
+            try
+            {
+                return (Properties)_getClientInfo.invoke(connection, new Object[] {});
+            }
+            catch(Exception e)
+            {
+                Throwable cause = e.getCause();
+                if (cause == null)
+                {
+                    cause = e;
+                }
+                if(cause instanceof SQLException)
+                {
+                    throw (SQLException)cause;
+                }
+                else
+                {
+                    throw new SQLException(cause);
+                }
+            }
+        }
+    }
+
+    public String getClientInfo(String name) throws SQLException
+    {
+        if(_getClientInfo2 == null)
+        {
+            throw new SQLException("Unsupported method.");
+        }
+        else
+        {
+            try
+            {
+                return (String)_getClientInfo2.invoke(connection, new Object[] {name});
+            }
+            catch(Exception e)
+            {
+                Throwable cause = e.getCause();
+                if (cause == null)
+                {
+                    cause = e;
+                }
+                if(cause instanceof SQLException)
+                {
+                    throw (SQLException)cause;
+                }
+                else
+                {
+                    throw new SQLException(cause);
+                }
+            }
+        }
+    }
+
+    public Array createArrayOf(String typeName, Object[] elements) throws SQLException
+    {
+        if(_createArrayOf == null)
+        {
+            throw new SQLException("Unsupported method.");
+        }
+        else
+        {
+            try
+            {
+                return (Array)_createArrayOf.invoke(connection, new Object[] {typeName,elements});
+            }
+            catch(Exception e)
+            {
+                Throwable cause = e.getCause();
+                if (cause == null)
+                {
+                    cause = e;
+                }
+                if(cause instanceof SQLException)
+                {
+                    throw (SQLException)cause;
+                }
+                else
+                {
+                    throw new SQLException(cause);
+                }
+            }
+        }
+    }
+
+    public Struct createStruct(String typeName, Object[] attributes) throws SQLException
+    {
+        if(_createStruct == null)
+        {
+            throw new SQLException("Unsupported method.");
+        }
+        else
+        {
+            try
+            {
+                return (Struct)_createStruct.invoke(connection, new Object[] {typeName,attributes});
+            }
+            catch(Exception e)
+            {
+                Throwable cause = e.getCause();
+                if (cause == null)
+                {
+                    cause = e;
+                }
+                if(cause instanceof SQLException)
+                {
+                    throw (SQLException)cause;
+                }
+                else
+                {
+                    throw new SQLException(cause);
+                }
+            }
+        }
+    }
+
+    public boolean isWrapperFor(Class<?> iface) throws SQLException
+    {
+        throw new SQLException("Unsupported method.");
+    }
+
+    public <T> T unwrap(Class<T> iface) throws SQLException
+    {
+        throw new SQLException("Unsupported method.");
+    }
+}

Added: velocity/sandbox/velosurf/src/java/org/apache/velocity/velosurf/sql/Database.java
URL: http://svn.apache.org/viewvc/velocity/sandbox/velosurf/src/java/org/apache/velocity/velosurf/sql/Database.java?rev=1298906&view=auto
==============================================================================
--- velocity/sandbox/velosurf/src/java/org/apache/velocity/velosurf/sql/Database.java (added)
+++ velocity/sandbox/velosurf/src/java/org/apache/velocity/velosurf/sql/Database.java Fri Mar  9 16:23:25 2012
@@ -0,0 +1,1148 @@
+/*
+ * Copyright 2003 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.velocity.velosurf.sql;
+
+import java.io.*;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.util.*;
+import org.apache.velocity.velosurf.cache.Cache;
+import org.apache.velocity.velosurf.context.RowIterator;
+import org.apache.velocity.velosurf.model.Attribute;
+import org.apache.velocity.velosurf.model.Entity;
+import org.apache.velocity.velosurf.model.Action;
+import org.apache.velocity.velosurf.util.Logger;
+import org.apache.velocity.velosurf.util.LineWriterOutputStream;
+import org.apache.velocity.velosurf.util.Cryptograph;
+import org.apache.velocity.velosurf.util.XIncludeResolver;
+import org.apache.velocity.velosurf.util.UserContext;
+
+/**
+ * This class encapsulates  a connection to the database and contains all the stuff relative to it.
+ *
+ *  <p>To get a new instance, client classes should call one of the getInstance static methods.</p>
+ *
+ *  @author <a href=mailto:claude.brisson@gmail.com>Claude Brisson</a>
+ *
+ */
+public class Database
+{
+    /**
+     * Builds a new connection.
+     */
+    private Database()
+    {
+    }
+
+    /**
+     * Builds a new connection.
+     *
+     * @param user user name
+     * @param password password
+     * @param url database url
+     * @param driver driver java class name
+     * @param schema schema name to use
+     * @exception SQLException thrown by the database engine
+     */
+    private Database(String user,String password,String url,String driver,String schema) throws SQLException
+    {
+        open(user,password,url,driver,schema);
+    }
+
+    /**
+     * Get a unique Database from connection params.
+     *
+     * @param user user name
+     * @param password password
+     * @param url database url
+     * @exception SQLException thrown by the database engine
+     * @return a new connection
+     */
+    public static Database getInstance(String user,String password,String url) throws SQLException
+    {
+        return getInstance(user,password,url,null,null);
+    }
+
+    /**
+     * Get a unique Database from connection params.
+     *
+     * @param user user name
+     * @param password password
+     * @param url database url
+     * @param driver driver java class name
+     * @exception SQLException thrown by the database engine
+     * @return a new connection
+     */
+    public static Database getInstance(String user,String password,String url,String driver) throws SQLException
+    {
+        return getInstance(user,password,url,driver,null);
+    }
+
+    /**
+     * Get a unique Database from connection params.
+     *
+     * @param user user name
+     * @param password password
+     * @param url database url
+     * @param driver driver java class name
+     * @param schema schema
+     * @exception SQLException thrown by the database engine
+     * @return a new connection
+     */
+    public static Database getInstance(String user,String password,String url,String driver,String schema) throws SQLException
+    {
+        Integer hash = Integer.valueOf((user==null?0:user.hashCode()) ^ (password==null?0:password.hashCode()) ^ url.hashCode() ^ (driver==null?0:driver.hashCode()) ^ (schema==null?0:schema.hashCode()) );
+        Database instance = (Database)connectionsByParams.get(hash);
+        if (instance == null)
+        {
+            instance = new Database(user,password,url,driver,schema);
+            connectionsByParams.put(hash,instance);
+        }
+        return instance;
+    }
+
+    /**
+     * Get a unique Database from config filename.
+     *
+     * @param configFilename config filename
+     * @exception SQLException thrown by the database engine
+     * @return a new connection
+     */
+    public static Database getInstance(String configFilename) throws SQLException,FileNotFoundException,IOException
+    {
+        Integer hash = Integer.valueOf(configFilename.hashCode());
+        Database instance = (Database)connectionsByConfigFile.get(hash);
+        if (instance == null)
+        {
+            String base = null;
+            configFilename = configFilename.replace('\\','/');
+            int i = configFilename.lastIndexOf('/');
+            if (i == -1)
+            {
+                base = ".";
+            }
+            else
+            {
+                base = configFilename.substring(0,i);
+            }
+            instance = getInstance(new FileInputStream(configFilename),new XIncludeResolver(base));
+            connectionsByConfigFile.put(hash,instance);
+        }
+        return instance;
+    }
+
+    /**
+     * Get a new connection.
+     * @param config config filename
+     * @exception SQLException thrown by the database engine
+     * @return a new connection
+     */
+    public static Database getInstance(InputStream config) throws SQLException
+    {
+        return Database.getInstance(config,null);
+    }
+
+    /**
+     * Get a new connection.
+     * @param config config filename
+     * @exception SQLException thrown by the database engine
+     * @return a new connection
+     */
+    public static Database getInstance(InputStream config,XIncludeResolver xincludeResolver) throws SQLException
+    {
+        Database instance = new Database();
+        instance.readConfigFile(config,xincludeResolver);
+        instance.initCryptograph();
+        instance.connect();
+        instance.getReverseEngineer().readMetaData();
+
+        // startup action
+        Action startup = instance.getRootEntity().getAction("startup");
+        if (startup != null)
+        {
+            startup.perform(null);
+        }
+
+        return instance;
+    }
+
+    /**
+     * Open the connection.
+     *
+     * @param user user name
+     * @param password password
+     * @param url database url
+     * @param driver driver java class name
+     * @param schema schema name
+     * @exception SQLException thrown by the database engine
+     */
+    private void open(String user,String password,String url,String driver,String schema) throws SQLException
+    {
+
+        this.user = user;
+        this.password = password;
+        this.url = url;
+        this.schema = schema;
+        driverClass = driver;
+        initCryptograph();
+        connect();
+        getReverseEngineer().readMetaData();        
+    }
+
+    /**
+     * Connect the database.
+     *
+     * @throws SQLException
+     */
+    private void connect() throws SQLException
+    {
+        Logger.info("opening database "+url+" for user "+user+(schema == null?"":" using schema "+schema));
+
+        loadDriver();
+
+        connectionPool = new ConnectionPool(url,user,password,schema,driverInfo,true,minConnections,maxConnections);
+        transactionConnectionPool = new ConnectionPool(url,user,password,schema,driverInfo,false,1,maxConnections);
+
+        statementPool = new StatementPool(connectionPool,checkConnections,checkInterval);
+        preparedStatementPool = new PreparedStatementPool(connectionPool,checkConnections,checkInterval);
+
+        transactionStatementPool = new StatementPool(transactionConnectionPool,checkConnections,checkInterval);
+        transactionPreparedStatementPool = new PreparedStatementPool(transactionConnectionPool,checkConnections,checkInterval);
+
+        if(rootEntity == null)
+        {
+            Entity root = new Entity(this,"velosurf.root",false,Cache.NO_CACHE);
+            addEntity(root);
+        }        
+    }
+
+    /**
+     * Set the read-only state.
+     * @param readOnly read-only state
+     */
+    public void setReadOnly(boolean readOnly)
+    {
+        this.readOnly = readOnly;
+    }
+
+    /**
+     * Set the caching method.
+     * @param cachingMethod caching method
+     */
+    public void setCaching(int cachingMethod)
+    {
+        caching = cachingMethod;
+    }
+
+    /** Set the database user.
+     *
+     * @param user user name.
+     */
+    public void setUser(String user)
+    {
+        this.user = user;
+    }
+
+    /**
+     * Set the database password.
+     * @param password password
+     */
+    public void setPassword(String password)
+    {
+       this.password = password;
+    }
+
+    /**
+     * Set the database URL.
+     * @param url database url
+     */
+    public void setURL(String url)
+    {
+        this.url = url;
+    }
+
+    /**
+     * Set driver class.
+     * @param driverClass driver class
+     */
+    public void setDriver(String driverClass)
+    {
+        this.driverClass = driverClass;
+    }
+
+    /**
+     * Set schema name.
+     * @param schema schema name
+     */
+    public void setSchema(String schema)
+    {
+        this.schema = schema;
+        if(this.schema != null)
+        {
+            // share entities
+            sharedCatalog.put(getMagicNumber(this.schema),entities);
+        }
+    }
+
+    /**
+     * Set minimum number of connections.
+     * @param minConnections minimum number of connections
+     */
+    public void setMinConnections(int minConnections)
+    {
+        this.minConnections = minConnections;
+    }
+
+    /**
+     * Set the maximum number of connections.
+     * @param maxConnections maximum number of connections
+     */
+    public void setMaxConnections(int maxConnections)
+    {
+        this.maxConnections = maxConnections;
+    }
+
+    /**
+     * Set the encryption seed.
+     * @param seed encryption seed
+     */
+    public void setSeed(String seed)
+    {
+        this.seed = seed;
+    }
+
+    /**
+     * Set the case policy.
+     * Possible values are CASE_SENSITIVE, CASE_LOWERCASE and CASE_UPPERCASE.
+     * @param caseSensivity case policy
+     */
+    public void setCase(int caseSensivity)
+    {
+        this.caseSensivity = caseSensivity;
+    }
+
+    /**
+     * Set whether or not connections are to be checked or not
+     * @param checkConnections read-only check or not
+     */
+    public void setCheckConnections(boolean checkConnections)
+    {
+        this.checkConnections = checkConnections;
+    }
+
+    /**
+     * Set the minimum check interval (in milliseconds)
+     * - connections are only checked when their last use 
+     * is older than this interval.
+     * @param checkInterval
+     */
+    public void setCheckInterval(long checkInterval)
+    {
+        this.checkInterval = checkInterval;
+    }
+
+    /**
+     * oad the appropriate driver.
+     */
+    @SuppressWarnings("deprecation") protected void loadDriver()
+    {
+        if (driverLoaded)
+        {
+            return;
+        }
+
+        if (Logger.getLogLevel() == Logger.TRACE_ID)
+        {
+            /* Initialize log */
+            DriverManager.setLogWriter(Logger.getWriter()); /* -> doesn't work with jdbc 1.0 drivers
+             *   so use the deprecated form
+             *  TODO: detect driver jdbc conformance
+             */
+/*            if(Logger.getLogLevel() <= Logger.DEBUG_ID) {
+Logger.debug("setting driver manager log");
+                DriverManager.setLogStream(new PrintStream(new LineWriterOutputStream(Logger.getWriter())));
+            }*/
+        }
+
+        /* driver behaviour */
+        driverInfo = DriverInfo.getDriverInfo(url,driverClass);
+
+        reverseEngineer.setDriverInfo(driverInfo);
+
+        if (driverClass!=null)
+        {
+            try
+            {
+		Logger.debug("loading class "+driverClass);
+                Class.forName(driverClass);
+                driverLoaded = true;
+            }
+            catch (Exception e)
+            {
+              Logger.log(e);
+            }
+        }
+        else if (driverInfo != null)
+        {
+            // try to load one of the known drivers
+            String[] drivers = driverInfo.getDrivers();
+            for (int i=0;i<drivers.length;i++)
+            try
+            {
+                Class.forName(drivers[i]);
+                driverLoaded = true;
+                break;
+            }
+            catch (Exception e) {}
+        }
+    }
+
+    /**
+     * Init cryptograph.
+     *
+     */
+    protected void initCryptograph()
+    {
+        if (cryptograph != null) return;
+        // to initialize the cryptograph, we need a chunk of user-provided bytes
+        // they must be persistent, so that urls that use encrypted params remain valid
+        // => use the database url if null
+        if (seed == null)
+        {
+            seed = url;
+        }
+        try
+        {
+            cryptograph = (Cryptograph)Class.forName("org.apache.velocity.velosurf.util.DESCryptograph").getDeclaredConstructor(new Class[] {}).newInstance(new Object[] {});
+            cryptograph.init(seed);
+        }
+        catch(Exception e)
+        {
+            Logger.error("Cannot initialize the cryptograph");
+            Logger.log(e);
+        }
+    }
+
+    /**
+     * Get reverse engineer.
+     * @return reverse engineer.
+     */
+    public ReverseEngineer getReverseEngineer()
+    {
+        return reverseEngineer;
+    }
+
+    /**
+     * Issue a query.
+     *
+     * @param query an SQL query
+     * @return the resulting RowIterator
+     */
+    public RowIterator query(String query) throws SQLException
+    {
+        return query(query,null);
+    }
+
+    /**
+     * Issue a query, knowing the resulting entity.
+     *
+     * @param query an SQL query
+     * @param entity the resulting entity
+     * @return return the resulting row iterator
+     */
+    public RowIterator query(String query,Entity entity) throws SQLException
+    {
+        PooledSimpleStatement statement = null;
+        statement=statementPool.getStatement();
+        return statement.query(query,entity == null ? getRootEntity() : entity);
+    }
+
+    /**
+     * Evaluate a query to a scalar.
+     *
+     * @param query an sql query
+     * @return the resulting scalar
+     */
+    public Object evaluate(String query)
+    {
+        PooledSimpleStatement statement = null;
+        try
+        {
+            statement=statementPool.getStatement();
+            return statement.evaluate(query);
+        }
+        catch (SQLException sqle)
+        {
+            Logger.log(sqle);
+            return null;
+        }
+    }
+
+    /**
+     * Prepare a query.
+     *
+     * @param query an sql query
+     * @return the pooled prepared statement corresponding to the query
+     */
+    public PooledPreparedStatement prepare(String query)
+    {
+        PooledPreparedStatement statement = null;
+        try
+        {
+            statement = preparedStatementPool.getPreparedStatement(query);
+            return statement;
+        }
+        catch (SQLException sqle)
+        {
+            Logger.log(sqle);
+            return null;
+        }
+    }
+
+    /**
+     * Prepare a query which is part of a transaction.
+     *
+     * @param query an sql query
+     * @return the prepared statemenet corresponding to the query
+     */
+    public PooledPreparedStatement transactionPrepare(String query)
+    {
+        PooledPreparedStatement statement = null;
+        try
+        {
+            statement = transactionPreparedStatementPool.getPreparedStatement(query);
+            return statement;
+        }
+        catch (SQLException sqle)
+        {
+            Logger.log(sqle);
+            return null;
+        }
+    }
+
+    /**
+     * Issue an update query.
+     *
+     * @param query an sql query
+     * @return the number of affected rows
+     */
+    public int update(String query)
+    {
+        try
+        {
+            PooledSimpleStatement statement = statementPool.getStatement();
+            return statement.update(query);
+        }
+        catch (SQLException sqle)
+        {
+            Logger.log(sqle);
+            return -1;
+        }
+    }
+
+    /**
+     * Issue an update query that is part of a transaction.
+     *
+     * @param query an sql query
+     * @return the number of affected rows
+     */
+    public int transactionUpdate(String query)
+    {
+        try
+        {
+            PooledSimpleStatement statement = transactionStatementPool.getStatement();
+            return statement.update(query);
+        }
+        catch (SQLException sqle)
+        {
+            Logger.log(sqle);
+            return -1;
+        }
+    }
+
+    /**
+     * Close the connection.
+     *
+     * @exception SQLException thrown by the database engine
+     */
+    public void close() throws SQLException
+    {
+        connectionPool.clear();
+        connectionPool = null;
+        transactionConnectionPool.clear();
+        transactionConnectionPool = null;
+        statementPool.clear();
+        statementPool = null;
+        transactionStatementPool.clear();
+        transactionStatementPool = null;
+        preparedStatementPool.clear();
+        preparedStatementPool = null;
+        transactionPreparedStatementPool.clear();
+        transactionPreparedStatementPool = null;
+    }
+
+    /**
+     * Display statistics about the statements pools.
+     */
+    public void displayStats()
+    {
+        System.out.println("DB statistics:");
+        int [] normalStats = statementPool.getUsageStats();
+        int [] preparedStats = preparedStatementPool.getUsageStats();
+        System.out.println("\tsimple statements   - "+normalStats[0]+" free statements out of "+normalStats[1]);
+        System.out.println("\tprepared statements - "+preparedStats[0]+" free statements out of "+preparedStats[1]);
+    }
+
+    /**
+     * Get a jdbc connection.
+     *
+     * @return a jdbc connection wrapper (which extends java.sql.Connection)
+     */
+    public ConnectionWrapper getConnection() throws SQLException
+    {
+        ConnectionWrapper c = connectionPool.getConnection();
+        c.setReadOnly(readOnly);
+        return c;
+    }
+
+    /**
+     * Get the underlying jdbc connection used for transactions, and mark it right away as busy.
+     *
+     * @return a jdbc connection wrapper (which extends java.sql.Connection)
+     */
+    public synchronized ConnectionWrapper getTransactionConnection() throws SQLException {
+        ConnectionWrapper ret = transactionConnectionPool.getConnection();
+        ret.setReadOnly(readOnly);
+        ret.enterBusyState();
+        return ret;
+    }
+
+    /**
+     * Read model configuration from the given input stream.
+     *
+     * @param config input stream on the config file
+     */
+    private void readConfigFile(InputStream config,XIncludeResolver xincludeResolver)
+    {
+        try
+        {
+            new ConfigLoader(this,xincludeResolver).loadConfig(config);
+        }
+        catch (Exception e)
+        {
+            Logger.error("could not load model!");
+            Logger.log(e);
+        }
+    }
+
+    /**
+     * Changes to lowercase or uppercase if needed.
+     *
+     * @param identifier
+     * @return changed identifier
+     */
+    public String adaptCase(String identifier)
+    {
+        if (identifier == null)
+        {
+            return null;
+        }
+        String ret;
+        switch(caseSensivity)
+        {
+            case CASE_SENSITIVE:
+            case CASE_UNKNOWN:
+                ret = identifier;
+                break;
+            case UPPERCASE:
+                ret = identifier.toUpperCase();
+                break;
+            case LOWERCASE:
+                ret = identifier.toLowerCase();
+                break;
+            default:
+                Logger.error("bad case-sensivity!");
+                ret = identifier;
+        }
+        return ret;
+    }
+
+    /**
+     * Add a new entity.
+     *
+     * @param entity entity to add
+     */
+    public void addEntity(Entity entity)
+    {
+        String name = entity.getName();
+        Entity previous = entities.put(adaptCase(name),entity);
+        if (previous != null)
+        {
+            Logger.warn("replacing an existing entity with a new one ("+name+")");
+        }
+        if(name.equals("velosurf.root"))
+        {
+            /* this is the root entity */
+            rootEntity = entity;
+        }
+    }
+
+    /**
+     * Get root entity.
+     * @return root entity
+     */
+    public Entity getRootEntity()
+    {
+        return rootEntity;
+    }
+
+    /**
+     * Get a named entity or creeate it if it doesn't exist
+     *
+     * @param name name of an entity
+     * @return the named entity
+     */
+    public Entity getEntityCreate(String name)
+    {
+        Entity entity = getEntity(name);
+        if (entity == null)
+        {
+            Logger.trace("Created entity: "+name);
+            entity = new Entity(this,name,readOnly,caching);
+            entities.put(adaptCase(name),entity);
+        }
+        return entity;
+    }
+
+    /**
+     * Get an existing entity.
+     *
+     * @param name the name of an entity
+     * @return the named entity
+     */
+    public Entity getEntity(String name)
+    {
+        int i;
+        Entity entity=(Entity)entities.get(adaptCase(name));
+        if (entity == null && name != null && (i=name.indexOf('.')) != -1)
+        {
+            // imported from another schema ?
+            String schema = name.substring(0,i);
+            name = name.substring(i+1);
+            Map external = (Map)sharedCatalog.get(getMagicNumber(schema));
+            if (external != null)
+            {
+                entity = (Entity)external.get(name);
+            }
+        }
+        return entity;
+    }
+
+    /**
+     * Entities map getter.
+     *
+     * @return entities map
+     */
+    public Map<String,Entity> getEntities()
+    {
+        return entities;
+    }
+
+    /**
+     * Get a root attribute.
+     *
+     * @param name name of an attribute
+     * @return the named attribute
+     */
+    public Attribute getAttribute(String name)
+    {
+        return rootEntity.getAttribute(adaptCase(name));
+    }
+
+    /**
+     * Get a root action.
+     *
+     * @param name name of an attribute
+     * @return the named attribute
+     */
+    public Action getAction(String name)
+    {
+        return rootEntity.getAction(adaptCase(name));
+    }
+
+    /**
+     * Obfuscate the given value.
+     * @param value value to obfuscate
+     *
+     * @return obfuscated value
+     */
+    public String obfuscate(Object value)
+    {
+        if (value == null)
+        {
+            return null;
+        }
+        String encoded = cryptograph.encrypt(value.toString());
+
+        // we want to avoid some characters fot HTTP GET
+        encoded = encoded.replace('=','$');
+        encoded = encoded.replace('/','_');
+        encoded = encoded.replace('+','-');
+
+        return encoded;
+    }
+
+    /**
+     * De-obfuscate the given value.
+     * @param value value to de-obfuscate
+     *
+     * @return obfuscated value
+     */
+    public String deobfuscate(Object value)
+    {
+        if (value == null)
+        {
+            return null;
+        }
+
+        String ret = value.toString();
+
+        // recover exact encoded string
+        ret = ret.replace('$','=');
+        ret = ret.replace('_','/');
+        ret = ret.replace('-','+');
+
+        ret = cryptograph.decrypt(ret);
+
+        if (ret == null)
+        {
+            Logger.error("deobfuscation of value '"+value+"' failed!");
+            return null;
+        }
+
+        return ret;
+    }
+
+    /**
+     * Get database driver infos.
+     * @return the database vendor
+     */
+    public DriverInfo getDriverInfo()
+    {
+        return driverInfo;
+    }
+
+    /**
+     * Get database case-sensivity policy.
+     *
+     * @return case-sensivity
+     */
+    public int getCaseSensivity()
+    {
+        return caseSensivity;
+    }
+
+    /**
+     * Get the integer key used to share schema entities among instances.
+     */
+    private Integer getMagicNumber(String schema)
+    {
+        // url is not checked for now because for some databases, the schema is part of the url.
+        return Integer.valueOf((user/*+url*/+schema).hashCode());
+    }
+
+    /**
+     * Get the schema.
+     * @return the schema
+     */
+    public String getSchema()
+    {
+        return schema;
+    }
+
+    /**
+     * Database user.
+     */
+    private String user = null;
+
+    /**
+     * Database user's password.
+     */
+    private String password = null;
+
+    /**
+     * Database url.
+     */
+    private String url = null;
+
+    /**
+     * Schema.
+     */
+    private String schema = null;
+
+    /**
+     * Whether the JDBC driver has been loaded.
+     */
+    private boolean driverLoaded = false;
+
+    /**
+     * Driver class name, if provided in the config file.
+     */
+    private String driverClass = null;
+
+    /**
+     * Pool of connections.
+     */
+    private ConnectionPool connectionPool = null;
+
+    /**
+     * Min connections.
+     */
+    private int minConnections = 1; // applies to connectionPool (min connections is always 1 for transactionConnectionPool)
+
+    /**
+     * Max connections.
+     */
+    private int maxConnections = 50; // applies to connectionPool and transactionConnectionPool
+
+    /**
+     * Pool of connections for transactions.
+     */
+    private ConnectionPool transactionConnectionPool = null;
+
+    /**
+     * Pool of statements.
+     */
+    private StatementPool statementPool = null;
+
+    /**
+     * Pool of statements for transactions.
+     */
+    private StatementPool transactionStatementPool = null;
+
+    /**
+     * Pool of prepared statements.
+     */
+    private PreparedStatementPool preparedStatementPool = null;
+
+    /**
+     * Pool of prepared statements for transactions.
+     */
+    private PreparedStatementPool transactionPreparedStatementPool = null;
+
+    /**
+     * Default access mode.
+     */
+    private boolean readOnly = true;
+
+    /**
+     * Default connections checking
+     */
+    private boolean checkConnections = true;
+
+    /**
+     * Default check interval
+     */
+    private long checkInterval = 1000 * 60 * 10; // 10 minutes by default
+
+    /**
+     * Default caching mode.
+     */
+    private int caching = Cache.NO_CACHE;
+
+    /**
+     * Map name->entity.
+     */
+    private Map<String,Entity> entities = new HashMap<String,Entity>();
+
+    /**
+     * Root entity that contains all root attributes and actions.
+     */
+    private Entity rootEntity = null;
+
+    /**
+     * Driver infos (database vendor specific).
+     */
+    private DriverInfo driverInfo = null;
+
+    /**
+     * Random seed used to initialize the cryptograph.
+     */
+    private String seed = null;
+
+    /**
+     * Cryptograph used to encrypt/decrypt database ids.
+     */
+    private Cryptograph cryptograph = null;
+
+    /**
+     * 'unknown' case-sensitive policy.
+     */
+    public static final int CASE_UNKNOWN = 0;
+
+    /**
+     * 'sensitive' case-sensitive policy.
+     */
+    public static final int CASE_SENSITIVE = 1;
+
+    /**
+     * 'uppercase' case-sensitive policy.
+     */
+    public static final int UPPERCASE = 2;
+
+    /**
+     * 'lowercase' case-sensitive policy.
+     */
+    public static final int LOWERCASE = 3;
+
+    /**
+     * Case-sensivity.
+     */
+    private int caseSensivity = CASE_UNKNOWN;
+
+    /**
+     * Case-sensivity for context.
+     */
+    private static int contextCase = CASE_SENSITIVE;
+
+    /* context case implemented as a system property for now...
+     *TODO: check also other model configuration realms or use model.xml
+     */
+    static
+    {
+        String contextCase = System.getProperty("velosurf.case");
+        if (contextCase != null)
+        {
+            if ("uppercase".equals(contextCase))
+            {
+                Database.contextCase = UPPERCASE;
+            }
+            else if ("lowercase".equals(contextCase))
+            {
+                Database.contextCase = LOWERCASE;
+            }
+            else if("sensitive".equals(contextCase))
+            {
+                Database.contextCase = CASE_SENSITIVE;
+	    }
+            else
+            {
+                Logger.error("system property 'velosurf.case' should be 'lowercase', 'uppercase' or 'sensitive'");
+            }
+        }
+    }
+
+    /**
+     * Adapt a string to the context case.
+     *
+     * @param str string to adapt
+     * @return adapted string
+     */
+    public static String adaptContextCase(String str)
+    {
+        if(str == null)
+        {
+            return null;
+        }
+        switch(contextCase)
+        {
+            case LOWERCASE:
+                return str.toLowerCase();
+            case UPPERCASE:
+                return str.toUpperCase();
+  	    case CASE_SENSITIVE:
+	        return str;
+            default:
+                Logger.error("unknown context case policy!");
+                return str;
+        }
+    }
+
+    /**
+     * Set this database user context (thread local)
+     *  @param userContext user context
+     */
+    public void setUserContext(UserContext userContext)
+    {
+        this.userContext.set(userContext);
+    }
+
+    /**
+     * Get this database user context (thread local)
+     *
+     * @return the thread local user context
+     */
+    public UserContext getUserContext()
+    {
+        UserContext ret = userContext.get();
+        if (ret == null)
+        {
+            /* create one */
+            ret = new UserContext();
+            userContext.set(ret);
+        }
+        return ret;
+    }
+
+    /**
+     * Set error message.
+     */
+    public void setError(String errormsg)
+    {
+        getUserContext().setError(errormsg);
+    }
+
+    /**
+     * Map parameters -> instances.
+     */
+    private static Map<Integer,Database> connectionsByParams = new HashMap<Integer,Database>();
+
+    /**
+     * Map config files -> instances.
+     */
+    private static Map<Integer,Database> connectionsByConfigFile = new HashMap<Integer,Database>();
+
+    /**
+     * <p>Shared catalog, to share entities among instances.</p>
+     *
+     * <p>Key is hashcode of (name+password+url+schema), value is an entities map.</p>
+     */
+    private static Map<Integer,Map<String,Entity>> sharedCatalog = new HashMap<Integer,Map<String,Entity>>();
+
+    /**
+     * Reverse engineer.
+     */
+    private ReverseEngineer reverseEngineer = new ReverseEngineer(this);
+
+    /**
+     * Thread-local user context.
+     */
+    private ThreadLocal<UserContext> userContext = new ThreadLocal<UserContext>();
+
+    /**
+     * Driver specific value filter
+     *
+     * @param value value to be filtered
+     * @return filtered value
+     */
+    public Object filterParam(Object value)
+    {
+        return driverInfo.filterValue(value);
+    }
+}