All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.modeshape.jcr.value.binary.Database Maven / Gradle / Ivy

There is a newer version: 5.4.1.Final
Show newest version
/*
 * ModeShape (http://www.modeshape.org)
 * See the COPYRIGHT.txt file distributed with this work for information
 * regarding copyright ownership.  Some portions may be licensed
 * to Red Hat, Inc. under one or more contributor license agreements.
 * See the AUTHORS.txt file in the distribution for a full listing of
 * individual contributors.
 *
 * ModeShape is free software. Unless otherwise indicated, all code in ModeShape
 * is licensed to you under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * ModeShape is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package org.modeshape.jcr.value.binary;

import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import org.modeshape.common.logging.Logger;
import org.modeshape.common.util.StringUtil;
import org.modeshape.jcr.JcrI18n;
import org.modeshape.jcr.value.BinaryKey;

/**
 * Helper class for manipulation with database.
 * 

* This class looks for database SQL statements in properties files named "binary_store_{type}_database.properties" * located within the "org/modeshape/jcr/database" area of the classpath, where "{type}" is {@link #determineType() * determined} from the connection, and matches one of the following: *

    *
  • mysql
  • *
  • postgres
  • *
  • derby
  • *
  • hsql
  • *
  • h2
  • *
  • sqlite
  • *
  • db2
  • *
  • db2_390
  • *
  • informix
  • *
  • interbase
  • *
  • firebird
  • *
  • sqlserver
  • *
  • access
  • *
  • oracle
  • *
  • sybase
  • *
* If the corresponding file is not found on the classpath, then the "binary_store_default_database.properties" file * is used. *

*

* Each property file should contain the set of DDL and DML statements that are used by the binary store, and the * database-specific file allows database-specific schemas and queries to be used. If the properties file that corresponds to the * connection's database type is not found on the classpath, then the "binary_store_default_database.properties" file * is used. *

*

* ModeShape does not provide out-of-the-box properties files for each of the database types listed above. If you run into any * problems, you can override the statements by providing a property file that matches the naming pattern described above, and by * putting that file on the classpath. (If you want to override one of ModeShape's out-of-the-box properties files, then be sure * to put your custom file first on the classpath.) *

* * @author kulikov */ public class Database { private static final Logger LOGGER = Logger.getLogger(Database.class); public static final String TABLE_NAME = "CONTENT_STORE"; public static final String STATEMENTS_FILE_PATH = "org/modeshape/jcr/database/"; protected static final String STATEMENTS_FILE_PREFIX = "binary_store_"; protected static final String STATEMENTS_FILENAME_SUFFIX = "_database.properties"; protected static final String DEFAULT_STATEMENTS_FILE_PATH = STATEMENTS_FILE_PATH + STATEMENTS_FILE_PREFIX + "default" + STATEMENTS_FILENAME_SUFFIX; public static enum Type { MYSQL, POSTGRES, DERBY, HSQL, H2, SQLITE, DB2, DB2_390, INFORMIX, INTERBASE, FIREBIRD, SQLSERVER, ACCESS, ORACLE, SYBASE, CASSANDRA, UNKNOWN; } private final Connection connection; private final Type databaseType; private final String prefix; private final String tableName; private final Properties statements; private PreparedStatement addContentSql; private PreparedStatement getUsedContentSql; private PreparedStatement getUnusedContentSql; private PreparedStatement markUnusedSql; private PreparedStatement markUsedSql; private PreparedStatement removedExpiredSql; private PreparedStatement getMimeType; private PreparedStatement setMimeType; private PreparedStatement getExtractedTextSql; private PreparedStatement setExtractedTextSql; private PreparedStatement getBinaryKeysSql; /** * Creates new instance of the database. * * @param connection connection to a database * @throws BinaryStoreException if the database type cannot be determined */ public Database( Connection connection ) throws BinaryStoreException { this(connection, null, null); } /** * Creates new instance of the database. * * @param connection connection to a database * @param type the type of database; may be null if the type is to be determined * @param prefix the prefix for the table name; may be null or blank * @throws BinaryStoreException if the database type cannot be determined */ public Database( Connection connection, Type type, String prefix ) throws BinaryStoreException { assert connection != null; this.connection = connection; this.databaseType = type != null ? type : determineType(); this.prefix = prefix == null ? null : prefix.trim(); this.tableName = this.prefix != null && this.prefix.length() != 0 ? this.prefix + TABLE_NAME : TABLE_NAME; LOGGER.debug("Discovered DBMS type for binary store as '{0}' on {1}", databaseType, connection); try { // Load the default statements ... String statementsFilename = DEFAULT_STATEMENTS_FILE_PATH; InputStream statementStream = getClass().getClassLoader().getResourceAsStream(statementsFilename); Properties defaultStatements = new Properties(); try { LOGGER.trace("Loading default statement from '{0}'", statementsFilename); defaultStatements.load(statementStream); } finally { statementStream.close(); } // Look for type-specific statements ... statementsFilename = STATEMENTS_FILE_PATH + STATEMENTS_FILE_PREFIX + databaseType.name().toLowerCase() + STATEMENTS_FILENAME_SUFFIX; statementStream = getClass().getClassLoader().getResourceAsStream(statementsFilename); if (statementStream != null) { // Try to read the type-specific statements ... try { LOGGER.trace("Loading DBMS-specific statement from '{0}'", statementsFilename); statements = new Properties(defaultStatements); statements.load(statementStream); } finally { statementStream.close(); } } else { // No type-specific statements, so just use the default statements ... statements = defaultStatements; LOGGER.trace("No DBMS-specific statement found in '{0}'", statementsFilename); } } catch (IOException e) { throw new BinaryStoreException(e); } } /** * Prepare this instance and the underlying database for usage. * * @throws BinaryStoreException if there is a problem */ public void initialize() throws BinaryStoreException { try { // First, prepare a statement to see if the table exists ... boolean createTable = true; try { PreparedStatement exists = prepareStatement("table_exists_query"); LOGGER.trace("Running statement: {0}", exists); exists.execute(); exists.close(); createTable = false; } catch (SQLException e) { // proceed to create the table ... } if (createTable) { LOGGER.debug("Unable to find existing table. Attempting to create '{0}' table in {1}", tableName, connection); try { PreparedStatement create = prepareStatement("create_table"); LOGGER.trace("Running statement: {0}", create); create.execute(); create.close(); } catch (SQLException e) { String msg = JcrI18n.errorCreatingDatabaseTable.text(tableName, databaseType, connection, e.getMessage()); throw new BinaryStoreException(msg); } } // Now prepare all of the SQL statements ... addContentSql = prepareStatement("add_content"); getUsedContentSql = prepareStatement("get_used_content"); getUnusedContentSql = prepareStatement("get_unused_content"); markUnusedSql = prepareStatement("mark_unused"); markUsedSql = prepareStatement("mark_used"); removedExpiredSql = prepareStatement("remove_expired"); getMimeType = prepareStatement("get_mimetype"); setMimeType = prepareStatement("set_mimetype"); getExtractedTextSql = prepareStatement("get_extracted_text"); setExtractedTextSql = prepareStatement("set_extracted_text"); getBinaryKeysSql = prepareStatement("get_binary_keys"); } catch (SQLException e) { throw new BinaryStoreException(e); } } protected PreparedStatement prepareStatement( String statementKey ) throws SQLException { String statementString = statements.getProperty(statementKey); statementString = StringUtil.createString(statementString, tableName); LOGGER.trace("Preparing statement: {0}", statementString); return connection.prepareStatement(statementString); } protected Type determineType() throws BinaryStoreException { try { String name = connection.getMetaData().getDatabaseProductName().toLowerCase(); if (name.toLowerCase().contains("mysql")) { return Type.MYSQL; } else if (name.contains("postgres")) { return Type.POSTGRES; } else if (name.contains("derby")) { return Type.DERBY; } else if (name.contains("hsql") || name.toLowerCase().contains("hypersonic")) { return Type.HSQL; } else if (name.contains("h2")) { return Type.H2; } else if (name.contains("sqlite")) { return Type.SQLITE; } else if (name.contains("db2")) { return Type.DB2; } else if (name.contains("informix")) { return Type.INFORMIX; } else if (name.contains("interbase")) { return Type.INTERBASE; } else if (name.contains("firebird")) { return Type.FIREBIRD; } else if (name.contains("sqlserver") || name.toLowerCase().contains("microsoft")) { return Type.SQLSERVER; } else if (name.contains("access")) { return Type.ACCESS; } else if (name.contains("oracle")) { return Type.ORACLE; } else if (name.contains("adaptive")) { return Type.SYBASE; } else if (name.contains("Cassandra")) { return Type.CASSANDRA; } return Type.UNKNOWN; } catch (SQLException e) { throw new BinaryStoreException(e); } } /** * Closes connection with database. */ public void disconnect() { if (connection != null) { boolean failed = false; try { if (addContentSql != null) addContentSql.close(); if (getUsedContentSql != null) getUsedContentSql.close(); if (getUnusedContentSql != null) getUnusedContentSql.close(); if (markUnusedSql != null) markUnusedSql.close(); if (markUsedSql != null) markUsedSql.close(); if (removedExpiredSql != null) removedExpiredSql.close(); if (getMimeType != null) getMimeType.close(); if (setMimeType != null) setMimeType.close(); if (getExtractedTextSql != null) getExtractedTextSql.close(); if (setExtractedTextSql != null) setExtractedTextSql.close(); if (getBinaryKeysSql != null) getBinaryKeysSql.close(); } catch (SQLException e) { failed = true; throw new RuntimeException(e); } finally { try { connection.close(); } catch (SQLException e) { if (!failed) throw new RuntimeException(e); } finally { addContentSql = null; getUsedContentSql = null; getUnusedContentSql = null; markUnusedSql = null; markUsedSql = null; removedExpiredSql = null; getMimeType = null; setMimeType = null; getExtractedTextSql = null; setExtractedTextSql = null; getBinaryKeysSql = null; } } } } /** * The connection that this object is using. * * @return the connection; never null */ public Connection getConnection() { return connection; } /** * Shows type of this database. * * @return database type identifier. */ public Type getDatabaseType() { return databaseType; } /** * Current time. * * @return current time in milliseconds */ private long now() { return new java.util.Date().getTime(); } /** * Create statement for store content. * * @param key unique content identifier * @param stream content to store * @return SQL statement. * @throws BinaryStoreException */ public PreparedStatement insertContentSQL( BinaryKey key, InputStream stream ) throws BinaryStoreException { try { addContentSql.setString(1, key.toString()); addContentSql.setTimestamp(2, new java.sql.Timestamp(now())); addContentSql.setBinaryStream(3, stream); return addContentSql; } catch (SQLException e) { throw new BinaryStoreException(e); } } /** * Generates SQL statement for content retrieve. * * @param key content id * @param inUse true if the binary given by the key is expected to be still be in use, or false if the binary can be no longer * used * @return executable SQL statement * @throws BinaryStoreException */ public PreparedStatement retrieveContentSQL( BinaryKey key, boolean inUse ) throws BinaryStoreException { try { PreparedStatement sql = inUse ? getUsedContentSql : getUnusedContentSql; sql.setString(1, key.toString()); return sql; } catch (SQLException e) { throw new BinaryStoreException(e); } } /** * Generates SQL statement which marks content as not used. * * @param key the content id. * @return SQL statement. * @throws BinaryStoreException */ public PreparedStatement markUnusedSQL( BinaryKey key ) throws BinaryStoreException { try { markUnusedSql.setTimestamp(1, new java.sql.Timestamp(now())); markUnusedSql.setString(2, key.toString()); return markUnusedSql; } catch (SQLException e) { throw new BinaryStoreException(e); } } /** * Generates SQL statement which marks content as used. * * @param key the content id. * @return SQL statement. * @throws BinaryStoreException */ public PreparedStatement restoreContentSQL( BinaryKey key ) throws BinaryStoreException { try { markUsedSql.setString(1, key.toString()); return markUsedSql; } catch (SQLException e) { throw new BinaryStoreException(e); } } /** * Generates SQL statement which removes expired content. * * @param deadline expire time * @return SQL statement. * @throws BinaryStoreException */ public PreparedStatement removeExpiredContentSQL( long deadline ) throws BinaryStoreException { try { removedExpiredSql.setTimestamp(1, new java.sql.Timestamp(deadline)); return removedExpiredSql; } catch (SQLException e) { throw new BinaryStoreException(e); } } /** * Generates SQL statement for mime type retrieve. * * @param key content id * @return SQL statement. * @throws BinaryStoreException */ public PreparedStatement retrieveMimeTypeSQL( BinaryKey key ) throws BinaryStoreException { try { getMimeType.setString(1, key.toString()); return getMimeType; } catch (SQLException e) { throw new BinaryStoreException(e); } } /** * Generates SQL statement which modifies mime type value. * * @param key content id * @param mimeType the new value for mime type * @return SQL statement * @throws BinaryStoreException */ public PreparedStatement updateMimeTypeSQL( BinaryKey key, String mimeType ) throws BinaryStoreException { try { setMimeType.setString(1, mimeType); setMimeType.setString(2, key.toString()); return setMimeType; } catch (SQLException e) { throw new BinaryStoreException(e); } } /** * Generate SQL statement which returns extracted text. * * @param key content id * @return SQL statement * @throws BinaryStoreException */ public PreparedStatement retrieveExtTextSQL( BinaryKey key ) throws BinaryStoreException { try { getExtractedTextSql.setString(1, key.toString()); return getExtractedTextSql; } catch (SQLException e) { throw new BinaryStoreException(e); } } /** * Generates SQL statement which updates extracted text field. * * @param key content id * @param text new value for the extracted text * @return SQL statement * @throws BinaryStoreException */ public PreparedStatement updateExtTextSQL( BinaryKey key, String text ) throws BinaryStoreException { try { setExtractedTextSql.setString(1, text); setExtractedTextSql.setString(2, key.toString()); return setExtractedTextSql; } catch (SQLException e) { throw new BinaryStoreException(e); } } /** * Generates SQL statement for retrieving the binary keys in the store. * * @param keys the container into which the keys should be placed * @return executable SQL statement * @throws BinaryStoreException */ public PreparedStatement retrieveBinaryKeys( Set keys ) throws BinaryStoreException { return getBinaryKeysSql; } /** * Executes specifies statement. * * @param sql the statement to execute * @throws BinaryStoreException */ public static void execute( PreparedStatement sql ) throws BinaryStoreException { try { LOGGER.trace("Running statement: {0}", sql); sql.execute(); } catch (SQLException e) { throw new BinaryStoreException(e); } } /** * Runs SQL statement * * @param sql SQL statement * @return result of statement execution * @throws BinaryStoreException */ public static ResultSet executeQuery( PreparedStatement sql ) throws BinaryStoreException { try { LOGGER.trace("Running statement: {0}", sql); return sql.executeQuery(); } catch (SQLException e) { throw new BinaryStoreException(e); } } /** * Executes specifies update statement. * * @param sql the statement to execute * @throws BinaryStoreException */ public static void executeUpdate( PreparedStatement sql ) throws BinaryStoreException { try { LOGGER.trace("Running statement: {0}", sql); sql.executeUpdate(); } catch (SQLException e) { throw new BinaryStoreException(e); } } /** * Provides access to query data * * @param rs retrieved single value * @return result as input stream. * @throws BinaryStoreException */ public static InputStream asStream( ResultSet rs ) throws BinaryStoreException { boolean error = false; try { if (!rs.next()) { return null; } return rs.getBinaryStream(1); } catch (SQLException e) { error = true; throw new BinaryStoreException(e); } catch (RuntimeException e) { error = true; throw e; } finally { // Always close the result set ... try { rs.close(); } catch (SQLException e) { if (!error) throw new BinaryStoreException(e); } } } /** * Provides access to query data * * @param rs retrieved query result * @return result as string. * @throws BinaryStoreException */ public static String asString( ResultSet rs ) throws BinaryStoreException { boolean error = false; try { if (!rs.next()) { return null; } return rs.getString(1); } catch (SQLException e) { error = true; throw new BinaryStoreException(e); } catch (RuntimeException e) { error = true; throw e; } finally { // Always close the result set ... try { rs.close(); } catch (SQLException e) { if (!error) throw new BinaryStoreException(e); } } } /** * Provides access to query data * * @param rs retrieved query result * @return result as string. * @throws BinaryStoreException */ public static List asStringList( ResultSet rs ) throws BinaryStoreException { boolean error = false; List result = new ArrayList(); try { while (rs.next()) { result.add(rs.getString(1)); } } catch (SQLException e) { error = true; throw new BinaryStoreException(e); } catch (RuntimeException e) { error = true; throw e; } finally { // Always close the result set ... try { rs.close(); } catch (SQLException e) { if (!error) throw new BinaryStoreException(e); } } return result; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy