001/** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 019package org.apache.oozie.util.db; 020 021import org.apache.commons.dbcp.BasicDataSource; 022import org.apache.commons.dbcp.ConnectionFactory; 023import org.apache.commons.dbcp.DriverConnectionFactory; 024import org.apache.commons.dbcp.SQLNestedException; 025 026import java.sql.Driver; 027import java.sql.DriverManager; 028import java.sql.SQLException; 029 030public class BasicDataSourceWrapper extends BasicDataSource { 031 032 /** 033 * Fixing a bug within {@link BasicDataSource#createConnectionFactory()} for {@code driverClassName} to have real effect. 034 * <p> 035 * Because we use currently Apache Commons DBCP 1.4.0 that has a bug not considering {@code driverClassName}, thus, we're unable 036 * to create a JDBC driver using a user-provided driver class name (we try to do that by setting explicitly a value for 037 * {@code openJpa.connectionProperties="DriverClassName=..."}), unless we perform the exact same fix that is applied by the DBCP 038 * patch. 039 * <p> 040 * Note: when DBCP 1.4.1 will be released, and Oozie will update to 1.4.1, we can remove this class. 041 * <p> 042 * Please see <a href="https://issues.apache.org/jira/browse/DBCP-333">the DBCP bug</a> and 043 * <a href="https://github.com/apache/commons-dbcp/blob/DBCP_1_4_x_BRANCH/src/java/org/apache/commons/dbcp/BasicDataSource.java#L1588-L1660"> 044 * the fixed method </a> 045 * for details. 046 * <p> 047 * Please also see how OpenJPA 048 * <a href="http://openjpa.apache.org/builds/2.2.1/apache-openjpa/docs/ref_guide_integration_dbcp.html"> is integrated</a> 049 * with DBCP. 050 */ 051 protected ConnectionFactory createConnectionFactory() throws SQLException { 052 // Load the JDBC driver class 053 Class driverFromCCL = null; 054 if (driverClassName != null) { 055 try { 056 try { 057 if (driverClassLoader == null) { 058 driverFromCCL = Class.forName(driverClassName); 059 } else { 060 driverFromCCL = Class.forName(driverClassName, true, driverClassLoader); 061 } 062 } catch (ClassNotFoundException cnfe) { 063 driverFromCCL = Thread.currentThread( 064 ).getContextClassLoader().loadClass( 065 driverClassName); 066 } 067 } catch (Throwable t) { 068 String message = "Cannot load JDBC driver class '" + 069 driverClassName + "'"; 070 logWriter.println(message); 071 t.printStackTrace(logWriter); 072 throw new SQLNestedException(message, t); 073 } 074 } 075 076 // Create a JDBC driver instance 077 Driver driver = null; 078 try { 079 if (driverFromCCL == null) { 080 driver = DriverManager.getDriver(url); 081 } else { 082 // Usage of DriverManager is not possible, as it does not 083 // respect the ContextClassLoader 084 driver = (Driver) driverFromCCL.newInstance(); 085 if (!driver.acceptsURL(url)) { 086 throw new SQLException("No suitable driver", "08001"); 087 } 088 } 089 } catch (Throwable t) { 090 String message = "Cannot create JDBC driver of class '" + 091 (driverClassName != null ? driverClassName : "") + 092 "' for connect URL '" + url + "'"; 093 logWriter.println(message); 094 t.printStackTrace(logWriter); 095 throw new SQLNestedException(message, t); 096 } 097 098 // Can't test without a validationQuery 099 if (validationQuery == null) { 100 setTestOnBorrow(false); 101 setTestOnReturn(false); 102 setTestWhileIdle(false); 103 } 104 105 // Set up the driver connection factory we will use 106 String user = username; 107 if (user != null) { 108 connectionProperties.put("user", user); 109 } else { 110 log("DBCP DataSource configured without a 'username'"); 111 } 112 113 String pwd = password; 114 if (pwd != null) { 115 connectionProperties.put("password", pwd); 116 } else { 117 log("DBCP DataSource configured without a 'password'"); 118 } 119 120 ConnectionFactory driverConnectionFactory = new DriverConnectionFactory(driver, url, connectionProperties); 121 return driverConnectionFactory; 122 } 123}