/** * Copyright (C) 2004 Orbeon, Inc. * * This program is free software; you can redistribute it and/or modify it 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. * * This program 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. * * The full text of the license is available at http://www.gnu.org/copyleft/lesser.html */ package org.orbeon.oxf.processor; import org.apache.log4j.Logger; import org.orbeon.oxf.common.OXFException; import org.orbeon.oxf.pipeline.api.PipelineContext; import org.orbeon.oxf.util.LoggerFactory; import javax.naming.InitialContext; import javax.sql.DataSource; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.HashMap; import java.util.Map; /** * Represent a database context for processors using SQL connections. */ public class DatabaseContext { private static Logger logger = LoggerFactory.createLogger(DatabaseContext.class); public static final String DATASOURCE_CONTEXT = "datasource-context"; // used by DatabaseContext /** * Get a connection valid for this pipeline execution, given a JDBC JNDI name. * * The returned connection must not be closed by the user. * * @param pipelineContext current pipeline context * @param datasource Datasource object * @return Connection object */ public static Connection getConnection(PipelineContext pipelineContext, final String jndiName) { // Try to obtain connection from context // We used to synchronize on DatabaseContext.class here, but this should not be necessary since pipelineContext // is only used by one thread at a time. Connection connection = (Connection) getContext(pipelineContext).connections.get(jndiName); if (connection == null) { try { // Create connection from datasource javax.naming.Context initialContext = new InitialContext(); javax.naming.Context envContext = (javax.naming.Context) initialContext.lookup("java:comp/env"); DataSource ds = (DataSource) envContext.lookup(jndiName); if (ds == null) { throw new OXFException("Cannot find DataSource object by looking-up: " + jndiName); } Connection newConnection = ds.getConnection(); // Set connection properties setConnectionProperties(newConnection, pipelineContext, jndiName); // Save connection into context getContext(pipelineContext).connections.put(jndiName, newConnection); connection = newConnection; } catch (OXFException e) { throw e; } catch (Exception e) { throw new OXFException(e); } } return connection; } /** * Get a connection valid for this pipeline execution, given a Datasource object. * * The returned connection must not be closed by the user. * * @param pipelineContext current pipeline context * @param datasource Datasource object * @return Connection object */ public static Connection getConnection(PipelineContext pipelineContext, Datasource datasource) { // Try to obtain connection from context Connection connection = (Connection) getContext(pipelineContext).connections.get(datasource.toString()); if (connection == null) { synchronized (DatabaseContext.class) { connection = (Connection) getContext(pipelineContext).connections.get(datasource.toString()); if (connection == null) { // Create connection try { Class.forName(datasource.getDriverClassName()); } catch (ClassNotFoundException e) { throw new OXFException("Cannot load JDBC driver for class: " + datasource.getDriverClassName()); } Connection newConnection; try { newConnection = DriverManager.getConnection(datasource.getUri(), datasource.getUsername(), datasource.getPassword()); } catch (SQLException e) { throw new OXFException("Cannot get connection from JDBC DriverManager for datasource: " + datasource, e); } // Set connection properties try { setConnectionProperties(newConnection, pipelineContext, datasource.toString()); } catch (Exception e) { throw new OXFException(e); } // Save connection into context getContext(pipelineContext).connections.put(datasource.toString(), newConnection); connection = newConnection; } } } return connection; } private static void setConnectionProperties(final Connection connection, PipelineContext pipelineContext, final String datasourceName) throws SQLException { // Set connection properties connection.setAutoCommit(false); // Commit or rollback when context is destroyed pipelineContext.addContextListener(new PipelineContext.ContextListenerAdapter() { public void contextDestroyed(boolean success) { try { if (success) { logger.info("Committing JDBC connection for datasource: " + datasourceName + "."); connection.commit(); connection.close(); } else { logger.info("Rolling back JDBC connection for datasource: " + datasourceName + "."); connection.rollback(); connection.close(); } } catch (SQLException e) { throw new OXFException(e); } } }); } private static Context getContext(PipelineContext pipelineContext) { Context context = (Context) pipelineContext.getAttribute(DATASOURCE_CONTEXT); if (context == null) { context = new Context(); pipelineContext.setAttribute(DATASOURCE_CONTEXT, context); } return context; } private static class Context { // Map datasource to connections public Map connections = new HashMap(); } }