Java tutorial
/* * $Header: /var/chroot/cvs/cvs/factsheetDesigner/extern/jakarta-slide-server-src-2.1-iPlus Edit/src/stores/org/apache/slide/store/impl/rdbms/JDBCStore.java,v 1.3 2006-04-19 15:06:55 peter-cvs Exp $ * $Revision: 1.3 $ * $Date: 2006-04-19 15:06:55 $ * * ==================================================================== * * Copyright 1999-2002 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 org.apache.commons.dbcp.DriverManagerConnectionFactory; import org.apache.commons.dbcp.PoolableConnectionFactory; import org.apache.commons.dbcp.PoolingDriver; import org.apache.commons.pool.impl.GenericObjectPool; 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.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. As this * implementation only uses a single connection to the database, it does not * work properly in production environments that require simultaneous access by * multiple clients. * * @version $Revision: 1.3 $ */ public class JDBCStore extends AbstractRDBMSStore implements LockStore, NodeStore, RevisionDescriptorsStore, RevisionDescriptorStore, SecurityStore, ContentStore { public static final String DBCP_URL = "jdbc:apache:commons:dbcp"; public static final String TRANSACTION_NONE = "NONE"; public static final String TRANSACTION_READ_UNCOMMITTED = "READ_UNCOMMITTED"; public static final String TRANSACTION_READ_COMMITTED = "READ_COMMITTED"; public static final String TRANSACTION_REPEATABLE_READ = "REPEATABLE_READ"; public static final String TRANSACTION_SERIALIZABLE = "SERIALIZABLE"; public static final int DEFAUT_ISOLATION_LEVEL = Connection.TRANSACTION_READ_COMMITTED; protected static String isolationLevelToString(int isolationLevel) { 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) { if (TRANSACTION_NONE.equals(levelString)) { return Connection.TRANSACTION_NONE; } else if (TRANSACTION_READ_UNCOMMITTED.equals(levelString)) { return Connection.TRANSACTION_READ_UNCOMMITTED; } else if (TRANSACTION_READ_COMMITTED.equals(levelString)) { return Connection.TRANSACTION_READ_COMMITTED; } else if (TRANSACTION_REPEATABLE_READ.equals(levelString)) { return Connection.TRANSACTION_REPEATABLE_READ; } else if (TRANSACTION_SERIALIZABLE.equals(levelString)) { return Connection.TRANSACTION_SERIALIZABLE; } else { return -1; } } // ----------------------------------------------------- Instance Variables /** * Driver class name. */ protected String driver; /** * Connection URL. */ protected String url; /** * User name. */ protected String user = ""; /** * Password. */ protected String password = ""; protected boolean useDbcpPooling = false; protected String dbcpPoolName = "dbcpPool" + System.identityHashCode(this); protected int maxPooledConnections = -1; protected int isolationLevel = DEFAUT_ISOLATION_LEVEL; // -------------------------------------------------------- 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 path value = (String) parameters.get("path"); if (value == null) { throw new ServiceParameterMissingException(this, "path"); } else { url = value; } // User name value = (String) parameters.get("user"); if (value != null) { user = value; } // Password value = (String) parameters.get("password"); if (value != null) { password = value; } 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; } } value = (String) parameters.get("dbcpPooling"); if (value != null) { useDbcpPooling = "true".equals(value); } if (useDbcpPooling) { value = (String) parameters.get("maxPooledConnections"); if (value != null) { try { maxPooledConnections = Integer.parseInt(value); } catch (NumberFormatException nfe) { getLogger().log("Could not set maximum pooled connections, parameter must be integer", LOG_CHANNEL, Logger.WARNING); } } } super.setParameters(parameters); } /** * Initializes driver. * <p/> * Occurs in four steps : * <li>Driver class is loaded</li> * <li>Driver is instantiated</li> * <li>Driver registration in the driver manager</li> * <li>Creation of the basic tables, if they didn't exist before</li> * * @exception ServiceInitializationFailedException Throws an exception * if the data source has already been initialized before */ public synchronized void initialize(NamespaceAccessToken token) throws ServiceInitializationFailedException { // XXX might be done already in setParameter if (!alreadyInitialized) { try { // Loading and registering driver getLogger().log("Loading and registering driver '" + driver + "'", LOG_CHANNEL, Logger.INFO); Class driverClass = Class.forName(driver); Driver driverInstance = (Driver) driverClass.newInstance(); String levelString = isolationLevelToString(isolationLevel); getLogger().log("Setting isolation level '" + levelString + "'", LOG_CHANNEL, Logger.INFO); // use DBCP pooling if enabled if (useDbcpPooling) { getLogger().log("Using DBCP pooling", LOG_CHANNEL, Logger.INFO); GenericObjectPool connectionPool = new GenericObjectPool(null); if (maxPooledConnections != -1) { connectionPool.setMaxActive(maxPooledConnections); } getLogger().log("Number of connections set to " + connectionPool.getMaxActive(), LOG_CHANNEL, Logger.INFO); DriverManagerConnectionFactory connectionFactory = new DriverManagerConnectionFactory(url, user, password); new PoolableConnectionFactory(connectionFactory, connectionPool, // TODO switching on pooling of prepared statements causes problems with closing of connections // switched off for now // new StackKeyedObjectPoolFactory(), null, null, false, false, isolationLevel); PoolingDriver driver = new PoolingDriver(); driver.registerPool(dbcpPoolName, connectionPool); // already done when loding PoolingDriver class // DriverManager.registerDriver(driver); } else { 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; } } } protected Connection getNewConnection() throws SQLException { Connection connection; if (useDbcpPooling) { try { connection = DriverManager.getConnection(DBCP_URL + ":" + dbcpPoolName); } catch (SQLException e) { getLogger().log("Could not create connection. Reason: " + e, LOG_CHANNEL, Logger.EMERGENCY); throw e; } } 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; } }