/*
* 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 org.apache.jackrabbit.core.fs.FileSystem;
import org.apache.jackrabbit.core.fs.FileSystemException;
import org.apache.jackrabbit.core.fs.FileSystemPathUtil;
import org.apache.jackrabbit.core.persistence.PMContext;
import org.apache.jackrabbit.core.util.db.CheckSchemaOperation;
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.util.TransientFileFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.sql.DataSource;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FilterInputStream;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.FileInputStream;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
/**
* Base class for database file systems. This class contains common
* functionality for database file system subclasses that normally differ only
* in the way the database connection is acquired. Subclasses should override
* the {@link #getConnection()} method to return the configured database
* connection.
* <p>
* See the {@link DbFileSystem} for a detailed description of the available
* configuration options and database behaviour.
*/
public abstract class DatabaseFileSystem implements FileSystem {
/**
* Logger instance
*/
private static Logger log = LoggerFactory.getLogger(DatabaseFileSystem.class);
protected boolean initialized;
protected String schema;
protected String schemaObjectPrefix;
// initial size of buffer used to serialize objects
protected static final int INITIAL_BUFFER_SIZE = 8192;
/**
* Whether the schema check must be done during initialization.
*/
private boolean schemaCheckEnabled = true;
/** the {@link ConnectionHelper} set in the {@link #init()} method */
protected ConnectionHelper conHelper;
// SQL statements
protected String selectExistSQL;
protected String selectFileExistSQL;
protected String selectFolderExistSQL;
protected String selectChildCountSQL;
protected String selectDataSQL;
protected String selectLastModifiedSQL;
protected String selectLengthSQL;
protected String selectFileNamesSQL;
protected String selectFolderNamesSQL;
protected String selectFileAndFolderNamesSQL;
protected String deleteFileSQL;
protected String deleteFolderSQL;
protected String insertFileSQL;
protected String insertFolderSQL;
protected String updateDataSQL;
protected String updateLastModifiedSQL;
protected String copyFileSQL;
protected String copyFilesSQL;
/**
* Default constructor
*/
public DatabaseFileSystem() {
schema = "default";
schemaObjectPrefix = "";
initialized = false;
}
//----------------------------------------------------< setters & getters >
public String getSchemaObjectPrefix() {
return schemaObjectPrefix;
}
public void setSchemaObjectPrefix(String schemaObjectPrefix) {
// make sure prefix is all uppercase
this.schemaObjectPrefix = schemaObjectPrefix.toUpperCase();
}
public String getSchema() {
return schema;
}
public void setSchema(String schema) {
this.schema = schema;
}
/**
* @return whether the schema check is enabled
*/
public final boolean isSchemaCheckEnabled() {
return schemaCheckEnabled;
}
/**
* @param enabled set whether the schema check is enabled
*/
public final void setSchemaCheckEnabled(boolean enabled) {
schemaCheckEnabled = enabled;
}
//-------------------------------------------< java.lang.Object overrides >
/**
* {@inheritDoc}
*/
public boolean equals(Object obj) {
if (this == obj) {
return true;
} else if (obj instanceof DatabaseFileSystem) {
DatabaseFileSystem other = (DatabaseFileSystem) obj;
return equals(schema, other.schema)
&& equals(schemaObjectPrefix, other.schemaObjectPrefix);
} else {
return false;
}
}
private static boolean equals(Object a, Object b) {
if (a == null && b == null) {
return true;
} else if (a == null || b == null) {
return false;
} else {
return a.equals(b);
}
}
/**
* Returns zero to satisfy the Object equals/hashCode contract.
* This class is mutable and not meant to be used as a hash key.
*
* @return always zero
* @see Object#hashCode()
*/
public int hashCode() {
return 0;
}
//-----------------------------------------------------------< FileSystem >
/**
* {@inheritDoc}
*/
public void init() throws FileSystemException {
if (initialized) {
throw new IllegalStateException("already initialized");
}
try {
conHelper = createConnectionHelper(getDataSource());
// make sure schemaObjectPrefix consists of legal name characters only
schemaObjectPrefix = conHelper.prepareDbIdentifier(schemaObjectPrefix);
// check if schema objects exist and create them if necessary
if (isSchemaCheckEnabled()) {
createCheckSchemaOperation().run();
}
// build sql statements
buildSQLStatements();
// finally verify that there's a file system root entry
verifyRootExists();
initialized = true;
} catch (Exception e) {
String msg = "failed to initialize file system";
log.error(msg, e);
throw new FileSystemException(msg, e);
}
}
/**
* @return
* @throws Exception
*/
protected abstract DataSource getDataSource() throws Exception;
/**
* This method is called from the {@link #init(PMContext)} 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, false);
}
/**
* This method is called from {@link #init(PMContext)} 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 = DatabaseFileSystem.class.getResourceAsStream(getSchema() + ".ddl");
return new CheckSchemaOperation(conHelper, in, schemaObjectPrefix + "FSENTRY").addVariableReplacement(
CheckSchemaOperation.SCHEMA_OBJECT_PREFIX_VARIABLE, schemaObjectPrefix);
}
/**
* {@inheritDoc}
*/
public void close() throws FileSystemException {
if (!initialized) {
throw new IllegalStateException("not initialized");
}
}
/**
* {@inheritDoc}
*/
public void createFolder(String folderPath) throws FileSystemException {
if (!initialized) {
throw new IllegalStateException("not initialized");
}
FileSystemPathUtil.checkFormat(folderPath);
if (!exists(folderPath)) {
createDeepFolder(folderPath);
} else {
throw new FileSystemException("file system entry already exists: " + folderPath);
}
}
/**
* {@inheritDoc}
*/
public void deleteFile(String filePath) throws FileSystemException {
if (!initialized) {
throw new IllegalStateException("not initialized");
}
FileSystemPathUtil.checkFormat(filePath);
String parentDir = FileSystemPathUtil.getParentDir(filePath);
String name = FileSystemPathUtil.getName(filePath);
int count = 0;
synchronized (deleteFileSQL) {
try {
count = conHelper.update(
deleteFileSQL, new Object[]{parentDir, name});
} catch (SQLException e) {
String msg = "failed to delete file: " + filePath;
log.error(msg, e);
throw new FileSystemException(msg, e);
}
}
if (count == 0) {
throw new FileSystemException("no such file: " + filePath);
}
}
/**
* {@inheritDoc}
*/
public void deleteFolder(String folderPath) throws FileSystemException {
if (!initialized) {
throw new IllegalStateException("not initialized");
}
FileSystemPathUtil.checkFormat(folderPath);
if (folderPath.equals(FileSystem.SEPARATOR)) {
throw new FileSystemException("cannot delete root");
}
String parentDir = FileSystemPathUtil.getParentDir(folderPath);
String name = FileSystemPathUtil.getName(folderPath);
int count = 0;
synchronized (deleteFolderSQL) {
try {
count = conHelper.update(deleteFolderSQL, new Object[]{
parentDir,
name,
folderPath,
folderPath + FileSystem.SEPARATOR + "%"});
} catch (SQLException e) {
String msg = "failed to delete folder: " + folderPath;
log.error(msg, e);
throw new FileSystemException(msg, e);
}
}
if (count == 0) {
throw new FileSystemException("no such folder: " + folderPath);
}
}
/**
* {@inheritDoc}
*/
public boolean exists(String path) throws FileSystemException {
if (!initialized) {
throw new IllegalStateException("not initialized");
}
FileSystemPathUtil.checkFormat(path);
String parentDir = FileSystemPathUtil.getParentDir(path);
String name = FileSystemPathUtil.getName(path);
synchronized (selectExistSQL) {
ResultSet rs = null;
try {
rs = conHelper.exec(
selectExistSQL, new Object[]{parentDir, name}, false, 0);
// a file system entry exists if the result set
// has at least one entry
return rs.next();
} catch (SQLException e) {
String msg = "failed to check existence of file system entry: " + path;
log.error(msg, e);
throw new FileSystemException(msg, e);
} finally {
DbUtility.close(rs);
}
}
}
/**
* {@inheritDoc}
*/
public boolean isFile(String path) throws FileSystemException {
if (!initialized) {
throw new IllegalStateException("not initialized");
}
FileSystemPathUtil.checkFormat(path);
String parentDir = FileSystemPathUtil.getParentDir(path);
String name = FileSystemPathUtil.getName(path);
synchronized (selectFileExistSQL) {
ResultSet rs = null;
try {
rs = conHelper.exec(
selectFileExistSQL, new Object[]{parentDir, name}, false, 0);
// a file exists if the result set has at least one entry
return rs.next();
} catch (SQLException e) {
String msg = "failed to check existence of file: " + path;
log.error(msg, e);
throw new FileSystemException(msg, e);
} finally {
DbUtility.close(rs);
}
}
}
/**
* {@inheritDoc}
*/
public boolean isFolder(String path) throws FileSystemException {
if (!initialized) {
throw new IllegalStateException("not initialized");
}
FileSystemPathUtil.checkFormat(path);
String parentDir = FileSystemPathUtil.getParentDir(path);
String name = FileSystemPathUtil.getName(path);
synchronized (selectFolderExistSQL) {
ResultSet rs = null;
try {
rs = conHelper.exec(
selectFolderExistSQL, new Object[]{parentDir, name}, false, 0);
// a folder exists if the result set has at least one entry
return rs.next();
} catch (SQLException e) {
String msg = "failed to check existence of folder: " + path;
log.error(msg, e);
throw new FileSystemException(msg, e);
} finally {
DbUtility.close(rs);
}
}
}
/**
* {@inheritDoc}
*/
public long lastModified(String path) throws FileSystemException {
if (!initialized) {
throw new IllegalStateException("not initialized");
}
FileSystemPathUtil.checkFormat(path);
String parentDir = FileSystemPathUtil.getParentDir(path);
String name = FileSystemPathUtil.getName(path);
synchronized (selectLastModifiedSQL) {
ResultSet rs = null;
try {
rs = conHelper.exec(
selectLastModifiedSQL, new Object[]{parentDir, name}, false, 0);
if (!rs.next()) {
throw new FileSystemException("no such file system entry: " + path);
}
return rs.getLong(1);
} catch (SQLException e) {
String msg = "failed to determine lastModified of file system entry: " + path;
log.error(msg, e);
throw new FileSystemException(msg, e);
} finally {
DbUtility.close(rs);
}
}
}
/**
* {@inheritDoc}
*/
public long length(String filePath) throws FileSystemException {
if (!initialized) {
throw new IllegalStateException("not initialized");
}
FileSystemPathUtil.checkFormat(filePath);
String parentDir = FileSystemPathUtil.getParentDir(filePath);
String name = FileSystemPathUtil.getName(filePath);
synchronized (selectLengthSQL) {
ResultSet rs = null;
try {
rs = conHelper.exec(
selectLengthSQL, new Object[]{parentDir, name}, false, 0);
if (!rs.next()) {
throw new FileSystemException("no such file: " + filePath);
}
return rs.getLong(1);
} catch (SQLException e) {
String msg = "failed to determine length of file: " + filePath;
log.error(msg, e);
throw new FileSystemException(msg, e);
} finally {
DbUtility.close(rs);
}
}
}
/**
* {@inheritDoc}
*/
public boolean hasChildren(String path) throws FileSystemException {
if (!initialized) {
throw new IllegalStateException("not initialized");
}
FileSystemPathUtil.checkFormat(path);
if (!exists(path)) {
throw new FileSystemException("no such file system entry: " + path);
}
synchronized (selectChildCountSQL) {
ResultSet rs = null;
try {
rs = conHelper.exec(selectChildCountSQL, new Object[]{path}, false, 0);
if (!rs.next()) {
return false;
}
int count = rs.getInt(1);
if (FileSystemPathUtil.denotesRoot(path)) {
// ingore file system root entry
count--;
}
return (count > 0);
} catch (SQLException e) {
String msg = "failed to determine child count of file system entry: " + path;
log.error(msg, e);
throw new FileSystemException(msg, e);
} finally {
DbUtility.close(rs);
}
}
}
/**
* {@inheritDoc}
*/
public String[] list(String folderPath) throws FileSystemException {
if (!initialized) {
throw new IllegalStateException("not initialized");
}
FileSystemPathUtil.checkFormat(folderPath);
if (!isFolder(folderPath)) {
throw new FileSystemException("no such folder: " + folderPath);
}
synchronized (selectFileAndFolderNamesSQL) {
ResultSet rs = null;
try {
rs = conHelper.exec(
selectFileAndFolderNamesSQL, new Object[]{folderPath}, false, 0);
ArrayList<String> names = new ArrayList<String>();
while (rs.next()) {
String name = rs.getString(1);
if (name.length() == 0
&& FileSystemPathUtil.denotesRoot(folderPath)) {
// this is the file system root entry, skip...
continue;
}
names.add(name);
}
return names.toArray(new String[names.size()]);
} catch (SQLException e) {
String msg = "failed to list child entries of folder: " + folderPath;
log.error(msg, e);
throw new FileSystemException(msg, e);
} finally {
DbUtility.close(rs);
}
}
}
/**
* {@inheritDoc}
*/
public String[] listFiles(String folderPath) throws FileSystemException {
if (!initialized) {
throw new IllegalStateException("not initialized");
}
FileSystemPathUtil.checkFormat(folderPath);
if (!isFolder(folderPath)) {
throw new FileSystemException("no such folder: " + folderPath);
}
synchronized (selectFileNamesSQL) {
ResultSet rs = null;
try {
rs = conHelper.exec(
selectFileNamesSQL, new Object[]{folderPath}, false, 0);
ArrayList<String> names = new ArrayList<String>();
while (rs.next()) {
names.add(rs.getString(1));
}
return names.toArray(new String[names.size()]);
} catch (SQLException e) {
String msg = "failed to list file entries of folder: " + folderPath;
log.error(msg, e);
throw new FileSystemException(msg, e);
} finally {
DbUtility.close(rs);
}
}
}
/**
* {@inheritDoc}
*/
public String[] listFolders(String folderPath) throws FileSystemException {
if (!initialized) {
throw new IllegalStateException("not initialized");
}
FileSystemPathUtil.checkFormat(folderPath);
if (!isFolder(folderPath)) {
throw new FileSystemException("no such folder: " + folderPath);
}
synchronized (selectFolderNamesSQL) {
ResultSet rs = null;
try {
rs = conHelper.exec(
selectFolderNamesSQL, new Object[]{folderPath}, false, 0);
ArrayList<String> names = new ArrayList<String>();
while (rs.next()) {
String name = rs.getString(1);
if (name.length() == 0
&& FileSystemPathUtil.denotesRoot(folderPath)) {
// this is the file system root entry, skip...
continue;
}
names.add(name);
}
return (String[]) names.toArray(new String[names.size()]);
} catch (SQLException e) {
String msg = "failed to list folder entries of folder: " + folderPath;
log.error(msg, e);
throw new FileSystemException(msg, e);
} finally {
DbUtility.close(rs);
}
}
}
/**
* {@inheritDoc}
*/
public InputStream getInputStream(String filePath) throws FileSystemException {
if (!initialized) {
throw new IllegalStateException("not initialized");
}
FileSystemPathUtil.checkFormat(filePath);
String parentDir = FileSystemPathUtil.getParentDir(filePath);
String name = FileSystemPathUtil.getName(filePath);
synchronized (selectDataSQL) {
try {
final ResultSet rs = conHelper.exec(
selectDataSQL, new Object[]{parentDir, name}, false, 0);
if (!rs.next()) {
throw new FileSystemException("no such file: " + filePath);
}
InputStream in = rs.getBinaryStream(1);
/**
* return an InputStream wrapper in order to
* close the ResultSet when the stream is closed
*/
return new FilterInputStream(in) {
public void close() throws IOException {
super.close();
// close ResultSet
DbUtility.close(rs);
}
};
} catch (SQLException e) {
String msg = "failed to retrieve data of file: " + filePath;
log.error(msg, e);
throw new FileSystemException(msg, e);
}
}
}
/**
* {@inheritDoc}
*/
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 write(byte[] bytes, int off, int len) throws IOException {
out.write(bytes, off, len);
}
public void close() throws IOException {
out.flush();
((FileOutputStream) out).getFD().sync();
out.close();
InputStream in = null;
try {
if (isFile(filePath)) {
synchronized (updateDataSQL) {
long length = tmpFile.length();
in = new FileInputStream(tmpFile);
conHelper.exec(updateDataSQL,
new Object[]{
new StreamWrapper(in, length),
new Long(System.currentTimeMillis()),
new Long(length),
parentDir,
name
});
}
} else {
synchronized (insertFileSQL) {
long length = tmpFile.length();
in = new FileInputStream(tmpFile);
conHelper.exec(insertFileSQL,
new Object[]{
parentDir,
name,
new StreamWrapper(in, length),
new Long(System.currentTimeMillis()),
new Long(length)
});
}
}
} catch (Exception e) {
IOException ioe = new IOException(e.getMessage());
ioe.initCause(e);
throw ioe;
} finally {
if (in != null) {
in.close();
}
// 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);
}
}
//----------------------------------< misc. helper methods & overridables >
/**
* Builds the SQL statements
*/
protected void buildSQLStatements() {
insertFileSQL = "insert into "
+ schemaObjectPrefix + "FSENTRY "
+ "(FSENTRY_PATH, FSENTRY_NAME, FSENTRY_DATA, "
+ "FSENTRY_LASTMOD, FSENTRY_LENGTH) "
+ "values (?, ?, ?, ?, ?)";
insertFolderSQL = "insert into "
+ schemaObjectPrefix + "FSENTRY "
+ "(FSENTRY_PATH, FSENTRY_NAME, FSENTRY_LASTMOD, FSENTRY_LENGTH) "
+ "values (?, ?, ?, 0)";
updateDataSQL = "update "
+ schemaObjectPrefix + "FSENTRY "
+ "set FSENTRY_DATA = ?, FSENTRY_LASTMOD = ?, FSENTRY_LENGTH = ? "
+ "where FSENTRY_PATH = ? and FSENTRY_NAME = ? "
+ "and FSENTRY_DATA is not null";
updateLastModifiedSQL = "update "
+ schemaObjectPrefix + "FSENTRY set FSENTRY_LASTMOD = ? "
+ "where FSENTRY_PATH = ? and FSENTRY_NAME = ? "
+ "and FSENTRY_DATA is not null";
selectExistSQL = "select 1 from "
+ schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? "
+ "and FSENTRY_NAME = ?";
selectFileExistSQL = "select 1 from "
+ schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? "
+ "and FSENTRY_NAME = ? and FSENTRY_DATA is not null";
selectFolderExistSQL = "select 1 from "
+ schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? "
+ "and FSENTRY_NAME = ? and FSENTRY_DATA is null";
selectFileNamesSQL = "select FSENTRY_NAME from "
+ schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? "
+ "and FSENTRY_DATA is not null";
selectFolderNamesSQL = "select FSENTRY_NAME from "
+ schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? "
+ "and FSENTRY_DATA is null";
selectFileAndFolderNamesSQL = "select FSENTRY_NAME from "
+ schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ?";
selectChildCountSQL = "select count(FSENTRY_NAME) from "
+ schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? ";
selectDataSQL = "select FSENTRY_DATA from "
+ schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? "
+ "and FSENTRY_NAME = ? and FSENTRY_DATA is not null";
selectLastModifiedSQL = "select FSENTRY_LASTMOD from "
+ schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? "
+ "and FSENTRY_NAME = ?";
selectLengthSQL = "select FSENTRY_LENGTH from "
+ schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? "
+ "and FSENTRY_NAME = ? and FSENTRY_DATA is not null";
deleteFileSQL = "delete from "
+ schemaObjectPrefix + "FSENTRY where FSENTRY_PATH = ? "
+ "and FSENTRY_NAME = ? and FSENTRY_DATA is not null";
deleteFolderSQL = "delete from "
+ schemaObjectPrefix + "FSENTRY where "
+ "(FSENTRY_PATH = ? and FSENTRY_NAME = ? and FSENTRY_DATA is null) "
+ "or (FSENTRY_PATH = ?) "
+ "or (FSENTRY_PATH like ?) ";
copyFileSQL = "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";
copyFilesSQL = "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";
}
/**
* Verifies that the root file system entry exists. If it doesn't exist yet
* it will be automatically created.
*
* @throws Exception if an error occurs
*/
protected void verifyRootExists() throws Exception {
// check if root file system entry exists
synchronized (selectFolderExistSQL) {
ResultSet rs = null;
try {
rs = conHelper.exec(
selectFolderExistSQL,
new Object[]{FileSystem.SEPARATOR, ""}, false, 0);
if (rs.next()) {
// root entry exists
return;
}
} catch (SQLException e) {
String msg = "failed to check existence of file system root entry";
log.error(msg, e);
throw new FileSystemException(msg, e);
} finally {
DbUtility.close(rs);
}
}
// the root entry doesn't exist yet, create it...
createDeepFolder(FileSystem.SEPARATOR);
}
/**
* Creates the specified files system folder entry, recursively creating
* any non-existing intermediate folder entries.
*
* @param folderPath folder entry to create
* @throws FileSystemException if an error occurs
*/
protected void createDeepFolder(String folderPath)
throws FileSystemException {
String parentDir = FileSystemPathUtil.getParentDir(folderPath);
String name = FileSystemPathUtil.getName(folderPath);
if (!FileSystemPathUtil.denotesRoot(folderPath)) {
if (!exists(parentDir)) {
createDeepFolder(parentDir);
}
}
synchronized (insertFolderSQL) {
try {
conHelper.exec(
insertFolderSQL,
new Object[]{
parentDir,
name,
new Long(System.currentTimeMillis())});
} catch (SQLException e) {
String msg = "failed to create folder entry: " + folderPath;
log.error(msg, e);
throw new FileSystemException(msg, e);
}
}
}
}