Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/fs/db/Oracle10R1FileSystem.java =================================================================== --- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/fs/db/Oracle10R1FileSystem.java (revision 0) +++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/fs/db/Oracle10R1FileSystem.java (revision 0) @@ -0,0 +1,345 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.jackrabbit.core.fs.db; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.RandomAccessFile; +import java.lang.reflect.Method; +import java.sql.Blob; +import java.sql.Connection; + +import org.apache.commons.io.IOUtils; +import org.apache.jackrabbit.core.fs.FileSystemException; +import org.apache.jackrabbit.core.fs.FileSystemPathUtil; +import org.apache.jackrabbit.core.fs.RandomAccessOutputStream; +import org.apache.jackrabbit.util.TransientFileFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * {@inheritDoc} + *
+ *Oracle10R1FileSystem works for Oracle database version up to, and including, 10 R1.
+ */
+public class Oracle10R1FileSystem extends OracleBaseFileSystem {
+ /**
+ * Logger instance
+ */
+ private static Logger log = LoggerFactory.getLogger(Oracle10R1FileSystem.class);
+
+ private Class blobClass;
+ private Integer durationSessionConstant;
+ private Integer modeReadWriteConstant;
+
+ //-----------------------------------------< DatabaseFileSystem overrides >
+ /**
+ * {@inheritDoc}
+ *
+ * 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 {
+ super.init();
+
+ // initialize oracle.sql.BLOB class & constants
+
+ // 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");
+ durationSessionConstant =
+ new Integer(blobClass.getField("DURATION_SESSION").getInt(null));
+ modeReadWriteConstant =
+ new Integer(blobClass.getField("MODE_READWRITE").getInt(null));
+ } catch (Exception e) {
+ String msg = "failed to load/introspect oracle.sql.BLOB";
+ log.error(msg, e);
+ throw new FileSystemException(msg, e);
+ }
+ }
+
+ /**
+ * {@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();
+
+ InputStream in = null;
+ Blob blob = null;
+ try {
+ if (isFile(filePath)) {
+ synchronized (updateDataSQL) {
+ long length = tmpFile.length();
+ in = new FileInputStream(tmpFile);
+ blob = createTemporaryBlob(in);
+ executeStmt(updateDataSQL,
+ new Object[]{
+ blob,
+ new Long(System.currentTimeMillis()),
+ new Long(length),
+ parentDir,
+ name
+ });
+ }
+ } else {
+ synchronized (insertFileSQL) {
+ long length = tmpFile.length();
+ in = new FileInputStream(tmpFile);
+ blob = createTemporaryBlob(in);
+ executeStmt(insertFileSQL,
+ new Object[]{
+ parentDir,
+ name,
+ blob,
+ new Long(System.currentTimeMillis()),
+ new Long(length)
+ });
+ }
+ }
+ } catch (Exception e) {
+ IOException ioe = new IOException(e.getMessage());
+ ioe.initCause(e);
+ throw ioe;
+ } finally {
+ if (blob != null) {
+ try {
+ freeTemporaryBlob(blob);
+ } catch (Exception e1) {
+ }
+ }
+ IOUtils.closeQuietly(in);
+ // 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 {
+ IOUtils.copy(in, out);
+ } finally {
+ out.close();
+ in.close();
+ }
+ }
+
+ return new RandomAccessOutputStream() {
+ private final RandomAccessFile raf =
+ new RandomAccessFile(tmpFile, "rw");
+
+ public void close() throws IOException {
+ raf.close();
+
+ InputStream in = null;
+ Blob blob = null;
+ try {
+ if (isFile(filePath)) {
+ synchronized (updateDataSQL) {
+ long length = tmpFile.length();
+ in = new FileInputStream(tmpFile);
+ blob = createTemporaryBlob(in);
+ executeStmt(updateDataSQL,
+ new Object[]{
+ blob,
+ new Long(System.currentTimeMillis()),
+ new Long(length),
+ parentDir,
+ name
+ });
+ }
+ } else {
+ synchronized (insertFileSQL) {
+ long length = tmpFile.length();
+ in = new FileInputStream(tmpFile);
+ blob = createTemporaryBlob(in);
+ executeStmt(insertFileSQL,
+ new Object[]{
+ parentDir,
+ name,
+ blob,
+ new Long(System.currentTimeMillis()),
+ new Long(length)
+ });
+ }
+ }
+ } catch (Exception e) {
+ IOException ioe = new IOException(e.getMessage());
+ ioe.initCause(e);
+ throw ioe;
+ } finally {
+ if (blob != null) {
+ try {
+ freeTemporaryBlob(blob);
+ } catch (Exception e1) {
+ }
+ }
+ IOUtils.closeQuietly(in);
+ // 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, durationSessionConstant});
+ Method open = blobClass.getMethod("open", new Class[]{Integer.TYPE});
+ open.invoke(blob, new Object[]{modeReadWriteConstant});
+ Method getBinaryOutputStream =
+ blobClass.getMethod("getBinaryOutputStream", new Class[0]);
+ OutputStream out = (OutputStream) getBinaryOutputStream.invoke(blob, null);
+ try {
+ IOUtils.copy(in, out);
+ } 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);
+ }
+}
Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/fs/db/OracleBaseFileSystem.java
===================================================================
--- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/fs/db/OracleBaseFileSystem.java (revision 0)
+++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/fs/db/OracleBaseFileSystem.java (revision 0)
@@ -0,0 +1,282 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jackrabbit.core.fs.db;
+
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.sql.DatabaseMetaData;
+import java.sql.ResultSet;
+import java.sql.Statement;
+
+import javax.jcr.RepositoryException;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.jackrabbit.util.Text;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * OracleBaseFileSystem is a JDBC-based FileSystem
+ * base implementation for Jackrabbit that persists file system entries in an
+ * Oracle database.
+ *
+ * It is configured through the following properties:
+ * driver: the FQN name of the JDBC driver class
+ * (default: "oracle.jdbc.OracleDriver")schema: type of schema to be used
+ * (default: "oracle")url: the database url (e.g.
+ * "jdbc:oracle:thin:@[host]:[port]:[sid]")user: the database userpassword: the user's passwordschemaObjectPrefix: prefix to be prepended to schema objectstableSpace: the tablespace to use+ * <FileSystem class="org.apache.jackrabbit.core.fs.db.Oracle*FileSystem"> + * <param name="url" value="jdbc:oracle:thin:@127.0.0.1:1521:orcl"/> + * <param name="user" value="scott"/> + * <param name="password" value="tiger"/> + * <param name="schemaObjectPrefix" value="rep_"/> + * <param name="tableSpace" value="default"/> + * </FileSystem> + *+ */ +public class OracleBaseFileSystem extends DbFileSystem { + /** + * Logger instance + */ + private static Logger log = LoggerFactory.getLogger(OracleBaseFileSystem.class); + + /** the variable for the Oracle table space */ + public static final String TABLE_SPACE_VARIABLE = "${tableSpace}"; + + /** the Oracle table space to use */ + protected String tableSpace; + + /** + * Creates a new
OracleBaseFileSystem instance.
+ */
+ protected OracleBaseFileSystem() {
+ // preset some attributes to reasonable defaults
+ schema = "oracle";
+ driver = "oracle.jdbc.OracleDriver";
+ schemaObjectPrefix = "";
+ initialized = false;
+ }
+
+ /**
+ * Returns the configured Oracle table space.
+ * @return the configured Oracle table space.
+ */
+ public String getTableSpace() {
+ return tableSpace;
+ }
+
+ /**
+ * Sets the Oracle table space.
+ * @param tableSpace the Oracle table space.
+ */
+ public void setTableSpace(String tableSpace) {
+ if (tableSpace != null) {
+ this.tableSpace = tableSpace.trim();
+ } else {
+ this.tableSpace = null;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Overridden in order to support multiple oracle schemas. Note that schema
+ * names in Oracle correspond to the username of the connection. See
+ * http://issues.apache.org/jira/browse/JCR-582
+ *
+ * @throws Exception if an error occurs
+ */
+ protected void checkSchema() throws Exception {
+ DatabaseMetaData metaData = con.getMetaData();
+ String tableName = schemaObjectPrefix + "FSENTRY";
+ 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);
+ boolean schemaExists;
+ try {
+ schemaExists = rs.next();
+ } finally {
+ rs.close();
+ }
+
+ if (!schemaExists) {
+ // read ddl from resources
+ InputStream in = OracleFileSystem.class.getResourceAsStream(schema + ".ddl");
+ if (in == null) {
+ String msg = "Configuration error: unknown schema '" + schema + "'";
+ log.debug(msg);
+ throw new RepositoryException(msg);
+ }
+ BufferedReader reader = new BufferedReader(new InputStreamReader(in));
+ Statement stmt = con.createStatement();
+ try {
+ String sql = reader.readLine();
+ while (sql != null) {
+ // Skip comments and empty lines
+ if (!sql.startsWith("#") && sql.length() > 0) {
+ // replace prefix variable
+ sql = Text.replace(sql, SCHEMA_OBJECT_PREFIX_VARIABLE, schemaObjectPrefix);
+
+ // set the tablespace if it is defined
+ String tspace;
+ if (tableSpace == null || "".equals(tableSpace)) {
+ tspace = "";
+ } else {
+ tspace = "tablespace " + tableSpace;
+ }
+ sql = Text.replace(sql, TABLE_SPACE_VARIABLE, tspace).trim();
+
+ // execute sql stmt
+ stmt.executeUpdate(sql);
+ }
+ // read next sql stmt
+ sql = reader.readLine();
+ }
+ } finally {
+ IOUtils.closeQuietly(in);
+ closeStatement(stmt);
+ }
+ }
+ }
+
+ /**
+ * Builds the SQL statements
+ *
+ * Since Oracle treats emtpy strings and BLOBs as null values the SQL
+ * statements had to be adapated accordingly. The following changes were
+ * necessary:
+ * OracleFileSystem is a JDBC-based FileSystem
- * implementation for Jackrabbit that persists file system entries in an
- * Oracle database.
+ * {@inheritDoc}
*
- * It is configured through the following properties:
- * driver: the FQN name of the JDBC driver class
- * (default: "oracle.jdbc.OracleDriver")schema: type of schema to be used
- * (default: "oracle")url: the database url (e.g.
- * "jdbc:oracle:thin:@[host]:[port]:[sid]")user: the database userpassword: the user's passwordschemaObjectPrefix: prefix to be prepended to schema objectstableSpace: the tablespace to use- * <FileSystem class="org.apache.jackrabbit.core.fs.db.OracleFileSystem"> - * <param name="url" value="jdbc:oracle:thin:@127.0.0.1:1521:orcl"/> - * <param name="user" value="scott"/> - * <param name="password" value="tiger"/> - * <param name="schemaObjectPrefix" value="rep_"/> - * <param name="tableSpace" value="default"/> - * </FileSystem> - *+ *
OracleFileSystem works for Oracle database version 10 R2+.
*/
-public class OracleFileSystem extends DbFileSystem {
-
+public class OracleFileSystem extends OracleBaseFileSystem {
/**
* Logger instance
*/
private static Logger log = LoggerFactory.getLogger(OracleFileSystem.class);
- private Class blobClass;
- private Integer durationSessionConstant;
- private Integer modeReadWriteConstant;
-
- /** the variable for the Oracle table space */
- public static final String TABLE_SPACE_VARIABLE =
- "${tableSpace}";
-
- /** the Oracle table space to use */
- protected String tableSpace;
-
/**
- * Creates a new OracleFileSystem instance.
+ * Creates a new Oracle10FileSystem instance.
*/
public OracleFileSystem() {
- // preset some attributes to reasonable defaults
- schema = "oracle";
- driver = "oracle.jdbc.OracleDriver";
- schemaObjectPrefix = "";
- initialized = false;
+ super();
}
-
- /**
- * Returns the configured Oracle table space.
- * @return the configured Oracle table space.
- */
- public String getTableSpace() {
- return tableSpace;
- }
-
- /**
- * Sets the Oracle table space.
- * @param tableSpace the Oracle table space.
- */
- public void setTableSpace(String tableSpace) {
- if (tableSpace != null) {
- this.tableSpace = tableSpace.trim();
- } else {
- this.tableSpace = null;
- }
- }
-
- //-----------------------------------------< DatabaseFileSystem overrides >
- /**
- * {@inheritDoc}
- *
- * 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 {
- super.init();
-
- // initialize oracle.sql.BLOB class & constants
-
- // 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");
- durationSessionConstant =
- new Integer(blobClass.getField("DURATION_SESSION").getInt(null));
- modeReadWriteConstant =
- new Integer(blobClass.getField("MODE_READWRITE").getInt(null));
- } catch (Exception e) {
- String msg = "failed to load/introspect oracle.sql.BLOB";
- log.error(msg, e);
- throw new FileSystemException(msg, e);
- }
- }
-
- /**
- * {@inheritDoc}
- *
- * Overridden in order to support multiple oracle schemas. Note that
- * schema names in Oracle correspond to the username of the connection.
- * See http://issues.apache.org/jira/browse/JCR-582
- *
- * @throws Exception if an error occurs
- */
- protected void checkSchema() throws Exception {
- DatabaseMetaData metaData = con.getMetaData();
- String tableName = schemaObjectPrefix + "FSENTRY";
- 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);
- boolean schemaExists;
- try {
- schemaExists = rs.next();
- } finally {
- rs.close();
- }
-
- if (!schemaExists) {
- // read ddl from resources
- InputStream in = OracleFileSystem.class.getResourceAsStream(schema + ".ddl");
- if (in == null) {
- String msg = "Configuration error: unknown schema '" + schema + "'";
- log.debug(msg);
- throw new RepositoryException(msg);
- }
- BufferedReader reader = new BufferedReader(new InputStreamReader(in));
- Statement stmt = con.createStatement();
- try {
- String sql = reader.readLine();
- while (sql != null) {
- // Skip comments and empty lines
- if (!sql.startsWith("#") && sql.length() > 0) {
- // replace prefix variable
- sql = Text.replace(sql, SCHEMA_OBJECT_PREFIX_VARIABLE, schemaObjectPrefix);
-
- // set the tablespace if it is defined
- String tspace;
- if (tableSpace == null || "".equals(tableSpace)) {
- tspace = "";
- } else {
- tspace = "tablespace " + tableSpace;
- }
- sql = Text.replace(sql, TABLE_SPACE_VARIABLE, tspace).trim();
-
- // execute sql stmt
- stmt.executeUpdate(sql);
- }
- // read next sql stmt
- sql = reader.readLine();
- }
- } finally {
- IOUtils.closeQuietly(in);
- closeStatement(stmt);
- }
- }
- }
-
- /**
- * Builds the SQL statements
- *
- * Since Oracle treats emtpy strings and BLOBs as null values the SQL
- * statements had to be adapated accordingly. The following changes were
- * necessary:
- * 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();
-
- InputStream in = null;
- Blob blob = null;
- try {
- if (isFile(filePath)) {
- synchronized (updateDataSQL) {
- long length = tmpFile.length();
- in = new FileInputStream(tmpFile);
- blob = createTemporaryBlob(in);
- executeStmt(updateDataSQL,
- new Object[]{
- blob,
- new Long(System.currentTimeMillis()),
- new Long(length),
- parentDir,
- name
- });
- }
- } else {
- synchronized (insertFileSQL) {
- long length = tmpFile.length();
- in = new FileInputStream(tmpFile);
- blob = createTemporaryBlob(in);
- executeStmt(insertFileSQL,
- new Object[]{
- parentDir,
- name,
- blob,
- new Long(System.currentTimeMillis()),
- new Long(length)
- });
- }
- }
- } catch (Exception e) {
- IOException ioe = new IOException(e.getMessage());
- ioe.initCause(e);
- throw ioe;
- } finally {
- if (blob != null) {
- try {
- freeTemporaryBlob(blob);
- } catch (Exception e1) {
- }
- }
- IOUtils.closeQuietly(in);
- // 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 {
- IOUtils.copy(in, out);
- } finally {
- out.close();
- in.close();
- }
- }
-
- return new RandomAccessOutputStream() {
- private final RandomAccessFile raf =
- new RandomAccessFile(tmpFile, "rw");
-
- public void close() throws IOException {
- raf.close();
-
- InputStream in = null;
- Blob blob = null;
- try {
- if (isFile(filePath)) {
- synchronized (updateDataSQL) {
- long length = tmpFile.length();
- in = new FileInputStream(tmpFile);
- blob = createTemporaryBlob(in);
- executeStmt(updateDataSQL,
- new Object[]{
- blob,
- new Long(System.currentTimeMillis()),
- new Long(length),
- parentDir,
- name
- });
- }
- } else {
- synchronized (insertFileSQL) {
- long length = tmpFile.length();
- in = new FileInputStream(tmpFile);
- blob = createTemporaryBlob(in);
- executeStmt(insertFileSQL,
- new Object[]{
- parentDir,
- name,
- blob,
- new Long(System.currentTimeMillis()),
- new Long(length)
- });
- }
- }
- } catch (Exception e) {
- IOException ioe = new IOException(e.getMessage());
- ioe.initCause(e);
- throw ioe;
- } finally {
- if (blob != null) {
- try {
- freeTemporaryBlob(blob);
- } catch (Exception e1) {
- }
- }
- IOUtils.closeQuietly(in);
- // 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, durationSessionConstant});
- Method open = blobClass.getMethod("open", new Class[]{Integer.TYPE});
- open.invoke(blob, new Object[]{modeReadWriteConstant});
- Method getBinaryOutputStream =
- blobClass.getMethod("getBinaryOutputStream", new Class[0]);
- OutputStream out = (OutputStream) getBinaryOutputStream.invoke(blob, null);
- try {
- IOUtils.copy(in, out);
- } 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);
- }
}