Return-Path: Delivered-To: apmail-jackrabbit-commits-archive@www.apache.org Received: (qmail 1525 invoked from network); 26 Oct 2006 15:27:42 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 26 Oct 2006 15:27:42 -0000 Received: (qmail 86417 invoked by uid 500); 26 Oct 2006 15:27:53 -0000 Delivered-To: apmail-jackrabbit-commits-archive@jackrabbit.apache.org Received: (qmail 86389 invoked by uid 500); 26 Oct 2006 15:27:53 -0000 Mailing-List: contact commits-help@jackrabbit.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@jackrabbit.apache.org Delivered-To: mailing list commits@jackrabbit.apache.org Received: (qmail 86380 invoked by uid 99); 26 Oct 2006 15:27:52 -0000 Received: from herse.apache.org (HELO herse.apache.org) (140.211.11.133) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 26 Oct 2006 08:27:52 -0700 X-ASF-Spam-Status: No, hits=0.6 required=10.0 tests=NO_REAL_NAME,UPPERCASE_25_50 X-Spam-Check-By: apache.org Received-SPF: pass (herse.apache.org: local policy) Received: from [140.211.11.3] (HELO eris.apache.org) (140.211.11.3) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 26 Oct 2006 08:27:38 -0700 Received: by eris.apache.org (Postfix, from userid 65534) id 1CB781A9846; Thu, 26 Oct 2006 08:27:18 -0700 (PDT) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r468036 - in /jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/fs/db: DB2FileSystem.java DatabaseFileSystem.java OracleFileSystem.java Date: Thu, 26 Oct 2006 15:27:17 -0000 To: commits@jackrabbit.apache.org From: stefan@apache.org X-Mailer: svnmailer-1.1.0 Message-Id: <20061026152718.1CB781A9846@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: stefan Date: Thu Oct 26 08:27:17 2006 New Revision: 468036 URL: http://svn.apache.org/viewvc?view=rev&rev=468036 Log: JCR-603: OracleFileSystem can't handle empty files Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/fs/db/DB2FileSystem.java jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/fs/db/DatabaseFileSystem.java jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/fs/db/OracleFileSystem.java Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/fs/db/DB2FileSystem.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/fs/db/DB2FileSystem.java?view=diff&rev=468036&r1=468035&r2=468036 ============================================================================== --- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/fs/db/DB2FileSystem.java (original) +++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/fs/db/DB2FileSystem.java Thu Oct 26 08:27:17 2006 @@ -62,7 +62,7 @@ initialized = false; } - //-----------------------------------------------< DbFileSystem overrides > + //-----------------------------------------< DatabaseFileSystem overrides > /** * {@inheritDoc} *

Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/fs/db/DatabaseFileSystem.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/fs/db/DatabaseFileSystem.java?view=diff&rev=468036&r1=468035&r2=468036 ============================================================================== --- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/fs/db/DatabaseFileSystem.java (original) +++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/fs/db/DatabaseFileSystem.java Thu Oct 26 08:27:17 2006 @@ -160,107 +160,6 @@ //-----------------------------------------------------------< FileSystem > /** - * initializes the prepared statements and returns the list of them. please - * note, that this list is used to close the statements in the {@link #close()} - * call. - * - * @return the list of prepared statements. - * @throws SQLException - */ - protected List initPreparedStatements() throws SQLException { - List stmts = new LinkedList(); - stmts.add(insertFileStmt = con.prepareStatement("insert into " - + schemaObjectPrefix + "FSENTRY " - + "(FSENTRY_PATH, FSENTRY_NAME, FSENTRY_DATA, " - + "FSENTRY_LASTMOD, FSENTRY_LENGTH) " - + "values (?, ?, ?, ?, ?)")); - - stmts.add(insertFolderStmt = con.prepareStatement("insert into " - + schemaObjectPrefix + "FSENTRY " - + "(FSENTRY_PATH, FSENTRY_NAME, FSENTRY_LASTMOD, FSENTRY_LENGTH) " - + "values (?, ?, ?, 0)")); - - stmts.add(updateDataStmt = con.prepareStatement("update " - + schemaObjectPrefix + "FSENTRY " - + "set FSENTRY_DATA = ?, FSENTRY_LASTMOD = ?, FSENTRY_LENGTH = ? " - + "where FSENTRY_PATH = ? and FSENTRY_NAME = ? " - + "and FSENTRY_DATA is not null")); - - stmts.add(updateLastModifiedStmt = con.prepareStatement("update " - + schemaObjectPrefix + "FSENTRY set FSENTRY_LASTMOD = ? " - + "where FSENTRY_PATH = ? and FSENTRY_NAME = ? " - + "and FSENTRY_DATA is not null")); - - stmts.add(selectExistStmt = con.prepareStatement("select 1 from " - + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? " - + "and FSENTRY_NAME = ?")); - - stmts.add(selectFileExistStmt = con.prepareStatement("select 1 from " - + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? " - + "and FSENTRY_NAME = ? and FSENTRY_DATA is not null")); - - stmts.add(selectFolderExistStmt = con.prepareStatement("select 1 from " - + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? " - + "and FSENTRY_NAME = ? and FSENTRY_DATA is null")); - - stmts.add(selectFileNamesStmt = con.prepareStatement("select FSENTRY_NAME from " - + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? " - + "and FSENTRY_DATA is not null")); - - stmts.add(selectFolderNamesStmt = con.prepareStatement("select FSENTRY_NAME from " - + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? " - + "and FSENTRY_DATA is null")); - - stmts.add(selectFileAndFolderNamesStmt = con.prepareStatement("select FSENTRY_NAME from " - + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ?")); - - stmts.add(selectChildCountStmt = con.prepareStatement("select count(FSENTRY_NAME) from " - + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? ")); - - stmts.add(selectDataStmt = con.prepareStatement("select FSENTRY_DATA from " - + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? " - + "and FSENTRY_NAME = ? and FSENTRY_DATA is not null")); - - stmts.add(selectLastModifiedStmt = con.prepareStatement("select FSENTRY_LASTMOD from " - + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? " - + "and FSENTRY_NAME = ?")); - - stmts.add(selectLengthStmt = con.prepareStatement("select FSENTRY_LENGTH from " - + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? " - + "and FSENTRY_NAME = ? and FSENTRY_DATA is not null")); - - stmts.add(deleteFileStmt = con.prepareStatement("delete from " - + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? " - + "and FSENTRY_NAME = ? and FSENTRY_DATA is not null")); - - stmts.add(deleteFolderStmt = con.prepareStatement("delete from " - + schemaObjectPrefix + "FSENTRY where " - + "(FSENTRY_PATH = ? and FSENTRY_NAME = ? and FSENTRY_DATA is null) " - + "or (FSENTRY_PATH = ?) " - + "or (FSENTRY_PATH like ?) ")); - - stmts.add(copyFileStmt = con.prepareStatement("insert into " - + schemaObjectPrefix + "FSENTRY " - + "(FSENTRY_PATH, FSENTRY_NAME, FSENTRY_DATA, " - + "FSENTRY_LASTMOD, FSENTRY_LENGTH) " - + "select ?, ?, FSENTRY_DATA, " - + "FSENTRY_LASTMOD, FSENTRY_LENGTH from " - + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? " - + "and FSENTRY_NAME = ? and FSENTRY_DATA is not null")); - - stmts.add(copyFilesStmt = con.prepareStatement("insert into " - + schemaObjectPrefix + "FSENTRY " - + "(FSENTRY_PATH, FSENTRY_NAME, FSENTRY_DATA, " - + "FSENTRY_LASTMOD, FSENTRY_LENGTH) " - + "select ?, FSENTRY_NAME, FSENTRY_DATA, " - + "FSENTRY_LASTMOD, FSENTRY_LENGTH from " - + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? " - + "and FSENTRY_DATA is not null")); - - return stmts; - } - - /** * {@inheritDoc} */ public void init() throws FileSystemException { @@ -908,7 +807,7 @@ } }; } catch (Exception e) { - String msg = "failed to open output strean to file: " + filePath; + String msg = "failed to open output stream to file: " + filePath; log.error(msg, e); throw new FileSystemException(msg, e); } @@ -1027,7 +926,7 @@ } }; } catch (Exception e) { - String msg = "failed to open output strean to file: " + filePath; + String msg = "failed to open output stream to file: " + filePath; log.error(msg, e); throw new FileSystemException(msg, e); } @@ -1203,6 +1102,107 @@ closeStatement(stmt); } } + } + + /** + * initializes the prepared statements and returns the list of them. please + * note, that this list is used to close the statements in the {@link #close()} + * call. + * + * @return the list of prepared statements. + * @throws SQLException + */ + protected List initPreparedStatements() throws SQLException { + List stmts = new LinkedList(); + stmts.add(insertFileStmt = con.prepareStatement("insert into " + + schemaObjectPrefix + "FSENTRY " + + "(FSENTRY_PATH, FSENTRY_NAME, FSENTRY_DATA, " + + "FSENTRY_LASTMOD, FSENTRY_LENGTH) " + + "values (?, ?, ?, ?, ?)")); + + stmts.add(insertFolderStmt = con.prepareStatement("insert into " + + schemaObjectPrefix + "FSENTRY " + + "(FSENTRY_PATH, FSENTRY_NAME, FSENTRY_LASTMOD, FSENTRY_LENGTH) " + + "values (?, ?, ?, 0)")); + + stmts.add(updateDataStmt = con.prepareStatement("update " + + schemaObjectPrefix + "FSENTRY " + + "set FSENTRY_DATA = ?, FSENTRY_LASTMOD = ?, FSENTRY_LENGTH = ? " + + "where FSENTRY_PATH = ? and FSENTRY_NAME = ? " + + "and FSENTRY_DATA is not null")); + + stmts.add(updateLastModifiedStmt = con.prepareStatement("update " + + schemaObjectPrefix + "FSENTRY set FSENTRY_LASTMOD = ? " + + "where FSENTRY_PATH = ? and FSENTRY_NAME = ? " + + "and FSENTRY_DATA is not null")); + + stmts.add(selectExistStmt = con.prepareStatement("select 1 from " + + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? " + + "and FSENTRY_NAME = ?")); + + stmts.add(selectFileExistStmt = con.prepareStatement("select 1 from " + + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? " + + "and FSENTRY_NAME = ? and FSENTRY_DATA is not null")); + + stmts.add(selectFolderExistStmt = con.prepareStatement("select 1 from " + + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? " + + "and FSENTRY_NAME = ? and FSENTRY_DATA is null")); + + stmts.add(selectFileNamesStmt = con.prepareStatement("select FSENTRY_NAME from " + + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? " + + "and FSENTRY_DATA is not null")); + + stmts.add(selectFolderNamesStmt = con.prepareStatement("select FSENTRY_NAME from " + + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? " + + "and FSENTRY_DATA is null")); + + stmts.add(selectFileAndFolderNamesStmt = con.prepareStatement("select FSENTRY_NAME from " + + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ?")); + + stmts.add(selectChildCountStmt = con.prepareStatement("select count(FSENTRY_NAME) from " + + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? ")); + + stmts.add(selectDataStmt = con.prepareStatement("select FSENTRY_DATA from " + + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? " + + "and FSENTRY_NAME = ? and FSENTRY_DATA is not null")); + + stmts.add(selectLastModifiedStmt = con.prepareStatement("select FSENTRY_LASTMOD from " + + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? " + + "and FSENTRY_NAME = ?")); + + stmts.add(selectLengthStmt = con.prepareStatement("select FSENTRY_LENGTH from " + + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? " + + "and FSENTRY_NAME = ? and FSENTRY_DATA is not null")); + + stmts.add(deleteFileStmt = con.prepareStatement("delete from " + + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? " + + "and FSENTRY_NAME = ? and FSENTRY_DATA is not null")); + + stmts.add(deleteFolderStmt = con.prepareStatement("delete from " + + schemaObjectPrefix + "FSENTRY where " + + "(FSENTRY_PATH = ? and FSENTRY_NAME = ? and FSENTRY_DATA is null) " + + "or (FSENTRY_PATH = ?) " + + "or (FSENTRY_PATH like ?) ")); + + stmts.add(copyFileStmt = con.prepareStatement("insert into " + + schemaObjectPrefix + "FSENTRY " + + "(FSENTRY_PATH, FSENTRY_NAME, FSENTRY_DATA, " + + "FSENTRY_LASTMOD, FSENTRY_LENGTH) " + + "select ?, ?, FSENTRY_DATA, " + + "FSENTRY_LASTMOD, FSENTRY_LENGTH from " + + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? " + + "and FSENTRY_NAME = ? and FSENTRY_DATA is not null")); + + stmts.add(copyFilesStmt = con.prepareStatement("insert into " + + schemaObjectPrefix + "FSENTRY " + + "(FSENTRY_PATH, FSENTRY_NAME, FSENTRY_DATA, " + + "FSENTRY_LASTMOD, FSENTRY_LENGTH) " + + "select ?, FSENTRY_NAME, FSENTRY_DATA, " + + "FSENTRY_LASTMOD, FSENTRY_LENGTH from " + + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? " + + "and FSENTRY_DATA is not null")); + + return stmts; } /** Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/fs/db/OracleFileSystem.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/fs/db/OracleFileSystem.java?view=diff&rev=468036&r1=468035&r2=468036 ============================================================================== --- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/fs/db/OracleFileSystem.java (original) +++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/fs/db/OracleFileSystem.java Thu Oct 26 08:27:17 2006 @@ -16,8 +16,11 @@ */ package org.apache.jackrabbit.core.fs.db; -import org.apache.jackrabbit.core.fs.FileSystemException; import org.apache.jackrabbit.util.Text; +import org.apache.jackrabbit.util.TransientFileFactory; +import org.apache.jackrabbit.core.fs.FileSystemException; +import org.apache.jackrabbit.core.fs.FileSystemPathUtil; +import org.apache.jackrabbit.core.fs.RandomAccessOutputStream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -25,9 +28,23 @@ import java.sql.DatabaseMetaData; import java.sql.ResultSet; import java.sql.Statement; +import java.sql.SQLException; +import java.sql.Blob; +import java.sql.Connection; +import java.sql.PreparedStatement; import java.io.InputStream; import java.io.BufferedReader; import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.IOException; +import java.io.File; +import java.io.FilterOutputStream; +import java.io.FileOutputStream; +import java.io.FileInputStream; +import java.io.RandomAccessFile; +import java.util.List; +import java.util.LinkedList; +import java.lang.reflect.Method; /** * OracleFileSystem is a JDBC-based FileSystem @@ -65,6 +82,10 @@ */ private static Logger log = LoggerFactory.getLogger(OracleFileSystem.class); + private Class blobClass; + private Integer DURATION_SESSION_CONSTANT; + private Integer MODE_READWRITE_CONSTANT; + /** * Creates a new OracleFileSystem instance. */ @@ -78,133 +99,31 @@ initialized = false; } - //-----------------------------------------------< DbFileSystem overrides > + //-----------------------------------------< DatabaseFileSystem overrides > /** * {@inheritDoc} *

