jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From marti...@apache.org
Subject svn commit: r811081 - in /jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core: journal/ persistence/bundle/ util/db/
Date Thu, 03 Sep 2009 19:03:57 GMT
Author: martijnh
Date: Thu Sep  3 19:03:56 2009
New Revision: 811081

URL: http://svn.apache.org/viewvc?rev=811081&view=rev
Log:
JCR-1456 Database connection pooling

* Refactored o.a.j.core.journal package to use the new db uitility classes and thus connection
pooling

Modified:
    jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/DatabaseJournal.java
    jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/MSSqlDatabaseJournal.java
    jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/OracleDatabaseJournal.java
    jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/BundleDbPersistenceManager.java
    jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/db/CheckSchemaOperation.java
    jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/db/ConnectionHelper.java
    jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/db/DbUtility.java

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/DatabaseJournal.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/DatabaseJournal.java?rev=811081&r1=811080&r2=811081&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/DatabaseJournal.java
(original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/DatabaseJournal.java
Thu Sep  3 19:03:56 2009
@@ -16,26 +16,26 @@
  */
 package org.apache.jackrabbit.core.journal;
 
+import org.apache.commons.io.IOUtils;
+import org.apache.jackrabbit.core.util.db.CheckSchemaOperation;
 import org.apache.jackrabbit.core.util.db.ConnectionFactory;
+import org.apache.jackrabbit.core.util.db.ConnectionHelper;
+import org.apache.jackrabbit.core.util.db.DbUtility;
+import org.apache.jackrabbit.core.util.db.StreamWrapper;
 import org.apache.jackrabbit.spi.commons.namespace.NamespaceResolver;
-import org.apache.jackrabbit.util.Text;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
 import java.io.File;
-import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
-import java.sql.Connection;
-import java.sql.DatabaseMetaData;
-import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
-import java.sql.Statement;
 import java.util.Calendar;
 
-import javax.jcr.RepositoryException;
+import javax.sql.DataSource;
 
 /**
  * Database-based journal implementation. Stores records inside a database table named
@@ -77,17 +77,6 @@
 public class DatabaseJournal extends AbstractJournal {
 
     /**
-     * Schema object prefix.
-     */
-    private static final String SCHEMA_OBJECT_PREFIX_VARIABLE =
-            "${schemaObjectPrefix}";
-
-    /**
-     * Default DDL script name.
-     */
-    private static final String DEFAULT_DDL_NAME = "default.ddl";
-
-    /**
      * Default journal table name, used to check schema completeness.
      */
     private static final String DEFAULT_JOURNAL_TABLE = "JOURNAL";
@@ -98,11 +87,6 @@
     private static final String LOCAL_REVISIONS_TABLE = "LOCAL_REVISIONS";
 
     /**
-     * Default reconnect delay in milliseconds.
-     */
-    private static final long DEFAULT_RECONNECT_DELAY_MS = 10000;
-
-    /**
      * Logger.
      */
     private static Logger log = LoggerFactory.getLogger(DatabaseJournal.class);
@@ -133,59 +117,9 @@
     private String password;
 
     /**
-     * Reconnect delay in milliseconds, bean property.
-     */
-    private long reconnectDelayMs;
-
-    /**
-     * JDBC Connection used.
-     */
-    private Connection connection;
-
-    /**
-     * Statement returning all revisions within a range.
-     */
-    private PreparedStatement selectRevisionsStmt;
-
-    /**
-     * Statement updating the global revision.
-     */
-    private PreparedStatement updateGlobalStmt;
-
-    /**
-     * Statement returning the global revision.
-     */
-    private PreparedStatement selectGlobalStmt;
-
-    /**
-     * Statement appending a new record.
-     */
-    private PreparedStatement insertRevisionStmt;
-
-    /**
-     * Statement returning the minimum of the local revisions.
-     */
-    private PreparedStatement selectMinLocalRevisionStmt;
-
-    /**
-     * Statement removing a set of revisions with from the journal table.
-     */
-    private PreparedStatement cleanRevisionStmt;
-
-    /**
-     * Statement returning the local revision of this cluster node.
-     */
-    private PreparedStatement getLocalRevisionStmt;
-    
-    /**
-     * Statement for inserting the local revision of this cluster node. 
-     */
-    private PreparedStatement insertLocalRevisionStmt;
-    
-    /**
-     * Statement for updating the local revision of this cluster node. 
+     * The connection helper
      */
-    private PreparedStatement updateLocalRevisionStmt;
+    private ConnectionHelper conHelper;
 
     /**
      * Auto commit level.
@@ -198,11 +132,6 @@
     private long lockedRevision;
 
     /**
-     * Next time in milliseconds to reattempt connecting to the database.
-     */
-    private long reconnectTimeMs;
-
-    /**
      * Whether the revision table janitor thread is enabled.
      */
     private boolean janitorEnabled = false;
@@ -231,6 +160,7 @@
      * The instance that manages the local revision.
      */
     private DatabaseRevision databaseRevision;
+
     /**
      * SQL statement returning all revisions within a range.
      */
@@ -281,6 +211,11 @@
      */
     protected String schemaObjectPrefix;
 
+    public DatabaseJournal() {
+        databaseType = "default";
+        schemaObjectPrefix = "";
+    }
+
     /**
      * {@inheritDoc}
      */
@@ -289,25 +224,22 @@
 
         super.init(id, resolver);
 
-        // Provide valid defaults for arguments
-        if (schemaObjectPrefix == null) {
-            schemaObjectPrefix = "";
-        }
-        if (reconnectDelayMs == 0) {
-            reconnectDelayMs = DEFAULT_RECONNECT_DELAY_MS;
-        }
-
         init();
 
         try {
-            connection = getConnection();
-            setAutoCommit(connection, true);
-            checkSchema();
+            conHelper = createConnectionHelper(ConnectionFactory.getDataSource(getDriver(),
getUrl(), getUser(),
+                getPassword()));
+
+            // make sure schemaObjectPrefix consists of legal name characters only
+            schemaObjectPrefix = conHelper.prepareDbIdentifier(schemaObjectPrefix);
+
+            // check if schema objects exist and create them if necessary
+            createCheckSchemaOperation().run();
+
             // Make sure that the LOCAL_REVISIONS table exists (see JCR-1087)
             checkLocalRevisionSchema();
 
             buildSQLStatements();
-            prepareStatements();
             initInstanceRevisionAndJanitor();
         } catch (Exception e) {
             String msg = "Unable to create connection.";
@@ -317,6 +249,32 @@
     }
 
     /**
+     * This method is called from the {@link #init(String, NamespaceResolver)} method of
this class and
+     * returns a {@link ConnectionHelper} instance which is assigned to the {@code conHelper}
field.
+     * Subclasses may override it to return a specialized connection helper.
+     * 
+     * @param dataSrc the {@link DataSource} of this persistence manager
+     * @return a {@link ConnectionHelper}
+     * @throws Exception on error
+     */
+    protected ConnectionHelper createConnectionHelper(DataSource dataSrc) throws Exception
{
+        return new ConnectionHelper(dataSrc);
+    }
+
+    /**
+     * This method is called from {@link #init(String, NamespaceResolver)} after the
+     * {@link #createConnectionHelper(DataSource)} method, and returns a default {@link CheckSchemaOperation}.
+     * Subclasses can overrride this implementation to get a customized implementation.
+     * 
+     * @return a new {@link CheckSchemaOperation} instance
+     */
+    protected CheckSchemaOperation createCheckSchemaOperation() {
+        InputStream in = DatabaseJournal.class.getResourceAsStream(databaseType + ".ddl");
+        return new CheckSchemaOperation(conHelper, in, schemaObjectPrefix + DEFAULT_JOURNAL_TABLE).addVariableReplacement(
+            CheckSchemaOperation.SCHEMA_OBJECT_PREFIX_VARIABLE, schemaObjectPrefix);
+    }
+
+    /**
      * Completes initialization of this database journal. Base implementation
      * checks whether the required bean properties <code>driver</code> and
      * <code>url</code> have been specified and optionally deduces a valid
@@ -344,13 +302,6 @@
                 throw new JournalException(msg);
             }
         }
-
-        try {
-            Class.forName(driver);
-        } catch (ClassNotFoundException e) {
-            String msg = "Unable to load driver class.";
-            throw new JournalException(msg, e);
-        }
     }
 
     /**
@@ -393,27 +344,6 @@
     }
 
     /**
-     * Creates a new database connection. This method is called inside
-     * {@link #init(String, org.apache.jackrabbit.spi.commons.namespace.NamespaceResolver)}
or
-     * when a connection has been dropped and must be reacquired. Base
-     * implementation uses <code>java.sql.DriverManager</code> to get the
-     * connection. May be overridden by subclasses.
-     *
-     * @see #init()
-     * @return new connection
-     * @throws JournalException if the driver could not be loaded
-     * @throws SQLException if the connection could not be established
-     */
-    protected Connection getConnection() throws SQLException, JournalException {
-        try {
-            return ConnectionFactory.getConnection(driver, url, user, password);
-        } catch (RepositoryException e) {
-            String msg = "Unable to load driver class.";
-            throw new JournalException(msg, e);
-        }
-    }
-
-    /**
      * Derive a database type from a JDBC connection URL. This simply treats the given URL
      * as delimeted by colons and takes the 2nd field.
      *
@@ -435,24 +365,12 @@
     /**
      * {@inheritDoc}
      */
-    public RecordIterator getRecords(long startRevision)
-            throws JournalException {
-
+    public RecordIterator getRecords(long startRevision) throws JournalException {
         try {
-            checkConnection();
-
-            selectRevisionsStmt.clearParameters();
-            selectRevisionsStmt.clearWarnings();
-            selectRevisionsStmt.setLong(1, startRevision);
-            selectRevisionsStmt.execute();
-
-            return new DatabaseRecordIterator(
-                    selectRevisionsStmt.getResultSet(), getResolver(), getNamePathResolver());
+            return new DatabaseRecordIterator(conHelper.exec(selectRevisionsStmtSQL, new
Object[]{new Long(
+                    startRevision)}, false, 0), getResolver(), getNamePathResolver());
         } catch (SQLException e) {
-            close(true);
-
-            String msg = "Unable to return record iterator.";
-            throw new JournalException(msg, e);
+            throw new JournalException("Unable to return record iterator.", e);
         }
     }
 
@@ -461,20 +379,10 @@
      */
     public RecordIterator getRecords() throws JournalException {
         try {
-            checkConnection();
-
-            selectRevisionsStmt.clearParameters();
-            selectRevisionsStmt.clearWarnings();
-            selectRevisionsStmt.setLong(1, Long.MIN_VALUE);
-            selectRevisionsStmt.execute();
-
-            return new DatabaseRecordIterator(
-                    selectRevisionsStmt.getResultSet(), getResolver(), getNamePathResolver());
+            return new DatabaseRecordIterator(conHelper.exec(selectRevisionsStmtSQL, new
Object[]{new Long(
+                    Long.MIN_VALUE)}, false, 0), getResolver(), getNamePathResolver());
         } catch (SQLException e) {
-            close(true);
-
-            String msg = "Unable to return record iterator.";
-            throw new JournalException(msg, e);
+            throw new JournalException("Unable to return record iterator.", e);
         }
     }
 
@@ -491,27 +399,16 @@
         boolean succeeded = false;
 
         try {
-            checkConnection();
             if (lockLevel++ == 0) {
-                setAutoCommit(connection, false);
+                conHelper.startBatch();
             }
         } catch (SQLException e) {
-            close(true);
-
-            String msg = "Unable to set autocommit to false.";
-            throw new JournalException(msg, e);
+            throw new JournalException("Unable to set autocommit to false.", e);
         }
 
         try {
-            updateGlobalStmt.clearParameters();
-            updateGlobalStmt.clearWarnings();
-            updateGlobalStmt.execute();
-
-            selectGlobalStmt.clearParameters();
-            selectGlobalStmt.clearWarnings();
-            selectGlobalStmt.execute();
-
-            rs = selectGlobalStmt.getResultSet();
+            conHelper.exec(updateGlobalStmtSQL);
+            rs = conHelper.exec(selectGlobalStmtSQL, null, false, 0);
             if (!rs.next()) {
                  throw new JournalException("No revision available.");
             }
@@ -519,12 +416,9 @@
             succeeded = true;
 
         } catch (SQLException e) {
-            close(true);
-
-            String msg = "Unable to lock global revision table.";
-            throw new JournalException(msg, e);
+            throw new JournalException("Unable to lock global revision table.", e);
         } finally {
-            close(rs);
+            DbUtility.close(rs);
             if (!succeeded) {
                 doUnlock(false);
             }
@@ -536,12 +430,11 @@
      */
     protected void doUnlock(boolean successful) {
         if (--lockLevel == 0) {
-            if (successful) {
-                commit(connection);
-            } else {
-                rollback(connection);
+            try {
+                conHelper.endBatch(successful);;
+            } catch (SQLException e) {
+                log.error("failed to end batch", e);
             }
-            setAutoCommit(connection, true);
         }
     }
 
@@ -563,19 +456,10 @@
             throws JournalException {
 
         try {
-            checkConnection();
-
-            insertRevisionStmt.clearParameters();
-            insertRevisionStmt.clearWarnings();
-            insertRevisionStmt.setLong(1, record.getRevision());
-            insertRevisionStmt.setString(2, getId());
-            insertRevisionStmt.setString(3, record.getProducerId());
-            insertRevisionStmt.setBinaryStream(4, in, length);
-            insertRevisionStmt.execute();
+            conHelper.exec(insertRevisionStmtSQL, record.getRevision(), getId(), record.getProducerId(),
+                new StreamWrapper(in, length));
 
         } catch (SQLException e) {
-            close(true);
-
             String msg = "Unable to append revision " + lockedRevision + ".";
             throw new JournalException(msg, e);
         }
@@ -585,226 +469,6 @@
      * {@inheritDoc}
      */
     public void close() {
-        close(false);
-    }
-
-    /**
-     * Close database connections and statements. If closing was due to an
-     * error that occurred, calculates the next time a reconnect should
-     * be attempted.
-     *
-     * @param failure whether closing is due to a failure
-     */
-    private void close(boolean failure) {
-        if (failure) {
-            reconnectTimeMs = System.currentTimeMillis() + reconnectDelayMs;
-        }
-
-        close(selectRevisionsStmt);
-        selectRevisionsStmt = null;
-        close(updateGlobalStmt);
-        updateGlobalStmt = null;
-        close(selectGlobalStmt);
-        selectGlobalStmt = null;
-        close(insertRevisionStmt);
-        insertRevisionStmt = null;
-        close(selectMinLocalRevisionStmt);
-        selectMinLocalRevisionStmt = null;
-        close(cleanRevisionStmt);
-        cleanRevisionStmt = null;
-        close(getLocalRevisionStmt);
-        getLocalRevisionStmt = null;
-        close(insertLocalRevisionStmt);
-        insertLocalRevisionStmt = null;
-        close(updateLocalRevisionStmt);
-        updateLocalRevisionStmt = null;
-        
-        close(connection);
-        connection = null;
-    }
-
-    /**
-     * Set the autocommit flag of a connection. Does nothing if the connection
-     * passed is <code>null</code> and logs any exception as warning.
-     *
-     * @param connection database connection
-     * @param autoCommit where to enable or disable autocommit
-     */
-    private static void setAutoCommit(Connection connection, boolean autoCommit) {
-        if (connection != null) {
-            try {
-                // JCR-1013: Setter may fail on a managed connection
-                if (connection.getAutoCommit() != autoCommit) {
-                    connection.setAutoCommit(autoCommit);
-                }
-            } catch (SQLException e) {
-                String msg = "Unable to set autocommit flag to " + autoCommit;
-                log.warn(msg, e);
-            }
-        }
-    }
-
-    /**
-     * Commit a connection. Does nothing if the connection passed is
-     * <code>null</code> and logs any exception as warning.
-     *
-     * @param connection connection.
-     */
-    private static void commit(Connection connection) {
-        if (connection != null) {
-            try {
-                connection.commit();
-            } catch (SQLException e) {
-                String msg = "Error while committing connection: " + e.getMessage();
-                log.warn(msg);
-            }
-        }
-    }
-
-    /**
-     * Rollback a connection. Does nothing if the connection passed is
-     * <code>null</code> and logs any exception as warning.
-     *
-     * @param connection connection.
-     */
-    private static void rollback(Connection connection) {
-        if (connection != null) {
-            try {
-                connection.rollback();
-            } catch (SQLException e) {
-                String msg = "Error while rolling back connection: " + e.getMessage();
-                log.warn(msg);
-            }
-        }
-    }
-
-    /**
-     * Closes the given database connection. Does nothing if the connection
-     * passed is <code>null</code> and logs any exception as warning.
-     *
-     * @param connection database connection
-     */
-    private static void close(Connection connection) {
-        if (connection != null) {
-            try {
-                connection.close();
-            } catch (SQLException e) {
-                String msg = "Error while closing connection: " + e.getMessage();
-                log.warn(msg);
-            }
-        }
-    }
-
-    /**
-     * Close some input stream.  Does nothing if the input stream
-     * passed is <code>null</code> and logs any exception as warning.
-     *
-     * @param in input stream, may be <code>null</code>.
-     */
-    private static void close(InputStream in) {
-        if (in != null) {
-            try {
-                in.close();
-            } catch (IOException e) {
-                String msg = "Error while closing input stream: " + e.getMessage();
-                log.warn(msg);
-            }
-        }
-    }
-
-    /**
-     * Close some statement.  Does nothing if the statement
-     * passed is <code>null</code> and logs any exception as warning.
-     *
-     * @param stmt statement, may be <code>null</code>.
-     */
-    private static void close(Statement stmt) {
-        if (stmt != null) {
-            try {
-                stmt.close();
-            } catch (SQLException e) {
-                String msg = "Error while closing statement: " + e.getMessage();
-                log.warn(msg);
-            }
-        }
-    }
-
-    /**
-     * Close some resultset.  Does nothing if the result set
-     * passed is <code>null</code> and logs any exception as warning.
-     *
-     * @param rs resultset, may be <code>null</code>.
-     */
-    private static void close(ResultSet rs) {
-        if (rs != null) {
-            try {
-                rs.close();
-            } catch (SQLException e) {
-                String msg = "Error while closing result set: " + e.getMessage();
-                log.warn(msg);
-            }
-        }
-    }
-
-    /**
-     * Checks the currently established connection. If the connection no longer
-     * exists, waits until at least <code>reconnectTimeMs</code> have passed
-     * since the error occurred and recreates the connection.
-     */
-    private void checkConnection() throws SQLException, JournalException {
-        if (connection == null) {
-            long delayMs = reconnectTimeMs - System.currentTimeMillis();
-            if (delayMs > 0) {
-                try {
-                    Thread.sleep(delayMs);
-                } catch (InterruptedException e) {
-                    /* ignore */
-                }
-            }
-            connection = getConnection();
-            prepareStatements();
-        }
-    }
-
-    /**
-     * Checks if the required schema objects exist and creates them if they
-     * don't exist yet.
-     *
-     * @throws Exception if an error occurs
-     */
-    private void checkSchema() throws Exception {
-        if (!tableExists(connection.getMetaData(), schemaObjectPrefix + DEFAULT_JOURNAL_TABLE))
{            // read ddl from resources
-            InputStream in = DatabaseJournal.class.getResourceAsStream(databaseType + ".ddl");
-            if (in == null) {
-                String msg = "No database-specific DDL found: '" + databaseType + ".ddl"
-                    + "', falling back to '" + DEFAULT_DDL_NAME + "'.";
-                log.info(msg);
-                in = DatabaseJournal.class.getResourceAsStream(DEFAULT_DDL_NAME);
-                if (in == null) {
-                    msg = "Unable to load '" + DEFAULT_DDL_NAME + "'.";
-                    throw new JournalException(msg);
-                }
-            }
-            BufferedReader reader = new BufferedReader(new InputStreamReader(in));
-            Statement stmt = connection.createStatement();
-            try {
-                String sql = reader.readLine();
-                while (sql != null) {
-                    // Skip comments and empty lines
-                    if (!sql.startsWith("#") && sql.length() > 0) {
-                        // replace prefix variable
-                        sql = createSchemaSQL(sql);
-                        // execute sql stmt
-                        stmt.executeUpdate(sql);
-                    }
-                    // read next sql stmt
-                    sql = reader.readLine();
-                }
-            } finally {
-                close(in);
-                close(stmt);
-            }
-        }
     }
 
     /**
@@ -814,78 +478,28 @@
      * @throws Exception if an error occurs
      */
     private void checkLocalRevisionSchema() throws Exception {
-        if (!tableExists(connection.getMetaData(), schemaObjectPrefix + LOCAL_REVISIONS_TABLE))
{
-            log.info("Creating " + schemaObjectPrefix + LOCAL_REVISIONS_TABLE + " table");
-            // read ddl from resources
-            InputStream in = DatabaseJournal.class.getResourceAsStream(databaseType + ".ddl");
-            if (in == null) {
-                String msg = "No database-specific DDL found: '" + databaseType + ".ddl"
+
-                        "', falling back to '" + DEFAULT_DDL_NAME + "'.";
-                log.info(msg);
-                in = DatabaseJournal.class.getResourceAsStream(DEFAULT_DDL_NAME);
-                if (in == null) {
-                    msg = "Unable to load '" + DEFAULT_DDL_NAME + "'.";
-                    throw new JournalException(msg);
-                }
-            }
+        InputStream localRevisionDDLStream = null;
+        InputStream in = DatabaseJournal.class.getResourceAsStream(databaseType + ".ddl");
+        try {
             BufferedReader reader = new BufferedReader(new InputStreamReader(in));
-            Statement stmt = connection.createStatement();
-            try {
-                String sql = reader.readLine();
-                while (sql != null) {
-                    // Skip comments and empty lines, and select only the statement
-                    // to create the LOCAL_REVISIONS table.
-                    if (!sql.startsWith("#") && sql.length() > 0
-                            && sql.indexOf(LOCAL_REVISIONS_TABLE) != -1) {
-                        // replace prefix variable
-                        sql = createSchemaSQL(sql);
-                        // execute sql stmt
-                        stmt.executeUpdate(sql);
-                    }
-                    // read next sql stmt
-                    sql = reader.readLine();
+            String sql = reader.readLine();
+            while (sql != null) {
+                // Skip comments and empty lines, and select only the statement to create
the LOCAL_REVISIONS
+                // table.
+                if (!sql.startsWith("#") && sql.length() > 0 && sql.indexOf(LOCAL_REVISIONS_TABLE)
!= -1) {
+                    localRevisionDDLStream = new ByteArrayInputStream(sql.getBytes());
+                    break;
                 }
-            } finally {
-                close(in);
-                close(stmt);
+                // read next sql stmt
+                sql = reader.readLine();
             }
-        }
-    }
-
-    /**
-     * Checks whether the required table(s) exist in the schema. May be
-     * overridden by subclasses to allow different table names.
-     *
-     * @param metaData database meta data
-     * @return <code>true</code> if the schema exists
-     * @throws SQLException if an SQL error occurs
-     */
-    protected boolean tableExists(DatabaseMetaData metaData, String tableName)
-        throws SQLException {
-
-        if (metaData.storesLowerCaseIdentifiers()) {
-            tableName = tableName.toLowerCase();
-        } else if (metaData.storesUpperCaseIdentifiers()) {
-            tableName = tableName.toUpperCase();
-        }
-
-        ResultSet rs = metaData.getTables(null, null, tableName, null);
-
-        try {
-            return rs.next();
         } finally {
-            rs.close();
+            IOUtils.closeQuietly(in);
         }
-    }
-
-    /**
-     * Creates an SQL statement for schema creation by variable substitution.
-     *
-     * @param sql a SQL string which may contain variables to substitute
-     * @return a valid SQL string
-     */
-    protected String createSchemaSQL(String sql) {
-        return Text.replace(sql, SCHEMA_OBJECT_PREFIX_VARIABLE, schemaObjectPrefix);
+        // Run the schema check for the single table
+        new CheckSchemaOperation(conHelper, localRevisionDDLStream, schemaObjectPrefix
+                + LOCAL_REVISIONS_TABLE).addVariableReplacement(
+            CheckSchemaOperation.SCHEMA_OBJECT_PREFIX_VARIABLE, schemaObjectPrefix).run();
     }
 
     /**
@@ -922,23 +536,6 @@
     }
 
     /**
-     * Prepares the SQL statements.
-     *
-     * @throws SQLException if an error occurs
-     */
-    private void prepareStatements() throws SQLException {
-        selectRevisionsStmt = connection.prepareStatement(selectRevisionsStmtSQL);
-        updateGlobalStmt = connection.prepareStatement(updateGlobalStmtSQL);
-        selectGlobalStmt = connection.prepareStatement(selectGlobalStmtSQL);
-        insertRevisionStmt = connection.prepareStatement(insertRevisionStmtSQL);
-        selectMinLocalRevisionStmt = connection.prepareStatement(selectMinLocalRevisionStmtSQL);
-        cleanRevisionStmt = connection.prepareStatement(cleanRevisionStmtSQL);
-        getLocalRevisionStmt = connection.prepareStatement(getLocalRevisionStmtSQL);
-        insertLocalRevisionStmt = connection.prepareStatement(insertLocalRevisionStmtSQL);
-        updateLocalRevisionStmt = connection.prepareStatement(updateLocalRevisionStmtSQL);
-    }
-
-    /**
      * Bean getters
      */
     public String getDriver() {
@@ -981,10 +578,6 @@
         return password;
     }
 
-    public long getReconnectDelayMs() {
-        return reconnectDelayMs;
-    }
-
     public boolean getJanitorEnabled() {
         return janitorEnabled;
     }
@@ -1040,10 +633,6 @@
         this.password = password;
     }
 
-    public void setReconnectDelayMs(long reconnectDelayMs) {
-        this.reconnectDelayMs = reconnectDelayMs;
-    }
-
     public void setJanitorEnabled(boolean enabled) {
         this.janitorEnabled = enabled;
     }
@@ -1089,29 +678,18 @@
          * @throws JournalException on error
          */
         protected synchronized long init(long revision) throws JournalException {
+            ResultSet rs = null;
             try {
-                // Check whether the connection is available
-                checkConnection();
-
                 // Check whether there is an entry in the database.
-                getLocalRevisionStmt.clearParameters();
-                getLocalRevisionStmt.clearWarnings();
-                getLocalRevisionStmt.setString(1, getId());
-                getLocalRevisionStmt.execute();
-                ResultSet rs = getLocalRevisionStmt.getResultSet();
+                rs = conHelper.exec(getLocalRevisionStmtSQL, new Object[]{getId()}, false,
0);
                 boolean exists = rs.next();
                 if (exists) {
                     revision = rs.getLong(1);
                 }
-                rs.close();
 
                 // Insert the given revision in the database
                 if (!exists) {
-                    insertLocalRevisionStmt.clearParameters();
-                    insertLocalRevisionStmt.clearWarnings();
-                    insertLocalRevisionStmt.setLong(1, revision);
-                    insertLocalRevisionStmt.setString(2, getId());
-                    insertLocalRevisionStmt.execute();
+                    conHelper.exec(insertLocalRevisionStmtSQL, revision, getId());
                 }
 
                 // Set the cached local revision and return
@@ -1121,8 +699,9 @@
 
             } catch (SQLException e) {
                 log.warn("Failed to initialize local revision.", e);
-                DatabaseJournal.this.close(true);
                 throw new JournalException("Failed to initialize local revision", e);
+            } finally {
+                DbUtility.close(rs);
             }
         }
 
@@ -1147,25 +726,18 @@
 
             // Update the cached value and the table with local revisions.
             try {
-                // Check whether the connection is available
-                checkConnection();
-                updateLocalRevisionStmt.clearParameters();
-                updateLocalRevisionStmt.clearWarnings();
-                updateLocalRevisionStmt.setLong(1, localRevision);
-                updateLocalRevisionStmt.setString(2, getId());
-                updateLocalRevisionStmt.execute();
+                conHelper.exec(updateLocalRevisionStmtSQL, localRevision, getId());
                 this.localRevision = localRevision;
             } catch (SQLException e) {
                 log.warn("Failed to update local revision.", e);
-                DatabaseJournal.this.close(true);
+                throw new JournalException("Failed to update local revision.", e);
             }
         }
         
         /**
          * {@inheritDoc}
          */
-        public synchronized void close() {
-            // Do nothing: The statements are closed in DatabaseJournal.close()
+        public void close() {
         }
     }
 
@@ -1200,35 +772,25 @@
          * Cleans old revisions from the clustering table.
          */
         protected void cleanUpOldRevisions() {
+            ResultSet rs = null;
             try {
                 long minRevision = 0;
-
-                // Check whether the connection is available
-                checkConnection();
-
-                // Find the minimal local revision
-                selectMinLocalRevisionStmt.clearParameters();
-                selectMinLocalRevisionStmt.clearWarnings();
-                selectMinLocalRevisionStmt.execute();
-                ResultSet rs = selectMinLocalRevisionStmt.getResultSet();
+                rs = conHelper.exec(selectMinLocalRevisionStmtSQL, null, false, 0);
                 boolean cleanUp = rs.next();
                 if (cleanUp) {
                     minRevision = rs.getLong(1);
                 }
-                rs.close();
 
                 // Clean up if necessary:
                 if (cleanUp) {
-                    cleanRevisionStmt.clearParameters();
-                    cleanRevisionStmt.clearWarnings();
-                    cleanRevisionStmt.setLong(1, minRevision);
-                    cleanRevisionStmt.execute();
+                    conHelper.exec(cleanRevisionStmtSQL, minRevision);
                     log.info("Cleaned old revisions up to revision " + minRevision + ".");
                 }
 
             } catch (Exception e) {
                 log.warn("Failed to clean up old revisions.", e);
-                close(true);
+            } finally {
+                DbUtility.close(rs);
             }
         }
     }

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/MSSqlDatabaseJournal.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/MSSqlDatabaseJournal.java?rev=811081&r1=811080&r2=811081&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/MSSqlDatabaseJournal.java
(original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/MSSqlDatabaseJournal.java
Thu Sep  3 19:03:56 2009
@@ -16,7 +16,7 @@
  */
 package org.apache.jackrabbit.core.journal;
 
-import org.apache.jackrabbit.util.Text;
+import org.apache.jackrabbit.core.util.db.CheckSchemaOperation;
 
 /**
  * It has the following property in addition to those of the DatabaseJournal:
@@ -35,7 +35,16 @@
      */
     public MSSqlDatabaseJournal() {
         setDriver("com.microsoft.sqlserver.jdbc.SQLServerDriver");
-        setSchema("mssql");
+        setDatabaseType("mssql");
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected CheckSchemaOperation createCheckSchemaOperation() {
+        return super.createCheckSchemaOperation().addVariableReplacement(
+            CheckSchemaOperation.TABLE_SPACE_VARIABLE, tableSpace);
     }
 
     /**
@@ -57,13 +66,4 @@
             this.tableSpace = "";
         }
     }
-
-    /**
-     * {@inheritDoc}
-     */
-    protected String createSchemaSQL(String sql) {
-        return Text.replace(
-                super.createSchemaSQL(sql), "${tableSpace}", tableSpace);
-    }
-
 }

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/OracleDatabaseJournal.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/OracleDatabaseJournal.java?rev=811081&r1=811080&r2=811081&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/OracleDatabaseJournal.java
(original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/OracleDatabaseJournal.java
Thu Sep  3 19:03:56 2009
@@ -16,11 +16,11 @@
  */
 package org.apache.jackrabbit.core.journal;
 
-import java.sql.DatabaseMetaData;
-import java.sql.ResultSet;
-import java.sql.SQLException;
+import javax.sql.DataSource;
 
-import org.apache.jackrabbit.util.Text;
+import org.apache.jackrabbit.core.util.db.CheckSchemaOperation;
+import org.apache.jackrabbit.core.util.db.ConnectionHelper;
+import org.apache.jackrabbit.core.util.db.OracleConnectionHelper;
 
 /**
  * It has the following property in addition to those of the DatabaseJournal:
@@ -35,61 +35,44 @@
         "${tableSpace}";
 
     /** the Oracle table space to use */
-    protected String tableSpace;
+    protected String tableSpace = "";
 
     /**
-     * Returns the configured Oracle table space.
-     * @return the configured Oracle table space.
+     * {@inheritDoc}
      */
-    public String getTableSpace() {
-        return tableSpace;
+    @Override
+    protected ConnectionHelper createConnectionHelper(DataSource dataSrc) throws Exception
{
+        OracleConnectionHelper helper = new OracleConnectionHelper(dataSrc);
+        helper.init();
+        return helper;
     }
 
     /**
-     * Sets the Oracle table space.
-     * @param tableSpace the Oracle table space.
+     * {@inheritDoc}
      */
-    public void setTableSpace(String tableSpace) {
-        if (tableSpace != null) {
-            this.tableSpace = tableSpace.trim();
-        } else {
-            this.tableSpace = null;
-        }
+    @Override
+    protected CheckSchemaOperation createCheckSchemaOperation() {
+        return super.createCheckSchemaOperation().addVariableReplacement(
+            CheckSchemaOperation.TABLE_SPACE_VARIABLE, tableSpace);
     }
 
     /**
-     * {@inheritDoc}
+     * Returns the configured Oracle table space.
+     * @return the configured Oracle table space.
      */
-    protected String createSchemaSQL(String sql) {
-        // replace the schemaObjectPrefix
-        sql = super.createSchemaSQL(sql);
-        // set the tablespace if it is defined
-        String tspace;
-        if (tableSpace == null || "".equals(tableSpace)) {
-            tspace = "";
-        } else {
-            tspace = "tablespace " + tableSpace;
-        }
-        return Text.replace(sql, TABLE_SPACE_VARIABLE, tspace).trim();
+    public String getTableSpace() {
+        return tableSpace;
     }
 
     /**
-     * {@inheritDoc}
+     * Sets the Oracle table space.
+     * @param tableSpace the Oracle table space.
      */
-    protected boolean tableExists(DatabaseMetaData metaData, String tableName) throws SQLException
{
-        if (metaData.storesLowerCaseIdentifiers()) {
-            tableName = tableName.toLowerCase();
-        } else if (metaData.storesUpperCaseIdentifiers()) {
-            tableName = tableName.toUpperCase();
-        }
-
-        String userName = metaData.getUserName();
-        ResultSet rs = metaData.getTables(null, userName, tableName, null);
-
-        try {
-            return rs.next();
-        } finally {
-            rs.close();
+    public void setTableSpace(String tableSpace) {
+        if (tableSpace != null && tableSpace.trim().length() > 0) {
+            this.tableSpace = "tablespace " + tableSpace.trim();
+        } else {
+            this.tableSpace = "";
         }
     }
 }

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/BundleDbPersistenceManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/BundleDbPersistenceManager.java?rev=811081&r1=811080&r2=811081&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/BundleDbPersistenceManager.java
(original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/BundleDbPersistenceManager.java
Thu Sep  3 19:03:56 2009
@@ -396,10 +396,16 @@
         return errorHandling.toString();
     }
 
+    /**
+     * @deprecated
+     */
     public void setBlockOnConnectionLoss(String block) {
         this.blockOnConnectionLoss = Boolean.valueOf(block).booleanValue();
     }
 
+    /**
+     * @deprecated
+     */
     public String getBlockOnConnectionLoss() {
         return Boolean.toString(blockOnConnectionLoss);
     }
@@ -426,24 +432,22 @@
      * Basically wraps a JDBC transaction around super.store().
      */
     public synchronized void store(ChangeLog changeLog) throws ItemStateException {
-        // FIXME: rethink blockOnConnectionLoss property
-        boolean transactionStarted = false;
-        boolean transactionEnded = false;
         try {
             conHelper.startBatch();
-            transactionStarted = true;
             super.store(changeLog);
-            transactionEnded = true;
             conHelper.endBatch(true);
-        } catch (Throwable th) {
+        } catch (SQLException e) {
+            // Either startBatch or stopBatch threw it: either way the
+            // transaction was not persisted and no action needs to be taken.
+            throw new ItemStateException(e.getMessage(), e);
+        } catch (ItemStateException e) {
+            // store call threw it: we need to cancel the transaction
             try {
-                if (transactionStarted && !transactionEnded) {
-                    conHelper.endBatch(false);
-                }
-            } catch (SQLException e) {
-                logException("rollback failed", e);
+                conHelper.endBatch(false);
+            } catch (SQLException e2) {
+                DbUtility.logException("rollback failed", e2);
             }
-            throw new ItemStateException(th.getMessage(), th);
+            throw e;
         }
     }
 
@@ -1216,20 +1220,6 @@
     }
 
     /**
-     * logs an sql exception
-     * @param message the message
-     * @param e the exception
-     */
-    protected void logException(String message, SQLException e) {
-        if (message != null) {
-            log.error(message);
-        }
-        log.error("       Reason: " + e.getMessage());
-        log.error("   State/Code: " + e.getSQLState() + "/" + e.getErrorCode());
-        log.debug("   dump:", e);
-    }
-
-    /**
      * @inheritDoc
      */
     public String toString() {

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/db/CheckSchemaOperation.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/db/CheckSchemaOperation.java?rev=811081&r1=811080&r2=811081&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/db/CheckSchemaOperation.java
(original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/db/CheckSchemaOperation.java
Thu Sep  3 19:03:56 2009
@@ -47,7 +47,8 @@
 
     /**
      * @param connectionhelper the connection helper
-     * @param ddlStream the stream of the DDL to use to create the schema if necessary (closed
by this method)
+     * @param ddlStream the stream of the DDL to use to create the schema if necessary (closed
by the
+     *            {@link #run()} method)
      * @param tableName the name of the table to use for the schema-existence-check
      */
     public CheckSchemaOperation(ConnectionHelper connectionhelper, InputStream ddlStream,
String tableName) {

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/db/ConnectionHelper.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/db/ConnectionHelper.java?rev=811081&r1=811080&r2=811081&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/db/ConnectionHelper.java
(original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/db/ConnectionHelper.java
Thu Sep  3 19:03:56 2009
@@ -26,27 +26,9 @@
 import javax.sql.DataSource;
 
 /**
- * This class provides convenience methods to execute SQL statements.
- * 
- * Responsibilities of this class.
- * <ul>
- * <li>Provide a means to execute SQL statements in isolation.</li>
- * <li>Provide a means to execute a JDBC transaction.</li>
- * </ul>
- * This class has two states: it is either in <i>batch mode</i> or it is not.
Batch mode affects three
- * methods:
- * 
- * <p/>
- * 
- * Behavior on an {@code SQLException} on the {@link #exec(String, Object[])},
- * {@link #exec(String, Object[], boolean, int)} and {@link #update(String, Object[])} methods
is as follows:
- * <ul>
- * <li>If a batch is in progress then the {@code SQLException} is thrown.
- * <li>If in non-batch mode, then the {@code SQLException} is caught and the SQL statement
is re-executed once
- * with a new connection from the {@link DataSource}.</li>
- * </ul>
- * 
- * TODO: retry if exec fails in non-batch mode (last bullet above)
+ * This class provides convenience methods to execute SQL statements. They can be either
executed in isolation
+ * or with in the context of a JDBC transaction (use the {@link #startBatch()} and {@link
#endBatch(boolean)}
+ * methods for this).
  */
 public class ConnectionHelper {
 

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/db/DbUtility.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/db/DbUtility.java?rev=811081&r1=811080&r2=811081&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/db/DbUtility.java
(original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/db/DbUtility.java
Thu Sep  3 19:03:56 2009
@@ -87,10 +87,12 @@
      * @param message the message
      * @param se the exception
      */
-    public static void logException(String message, SQLException se) {
-        LOG.error(message + ", reason: " + se.getMessage() + ", state/code: " + se.getSQLState()
+ "/"
-                + se.getErrorCode());
-        LOG.debug("   dump:", se);
+    public static void logException(String message, SQLException e) {
+        if (message != null) {
+            LOG.error(message);
+        }
+        LOG.error("       Reason: " + e.getMessage());
+        LOG.error("   State/Code: " + e.getSQLState() + "/" + e.getErrorCode());
+        LOG.debug("   dump:", e);
     }
-
 }



Mime
View raw message