JDBCStore.java
| Index Score | ||
|---|---|---|
![]() |
![]() |
org.apache.slide.store.impl.rdbms |
![]() |
![]() |
Jakarta Slide |
View: Reasons, Metrics, Source Code
These are the metrics that contribute to the Enerjy Score for this file, ranked by impact. So the metrics listed at the top influence the score to a greater extent that the metrics listed at the bottom.
/*
* $Header$
* $Revision: 208628 $
* $Date: 2005-06-13 08:55:20 -0400 (Mon, 13 Jun 2005) $
*
* ====================================================================
*
* Copyright 1999-2005 The Apache Software Foundation
*
* Licensed 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.slide.store.impl.rdbms;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Properties;
import org.apache.commons.dbcp.BasicDataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;
import org.apache.slide.common.NamespaceAccessToken;
import org.apache.slide.common.ServiceInitializationFailedException;
import org.apache.slide.common.ServiceParameterErrorException;
import org.apache.slide.common.ServiceParameterMissingException;
import org.apache.slide.common.ServiceDisconnectionFailedException;
import org.apache.slide.common.ServiceConnectionFailedException;
import org.apache.slide.store.ContentStore;
import org.apache.slide.store.LockStore;
import org.apache.slide.store.NodeStore;
import org.apache.slide.store.RevisionDescriptorStore;
import org.apache.slide.store.RevisionDescriptorsStore;
import org.apache.slide.store.SecurityStore;
import org.apache.slide.util.logger.Logger;
/**
* Store implementation that is able to store all information (like structure,
* locks and content) in a JDBC-aware relational database system.
* <p>
* Set the {@link #CONF_KEY_DBCP_ENABLED} configuration attribute to true
* to enable Commons DBCP connection pooling.
*
* @version $Revision: 208628 $
* @see <a href="http://jakarta.apache.org/slide/howto-j2eestore.html">Slide Configuration HOWTO</a>
* for complete configuration information
*/
public class JDBCStore
extends AbstractRDBMSStore
implements LockStore, NodeStore, RevisionDescriptorsStore, RevisionDescriptorStore, SecurityStore, ContentStore {
/** Configuration key: "true"=use Commons DBCP connection pooling. */
protected static final String CONF_KEY_DBCP_ENABLED = "dbcpPooling";
/**
* Configuration key prefix for all Commons DBCP settings.
* To pass properties directly to the underlying JDBC-driver,
* use the <b>{@link #CONF_KEY_DBCP_PREFIX}.connectionProperties</b>
* configuration property in your Slide domain configuration,
* set the value to semicolon-separated name=value pairs
* (eg "cachePreparedStatements=true;rowPrefetchSize=50;foo=bar").
* @see <a href="http://jakarta.apache.org/commons/dbcp/configuration.html">
* Commons DBCP website</a> for info about possible settings
*/
protected static final String CONF_KEY_DBCP_PREFIX = "dbcp.";
protected static final String TRANSACTION_NONE = "NONE";
protected static final String TRANSACTION_READ_UNCOMMITTED = "READ_UNCOMMITTED";
protected static final String TRANSACTION_READ_COMMITTED = "READ_COMMITTED";
protected static final String TRANSACTION_REPEATABLE_READ = "REPEATABLE_READ";
protected static final String TRANSACTION_SERIALIZABLE = "SERIALIZABLE";
public static final int DEFAUT_ISOLATION_LEVEL = Connection.TRANSACTION_READ_COMMITTED;
protected static String isolationLevelToString(int isolationLevel) {
final String levelString;
switch (isolationLevel) {
case Connection.TRANSACTION_NONE :
levelString = TRANSACTION_NONE;
break;
case Connection.TRANSACTION_READ_UNCOMMITTED :
levelString = TRANSACTION_READ_UNCOMMITTED;
break;
case Connection.TRANSACTION_READ_COMMITTED :
levelString = TRANSACTION_READ_COMMITTED;
break;
case Connection.TRANSACTION_REPEATABLE_READ :
levelString = TRANSACTION_REPEATABLE_READ;
break;
case Connection.TRANSACTION_SERIALIZABLE :
levelString = TRANSACTION_SERIALIZABLE;
break;
default :
levelString = "UNKNOWN";
break;
}
return levelString;
}
protected static int stringToIsolationLevelToString(String levelString) {
final int transactionIsolationLevel;
if (TRANSACTION_NONE.equals(levelString)) {
transactionIsolationLevel = Connection.TRANSACTION_NONE;
} else if (TRANSACTION_READ_UNCOMMITTED.equals(levelString)) {
transactionIsolationLevel = Connection.TRANSACTION_READ_UNCOMMITTED;
} else if (TRANSACTION_READ_COMMITTED.equals(levelString)) {
transactionIsolationLevel = Connection.TRANSACTION_READ_COMMITTED;
} else if (TRANSACTION_REPEATABLE_READ.equals(levelString)) {
transactionIsolationLevel = Connection.TRANSACTION_REPEATABLE_READ;
} else if (TRANSACTION_SERIALIZABLE.equals(levelString)) {
transactionIsolationLevel = Connection.TRANSACTION_SERIALIZABLE;
} else {
transactionIsolationLevel = -1;
}
return transactionIsolationLevel;
}
// ----------------------------------------------------- Instance Variables
/** JDBC driver class name. */
protected String driver;
/** JDBC connection URL. */
protected String url;
/** Database user-name. */
protected String user;
/** Database password. */
protected String password;
/** Transaction isolation level. */
protected int isolationLevel;
/** Switch for enabling Commons DBCP connection pooling. */
protected boolean useDbcpPooling;
/** Properties set from Store configuration, to be used with DBCP. */
protected Properties dbcpProperties;
/** Connection pool DataSource (set only if using Commons DBCP). */
protected BasicDataSource dbcpDataSource;
// -------------------------------------------------------- Service Methods
/**
* Initializes the data source with a set of parameters.
*
* @param parameters a Hashtable containing the parameters' name and
* associated value
* @exception ServiceParameterErrorException a service parameter holds an
* invalid value
* @exception ServiceParameterMissingException a required parameter is
* missing
*/
public void setParameters(Hashtable parameters)
throws ServiceParameterErrorException, ServiceParameterMissingException {
String value;
// Driver classname
value = (String) parameters.get("driver");
if (value == null) {
throw new ServiceParameterMissingException(this, "driver");
} else {
driver = value;
}
// Connection url
value = (String) parameters.get("url");
if (value == null) {
throw new ServiceParameterMissingException(this, "url");
} else {
url = value;
}
// User name
user = "";
value = (String) parameters.get("user");
if (value != null) {
user = value;
}
// Password
password = "";
value = (String) parameters.get("password");
if (value != null) {
password = value;
}
// Transaction isolation level
isolationLevel = DEFAUT_ISOLATION_LEVEL;
value = (String) parameters.get("isolation");
if (value != null) {
isolationLevel = stringToIsolationLevelToString(value);
if (isolationLevel == -1) {
getLogger().log(
"Could not set isolation level '"
+ value
+ "', allowed levels are "
+ TRANSACTION_NONE
+ ", "
+ TRANSACTION_READ_UNCOMMITTED
+ ", "
+ TRANSACTION_READ_COMMITTED
+ ", "
+ TRANSACTION_REPEATABLE_READ
+ ", "
+ TRANSACTION_SERIALIZABLE,
LOG_CHANNEL,
Logger.WARNING);
isolationLevel = DEFAUT_ISOLATION_LEVEL;
}
}
// Connection pooling
useDbcpPooling = false;
value = (String) parameters.get(CONF_KEY_DBCP_ENABLED);
if (value != null) {
useDbcpPooling = "true".equals(value);
}
if (useDbcpPooling) {
// Set up configuration properties to be used with Commons DBCP
dbcpProperties = getDbcpPoolProperties(parameters);
// Add driver and logon information
dbcpProperties.put("driverClassName", driver);
dbcpProperties.put("url", url);
dbcpProperties.put("username", user);
dbcpProperties.put("password", password);
// Set TX isolation level
final String isolationLevelString;
isolationLevelString = isolationLevelToString(isolationLevel);
dbcpProperties.put("defaultTransactionIsolation",
isolationLevelString);
// Turn off autocommit
dbcpProperties.put("defaultAutoCommit",
String.valueOf(Boolean.FALSE));
}
super.setParameters(parameters);
}
/**
* Initializes this store.
* <p/>
* If Commons DBCP is used, initialization is done by:
* <ol>
* <li>Loading JDBC-driver class (and running static initializers)</li>
* </ol>
* DBCP will handled DriverManager registration internally, which will
* (together with further initialization of Connection pool) occur in
* the {@link #connect} method.
* <p/>
* Otherwise (ie not using DBCP), initialization is done by:
* <ol>
* <li>Loading JDBC-driver class (and running static initializers)</li>
* <li>Instantiating Driver instance</li>
* <li>Driver registration in the JDBC DriverManager</li>
* </ol>
*
* @exception ServiceInitializationFailedException if JDBC driver
* classloading or registration fails
*/
public synchronized void initialize(NamespaceAccessToken token) throws ServiceInitializationFailedException {
// XXX might be done already in setParameter
if (!alreadyInitialized) {
try {
// Load driver class and force static init
getLogger().log("Loading and registering driver '" + driver + "'", LOG_CHANNEL, Logger.INFO);
final ClassLoader cl = Thread.currentThread().getContextClassLoader();
final Class driverClass = Class.forName(driver, true, cl);
// Use Commons DBCP pooling if enabled
if (useDbcpPooling) {
getLogger().log("Using DBCP pooling", LOG_CHANNEL, Logger.INFO);
} else {
// Register Driver instance with JDBC DriverManager
final Driver driverInstance = (Driver) driverClass.newInstance();
DriverManager.registerDriver(driverInstance);
getLogger().log("Not using DBCP pooling", LOG_CHANNEL, Logger.WARNING);
}
} catch (Exception e) {
getLogger().log(
"Loading and registering driver '" + driver + "' failed (" + e.getMessage() + ")",
LOG_CHANNEL,
Logger.ERROR);
throw new ServiceInitializationFailedException(this, e);
} finally {
alreadyInitialized = true;
}
}
}
public void connect() throws ServiceConnectionFailedException {
super.connect();
if (useDbcpPooling) {
try {
dbcpDataSource = (BasicDataSource)
BasicDataSourceFactory.createDataSource(dbcpProperties);
// The BasicDataSource has lazy initialization
// borrowing a connection will start the DataSource
// and make sure it is configured correctly.
final Connection conn = dbcpDataSource.getConnection();
conn.close();
} catch (Exception e) {
getLogger().log(
"Initialization of connection pool failed ("
+ e.getMessage() + ")",
LOG_CHANNEL, Logger.ERROR);
throw new ServiceConnectionFailedException(this, e);
} finally {
logConnectionPoolStatistics();
}
}
}
public boolean isConnected() {
if (useDbcpPooling) {
return dbcpDataSource != null;
}
return super.isConnected();
}
public void disconnect() throws ServiceDisconnectionFailedException {
if (useDbcpPooling) {
if (dbcpDataSource != null) {
try {
dbcpDataSource.close();
} catch (SQLException e) {
getLogger().log(
"Decomissioning of connection pool failed ("
+ e.getMessage() + ")",
LOG_CHANNEL, Logger.ERROR);
throw new ServiceDisconnectionFailedException(this, e);
}
dbcpDataSource = null;
}
}
super.disconnect();
}
protected Connection getNewConnection() throws SQLException {
final Connection connection;
if (useDbcpPooling) {
try {
connection = dbcpDataSource.getConnection();
} catch (SQLException e) {
getLogger().log("Could not create connection. Reason: " + e, LOG_CHANNEL, Logger.EMERGENCY);
throw e;
} finally {
logConnectionPoolStatistics();
}
} else {
try {
connection = DriverManager.getConnection(url, user, password);
} catch (SQLException e) {
getLogger().log("Could not create connection. Reason: " + e, LOG_CHANNEL, Logger.EMERGENCY);
throw e;
}
try {
if (connection.getTransactionIsolation() != isolationLevel) {
connection.setTransactionIsolation(isolationLevel);
}
} catch (SQLException e) {
getLogger().log(
"Could not set isolation level '" + isolationLevelToString(isolationLevel) + "'. Reason: " + e,
LOG_CHANNEL,
Logger.WARNING);
}
if (connection.getAutoCommit()) {
connection.setAutoCommit(false);
}
}
return connection;
}
protected boolean includeBranchInXid() {
return false;
}
/**
* Returns properties to be used with Commons DBCP BasicDataSource.
*
* @param parameters the configuration parameters for this store
* @return properties to pass to the DBCP datasource, set up
* according to store configuration parameters (never null)
*/
protected Properties getDbcpPoolProperties(Hashtable parameters) {
final Properties props = new Properties();
if (parameters == null) {
return props;
}
// Set all DBCP properties
final int prefixSkipchars = CONF_KEY_DBCP_PREFIX.length();
final Iterator keyIter = parameters.keySet().iterator();
while (keyIter.hasNext()) {
final String key = String.valueOf(keyIter.next());
if (key.startsWith(CONF_KEY_DBCP_PREFIX)) {
final String property = key.substring(prefixSkipchars);
final Object value = parameters.get(key);
if (value != null) {
props.put(property, value.toString());
}
}
}
int intValue = -2; // use -2, since -1 and 0 are magic numbers already
// Old maxActive setting ("maxPooledConnections") have priority
final Object value = parameters.get("maxPooledConnections");
if (value != null) {
try {
intValue = Integer.parseInt(value.toString());
} catch (NumberFormatException e) {
getLogger().log("Could not parse configuration setting " +
"maxPooledConnections, parameter must be integer",
LOG_CHANNEL,
Logger.WARNING);
}
}
if (intValue > -2) {
getLogger().log("The maxPooledConnections configuration " +
"attribute is deprecated, please use " +
CONF_KEY_DBCP_PREFIX + "maxActive instead.",
LOG_CHANNEL,
Logger.WARNING);
props.put("maxActive", value.toString());
}
return props;
}
/**
* Log statistics for Connection pool
* (when using Commons DBCP and log level DEBUG).
*/
protected void logConnectionPoolStatistics() {
// Avoid String concatenation if message is not going to be logged
if (useDbcpPooling && getLogger().getLoggerLevel(LOG_CHANNEL) >= Logger.DEBUG) {
getLogger().log("Connection pool stats: active: " +
dbcpDataSource.getNumActive() + " (max: " +
dbcpDataSource.getMaxActive() + "), idle: " +
dbcpDataSource.getNumIdle() + "(max: " +
dbcpDataSource.getMaxIdle() + ")",
LOG_CHANNEL, Logger.DEBUG);
}
}
}
The table below shows all metrics for JDBCStore.java.