- * Since Oracle treats emtpy strings and BLOBs as null values the SQL - * statements had to adapated accordingly. The following changes were - * necessary: - *

    - *
  • The distinction between file and folder entries is based on - * FSENTRY_LENGTH being null/not null rather than FSENTRY_DATA being - * null/not null because FSENTRY_DATA of a 0-length (i.e. empty) file is - * null in Oracle.
  • - *
  • Folder entries: Since the root folder has an empty name (which would - * be null in Oracle), an empty name is automatically converted and treated - * as " ".
  • - *
+ * Retrieve the oracle.sql.BLOB class via reflection, and + * initialize the values for the DURATION_SESSION and + * MODE_READWRITE constants defined there. + * @see oracle.sql.BLOB#DURATION_SESSION + * @see oracle.sql.BLOB#MODE_READWRITE */ public void init() throws FileSystemException { - if (initialized) { - throw new IllegalStateException("already initialized"); - } - - try { - // setup jdbc connection - initConnection(); - - // check if schema objects exist and create them if necessary - checkSchema(); + super.init(); - // prepare statements - insertFileStmt = con.prepareStatement("insert into " - + schemaObjectPrefix + "FSENTRY " - + "(FSENTRY_PATH, FSENTRY_NAME, FSENTRY_DATA, " - + "FSENTRY_LASTMOD, FSENTRY_LENGTH) " - + "values (?, ?, ?, ?, ?)"); - - insertFolderStmt = con.prepareStatement("insert into " - + schemaObjectPrefix + "FSENTRY " - + "(FSENTRY_PATH, FSENTRY_NAME, FSENTRY_LASTMOD, FSENTRY_LENGTH) " - + "values (?, nvl(?, ' '), ?, null)"); - - updateDataStmt = con.prepareStatement("update " - + schemaObjectPrefix + "FSENTRY " - + "set FSENTRY_DATA = ?, FSENTRY_LASTMOD = ?, FSENTRY_LENGTH = ? " - + "where FSENTRY_PATH = ? and FSENTRY_NAME = ? " - + "and FSENTRY_LENGTH is not null"); - - updateLastModifiedStmt = con.prepareStatement("update " - + schemaObjectPrefix + "FSENTRY set FSENTRY_LASTMOD = ? " - + "where FSENTRY_PATH = ? and FSENTRY_NAME = ? " - + "and FSENTRY_LENGTH is not null"); - - selectExistStmt = con.prepareStatement("select 1 from " - + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? " - + "and FSENTRY_NAME = nvl(?, ' ')"); - - selectFileExistStmt = con.prepareStatement("select 1 from " - + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? " - + "and FSENTRY_NAME = ? and FSENTRY_LENGTH is not null"); - - selectFolderExistStmt = con.prepareStatement("select 1 from " - + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? " - + "and FSENTRY_NAME = nvl(?, ' ') and FSENTRY_LENGTH is null"); - - selectFileNamesStmt = con.prepareStatement("select FSENTRY_NAME from " - + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? " - + "and FSENTRY_LENGTH is not null"); - - selectFolderNamesStmt = con.prepareStatement("select FSENTRY_NAME from " - + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? " - + "and FSENTRY_NAME != ' ' " - + "and FSENTRY_LENGTH is null"); - - selectFileAndFolderNamesStmt = con.prepareStatement("select FSENTRY_NAME from " - + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? " - + "and FSENTRY_NAME != ' '"); - - selectChildCountStmt = con.prepareStatement("select count(FSENTRY_NAME) from " - + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? " - + "and FSENTRY_NAME != ' '"); - - selectDataStmt = con.prepareStatement("select nvl(FSENTRY_DATA, empty_blob()) from " - + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? " - + "and FSENTRY_NAME = ? and FSENTRY_LENGTH is not null"); - - selectLastModifiedStmt = con.prepareStatement("select FSENTRY_LASTMOD from " - + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? " - + "and FSENTRY_NAME = nvl(?, ' ')"); - - selectLengthStmt = con.prepareStatement("select nvl(FSENTRY_LENGTH, 0) from " - + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? " - + "and FSENTRY_NAME = ? and FSENTRY_LENGTH is not null"); - - deleteFileStmt = con.prepareStatement("delete from " - + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? " - + "and FSENTRY_NAME = ? and FSENTRY_LENGTH is not null"); - - deleteFolderStmt = con.prepareStatement("delete from " - + schemaObjectPrefix + "FSENTRY where " - + "(FSENTRY_PATH = ? and FSENTRY_NAME = nvl(?, ' ') and FSENTRY_LENGTH is null) " - + "or (FSENTRY_PATH = ?) " - + "or (FSENTRY_PATH like ?) "); - - copyFileStmt = con.prepareStatement("insert into " - + schemaObjectPrefix + "FSENTRY " - + "(FSENTRY_PATH, FSENTRY_NAME, FSENTRY_DATA, " - + "FSENTRY_LASTMOD, FSENTRY_LENGTH) " - + "select ?, ?, FSENTRY_DATA, " - + "FSENTRY_LASTMOD, FSENTRY_LENGTH from " - + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? " - + "and FSENTRY_NAME = ? and FSENTRY_LENGTH is not null"); - - copyFilesStmt = con.prepareStatement("insert into " - + schemaObjectPrefix + "FSENTRY " - + "(FSENTRY_PATH, FSENTRY_NAME, FSENTRY_DATA, " - + "FSENTRY_LASTMOD, FSENTRY_LENGTH) " - + "select ?, FSENTRY_NAME, FSENTRY_DATA, " - + "FSENTRY_LASTMOD, FSENTRY_LENGTH from " - + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? " - + "and FSENTRY_LENGTH is not null"); + // initialize oracle.sql.BLOB class & constants - // finally verify that there's a file system root entry - verifyRootExists(); - - initialized = true; + // use the Connection object for using the exact same + // class loader that the Oracle driver was loaded with + try { + blobClass = con.getClass().getClassLoader().loadClass("oracle.sql.BLOB"); + DURATION_SESSION_CONSTANT = + new Integer(blobClass.getField("DURATION_SESSION").getInt(null)); + MODE_READWRITE_CONSTANT = + new Integer(blobClass.getField("MODE_READWRITE").getInt(null)); } catch (Exception e) { - String msg = "failed to initialize file system"; + String msg = "failed to load/introspect oracle.sql.BLOB"; log.error(msg, e); throw new FileSystemException(msg, e); } @@ -265,5 +184,393 @@ closeStatement(stmt); } } + } + + /** + * {@inheritDoc} + *

+ * Since Oracle treats emtpy strings and BLOBs as null values the SQL + * statements had to be adapated accordingly. The following changes were + * necessary: + *

    + *
  • The distinction between file and folder entries is based on + * FSENTRY_LENGTH being null/not null rather than FSENTRY_DATA being + * null/not null because FSENTRY_DATA of a 0-length (i.e. empty) file is + * null in Oracle.
  • + *
  • Folder entries: Since the root folder has an empty name (which would + * be null in Oracle), an empty name is automatically converted and treated + * as " ".
  • + *
+ */ + protected List initPreparedStatements() throws SQLException { + List stmts = new LinkedList(); + stmts.add(insertFileStmt = con.prepareStatement("insert into " + + schemaObjectPrefix + "FSENTRY " + + "(FSENTRY_PATH, FSENTRY_NAME, FSENTRY_DATA, " + + "FSENTRY_LASTMOD, FSENTRY_LENGTH) " + + "values (?, ?, ?, ?, ?)")); + + stmts.add(insertFolderStmt = con.prepareStatement("insert into " + + schemaObjectPrefix + "FSENTRY " + + "(FSENTRY_PATH, FSENTRY_NAME, FSENTRY_LASTMOD, FSENTRY_LENGTH) " + + "values (?, nvl(?, ' '), ?, null)")); + + stmts.add(updateDataStmt = con.prepareStatement("update " + + schemaObjectPrefix + "FSENTRY " + + "set FSENTRY_DATA = ?, FSENTRY_LASTMOD = ?, FSENTRY_LENGTH = ? " + + "where FSENTRY_PATH = ? and FSENTRY_NAME = ? " + + "and FSENTRY_LENGTH is not null")); + + stmts.add(updateLastModifiedStmt = con.prepareStatement("update " + + schemaObjectPrefix + "FSENTRY set FSENTRY_LASTMOD = ? " + + "where FSENTRY_PATH = ? and FSENTRY_NAME = ? " + + "and FSENTRY_LENGTH is not null")); + + stmts.add(selectExistStmt = con.prepareStatement("select 1 from " + + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? " + + "and FSENTRY_NAME = nvl(?, ' ')")); + + stmts.add(selectFileExistStmt = con.prepareStatement("select 1 from " + + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? " + + "and FSENTRY_NAME = ? and FSENTRY_LENGTH is not null")); + + stmts.add(selectFolderExistStmt = con.prepareStatement("select 1 from " + + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? " + + "and FSENTRY_NAME = nvl(?, ' ') and FSENTRY_LENGTH is null")); + + stmts.add(selectFileNamesStmt = con.prepareStatement("select FSENTRY_NAME from " + + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? " + + "and FSENTRY_LENGTH is not null")); + + stmts.add(selectFolderNamesStmt = con.prepareStatement("select FSENTRY_NAME from " + + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? " + + "and FSENTRY_NAME != ' ' " + + "and FSENTRY_LENGTH is null")); + + stmts.add(selectFileAndFolderNamesStmt = con.prepareStatement("select FSENTRY_NAME from " + + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? " + + "and FSENTRY_NAME != ' '")); + + stmts.add(selectChildCountStmt = con.prepareStatement("select count(FSENTRY_NAME) from " + + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? " + + "and FSENTRY_NAME != ' '")); + + stmts.add(selectDataStmt = con.prepareStatement("select nvl(FSENTRY_DATA, empty_blob()) from " + + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? " + + "and FSENTRY_NAME = ? and FSENTRY_LENGTH is not null")); + + stmts.add(selectLastModifiedStmt = con.prepareStatement("select FSENTRY_LASTMOD from " + + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? " + + "and FSENTRY_NAME = nvl(?, ' ')")); + + stmts.add(selectLengthStmt = con.prepareStatement("select nvl(FSENTRY_LENGTH, 0) from " + + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? " + + "and FSENTRY_NAME = ? and FSENTRY_LENGTH is not null")); + + stmts.add(deleteFileStmt = con.prepareStatement("delete from " + + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? " + + "and FSENTRY_NAME = ? and FSENTRY_LENGTH is not null")); + + stmts.add(deleteFolderStmt = con.prepareStatement("delete from " + + schemaObjectPrefix + "FSENTRY where " + + "(FSENTRY_PATH = ? and FSENTRY_NAME = nvl(?, ' ') and FSENTRY_LENGTH is null) " + + "or (FSENTRY_PATH = ?) " + + "or (FSENTRY_PATH like ?) ")); + + stmts.add(copyFileStmt = con.prepareStatement("insert into " + + schemaObjectPrefix + "FSENTRY " + + "(FSENTRY_PATH, FSENTRY_NAME, FSENTRY_DATA, " + + "FSENTRY_LASTMOD, FSENTRY_LENGTH) " + + "select ?, ?, FSENTRY_DATA, " + + "FSENTRY_LASTMOD, FSENTRY_LENGTH from " + + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? " + + "and FSENTRY_NAME = ? and FSENTRY_LENGTH is not null")); + + stmts.add(copyFilesStmt = con.prepareStatement("insert into " + + schemaObjectPrefix + "FSENTRY " + + "(FSENTRY_PATH, FSENTRY_NAME, FSENTRY_DATA, " + + "FSENTRY_LASTMOD, FSENTRY_LENGTH) " + + "select ?, FSENTRY_NAME, FSENTRY_DATA, " + + "FSENTRY_LASTMOD, FSENTRY_LENGTH from " + + schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? " + + "and FSENTRY_LENGTH is not null")); + + return stmts; + } + + /** + * {@inheritDoc} + *

+ * Overridden because we need to use oracle.sql.Blob + * and PreparedStatement#setBlob instead of just + * PreparedStatement#setBinaryStream. + */ + public OutputStream getOutputStream(final String filePath) throws FileSystemException { + if (!initialized) { + throw new IllegalStateException("not initialized"); + } + + FileSystemPathUtil.checkFormat(filePath); + + final String parentDir = FileSystemPathUtil.getParentDir(filePath); + final String name = FileSystemPathUtil.getName(filePath); + + if (!isFolder(parentDir)) { + throw new FileSystemException("path not found: " + parentDir); + } + + if (isFolder(filePath)) { + throw new FileSystemException("path denotes folder: " + filePath); + } + + try { + TransientFileFactory fileFactory = TransientFileFactory.getInstance(); + final File tmpFile = fileFactory.createTransientFile("bin", null, null); + + return new FilterOutputStream(new FileOutputStream(tmpFile)) { + + public void close() throws IOException { + super.close(); + + PreparedStatement stmt = null; + InputStream in = null; + Blob blob = null; + try { + if (isFile(filePath)) { + stmt = updateDataStmt; + synchronized (stmt) { + long length = tmpFile.length(); + in = new FileInputStream(tmpFile); + blob = createTemporaryBlob(in); + stmt.setBlob(1, blob); + stmt.setLong(2, System.currentTimeMillis()); + stmt.setLong(3, length); + stmt.setString(4, parentDir); + stmt.setString(5, name); + stmt.executeUpdate(); + } + } else { + stmt = insertFileStmt; + stmt.setString(1, parentDir); + stmt.setString(2, name); + long length = tmpFile.length(); + in = new FileInputStream(tmpFile); + blob = createTemporaryBlob(in); + stmt.setBlob(3, blob); + stmt.setLong(4, System.currentTimeMillis()); + stmt.setLong(5, length); + stmt.executeUpdate(); + } + + } catch (Exception e) { + throw new IOException(e.getMessage()); + } finally { + if (stmt != null) { + resetStatement(stmt); + } + if (blob != null) { + try { + freeTemporaryBlob(blob); + } catch (Exception e1) { + } + } + if (in != null) { + try { + in.close(); + } catch (Exception e1) { + } + } + // temp file can now safely be removed + tmpFile.delete(); + } + } + }; + } catch (Exception e) { + String msg = "failed to open output stream to file: " + filePath; + log.error(msg, e); + throw new FileSystemException(msg, e); + } + } + + /** + * {@inheritDoc} + */ + public RandomAccessOutputStream getRandomAccessOutputStream(final String filePath) throws FileSystemException, UnsupportedOperationException { + if (!initialized) { + throw new IllegalStateException("not initialized"); + } + + FileSystemPathUtil.checkFormat(filePath); + + final String parentDir = FileSystemPathUtil.getParentDir(filePath); + final String name = FileSystemPathUtil.getName(filePath); + + if (!isFolder(parentDir)) { + throw new FileSystemException("path not found: " + parentDir); + } + + if (isFolder(filePath)) { + throw new FileSystemException("path denotes folder: " + filePath); + } + + try { + TransientFileFactory fileFactory = TransientFileFactory.getInstance(); + final File tmpFile = fileFactory.createTransientFile("bin", null, null); + + // @todo FIXME use java.sql.Blob + + if (isFile(filePath)) { + // file entry exists, spool contents to temp file first + InputStream in = getInputStream(filePath); + OutputStream out = new FileOutputStream(tmpFile); + try { + int read; + byte[] ba = new byte[8192]; + while ((read = in.read(ba, 0, ba.length)) != -1) { + out.write(ba, 0, read); + } + } finally { + out.close(); + in.close(); + } + } + + return new RandomAccessOutputStream() { + private final RandomAccessFile raf = + new RandomAccessFile(tmpFile, "rw"); + + public void close() throws IOException { + raf.close(); + + PreparedStatement stmt = null; + InputStream in = null; + Blob blob = null; + try { + if (isFile(filePath)) { + stmt = updateDataStmt; + synchronized (stmt) { + long length = tmpFile.length(); + in = new FileInputStream(tmpFile); + blob = createTemporaryBlob(in); + stmt.setBlob(1, blob); + stmt.setLong(2, System.currentTimeMillis()); + stmt.setLong(3, length); + stmt.setString(4, parentDir); + stmt.setString(5, name); + stmt.executeUpdate(); + } + } else { + stmt = insertFileStmt; + stmt.setString(1, parentDir); + stmt.setString(2, name); + long length = tmpFile.length(); + in = new FileInputStream(tmpFile); + blob = createTemporaryBlob(in); + stmt.setBlob(3, blob); + stmt.setLong(4, System.currentTimeMillis()); + stmt.setLong(5, length); + stmt.executeUpdate(); + } + + } catch (Exception e) { + throw new IOException(e.getMessage()); + } finally { + if (stmt != null) { + resetStatement(stmt); + } + if (blob != null) { + try { + freeTemporaryBlob(blob); + } catch (Exception e1) { + } + } + if (in != null) { + try { + in.close(); + } catch (Exception e1) { + } + } + // temp file can now safely be removed + tmpFile.delete(); + } + } + + public void seek(long position) throws IOException { + raf.seek(position); + } + + public void write(int b) throws IOException { + raf.write(b); + } + + public void flush() /*throws IOException*/ { + // nop + } + + public void write(byte[] b) throws IOException { + raf.write(b); + } + + public void write(byte[] b, int off, int len) throws IOException { + raf.write(b, off, len); + } + }; + } catch (Exception e) { + String msg = "failed to open output stream to file: " + filePath; + log.error(msg, e); + throw new FileSystemException(msg, e); + } + } + + //----------------------------------------< oracle-specific blob handling > + /** + * Creates a temporary oracle.sql.BLOB instance via reflection and spools + * the contents of the specified stream. + */ + protected Blob createTemporaryBlob(InputStream in) throws Exception { + /* + BLOB blob = BLOB.createTemporary(con, false, BLOB.DURATION_SESSION); + blob.open(BLOB.MODE_READWRITE); + OutputStream out = blob.getBinaryOutputStream(); + ... + out.flush(); + out.close(); + blob.close(); + return blob; + */ + Method createTemporary = blobClass.getMethod("createTemporary", + new Class[]{Connection.class, Boolean.TYPE, Integer.TYPE}); + Object blob = createTemporary.invoke(null, + new Object[]{con, Boolean.FALSE, DURATION_SESSION_CONSTANT}); + Method open = blobClass.getMethod("open", new Class[]{Integer.TYPE}); + open.invoke(blob, new Object[]{MODE_READWRITE_CONSTANT}); + Method getBinaryOutputStream = + blobClass.getMethod("getBinaryOutputStream", new Class[0]); + OutputStream out = (OutputStream) getBinaryOutputStream.invoke(blob, null); + try { + int read; + byte[] buf = new byte[8192]; + while ((read = in.read(buf, 0, buf.length)) > -1) { + out.write(buf, 0, read); + } + } finally { + try { + out.flush(); + } catch (IOException ioe) { + } + out.close(); + } + Method close = blobClass.getMethod("close", new Class[0]); + close.invoke(blob, null); + return (Blob) blob; + } + + /** + * Frees a temporary oracle.sql.BLOB instance via reflection. + */ + protected void freeTemporaryBlob(Object blob) throws Exception { + // blob.freeTemporary(); + Method freeTemporary = blobClass.getMethod("freeTemporary", new Class[0]); + freeTemporary.invoke(blob, null); } }