You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by ma...@apache.org on 2015/05/20 18:42:25 UTC

[5/9] incubator-nifi git commit: JDBC driver can be loaded from external location using URLClassLoader

JDBC driver can be loaded from external location using URLClassLoader

Signed-off-by: Toivo Adams <to...@gmail.com>
Signed-off-by: Mark Payne <ma...@hotmail.com>


Project: http://git-wip-us.apache.org/repos/asf/incubator-nifi/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-nifi/commit/1682d62d
Tree: http://git-wip-us.apache.org/repos/asf/incubator-nifi/tree/1682d62d
Diff: http://git-wip-us.apache.org/repos/asf/incubator-nifi/diff/1682d62d

Branch: refs/heads/develop
Commit: 1682d62d7f46ba854f77923352a77ff9f6a1b746
Parents: 864e099
Author: Toivo Adams <to...@gmail.com>
Authored: Sat Mar 14 12:34:40 2015 +0200
Committer: Mark Payne <ma...@hotmail.com>
Committed: Wed May 20 08:35:55 2015 -0400

----------------------------------------------------------------------
 .../apache/nifi/dbcp/DBCPConnectionPool.java    | 23 ++++--
 .../java/org/apache/nifi/dbcp/DriverShim.java   | 74 ++++++++++++++++++++
 .../org/apache/nifi/dbcp/DBCPServiceTest.java   | 35 +++++----
 3 files changed, 113 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/1682d62d/nifi/nifi-nar-bundles/nifi-standard-services/nifi-dbcp-service-bundle/nifi-dbcp-service/src/main/java/org/apache/nifi/dbcp/DBCPConnectionPool.java
----------------------------------------------------------------------
diff --git a/nifi/nifi-nar-bundles/nifi-standard-services/nifi-dbcp-service-bundle/nifi-dbcp-service/src/main/java/org/apache/nifi/dbcp/DBCPConnectionPool.java b/nifi/nifi-nar-bundles/nifi-standard-services/nifi-dbcp-service-bundle/nifi-dbcp-service/src/main/java/org/apache/nifi/dbcp/DBCPConnectionPool.java
index c2511c3..e2c0fea 100644
--- a/nifi/nifi-nar-bundles/nifi-standard-services/nifi-dbcp-service-bundle/nifi-dbcp-service/src/main/java/org/apache/nifi/dbcp/DBCPConnectionPool.java
+++ b/nifi/nifi-nar-bundles/nifi-standard-services/nifi-dbcp-service-bundle/nifi-dbcp-service/src/main/java/org/apache/nifi/dbcp/DBCPConnectionPool.java
@@ -20,6 +20,8 @@ import java.net.MalformedURLException;
 import java.net.URL;
 import java.net.URLClassLoader;
 import java.sql.Connection;
+import java.sql.Driver;
+import java.sql.DriverManager;
 import java.sql.SQLException;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -184,7 +186,7 @@ public class DBCPConnectionPool extends AbstractControllerService implements DBC
         
         // Optional driver URL, when exist, this URL will be used to locate driver jar file location
         String urlString	= context.getProperty(DB_DRIVER_JAR_URL).getValue();
-        dataSource.setDriverClassLoader( getDriverClassLoader(urlString) );
+        dataSource.setDriverClassLoader( getDriverClassLoader(urlString, drv) );
         
         String dburl  = dbsystem.buildUrl(host, port, dbname);
         
@@ -210,14 +212,27 @@ public class DBCPConnectionPool extends AbstractControllerService implements DBC
      * 	using Thread.currentThread().getContextClassLoader();
      * will ensure that you are using the ClassLoader for you NAR.
      * @throws InitializationException 
-     */    
-    protected ClassLoader getDriverClassLoader(String urlString) throws InitializationException {
+     */
+    protected ClassLoader getDriverClassLoader(String urlString, String drvName) throws InitializationException {
         if (urlString!=null && urlString.length()>0) {
         	try {
 				URL[] urls = new URL[] { new URL(urlString) };
-				return new URLClassLoader(urls);
+				URLClassLoader ucl = new URLClassLoader(urls);
+				
+				// Workaround which allows to use URLClassLoader for JDBC driver loading.
+				// (Because the DriverManager will refuse to use a driver not loaded by the system ClassLoader.) 
+		    	Class<?> clazz = Class.forName(drvName, true, ucl);
+		    	if (clazz==null)
+		    		throw new InitializationException("Can't load Database Driver " + drvName);
+		    	Driver driver = (Driver) clazz.newInstance();
+		    	DriverManager.registerDriver( new DriverShim(driver) );
+				
+				return ucl;
+				
 			} catch (MalformedURLException e) {
 				throw new InitializationException("Invalid Database Driver Jar Url", e);
+			} catch (Exception e) {
+				throw new InitializationException("Can't load Database Driver", e);
 			}
         }
         else 

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/1682d62d/nifi/nifi-nar-bundles/nifi-standard-services/nifi-dbcp-service-bundle/nifi-dbcp-service/src/main/java/org/apache/nifi/dbcp/DriverShim.java
----------------------------------------------------------------------
diff --git a/nifi/nifi-nar-bundles/nifi-standard-services/nifi-dbcp-service-bundle/nifi-dbcp-service/src/main/java/org/apache/nifi/dbcp/DriverShim.java b/nifi/nifi-nar-bundles/nifi-standard-services/nifi-dbcp-service-bundle/nifi-dbcp-service/src/main/java/org/apache/nifi/dbcp/DriverShim.java
new file mode 100644
index 0000000..8905d9d
--- /dev/null
+++ b/nifi/nifi-nar-bundles/nifi-standard-services/nifi-dbcp-service-bundle/nifi-dbcp-service/src/main/java/org/apache/nifi/dbcp/DriverShim.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.nifi.dbcp;
+
+import java.sql.Connection;
+import java.sql.Driver;
+import java.sql.DriverPropertyInfo;
+import java.sql.SQLException;
+import java.sql.SQLFeatureNotSupportedException;
+import java.util.Properties;
+import java.util.logging.Logger;
+
+/**
+ *  Workaround which allows to use URLClassLoader for JDBC driver loading.
+ *  (Because the DriverManager will refuse to use a driver not loaded by the system ClassLoader.) 
+ *
+ */
+class DriverShim implements Driver {
+	private Driver driver;
+	
+	DriverShim(Driver d) {
+		this.driver = d;
+	}
+	
+	@Override
+	public boolean acceptsURL(String u) throws SQLException {
+		return this.driver.acceptsURL(u);
+	}
+	
+	@Override
+	public Connection connect(String u, Properties p) throws SQLException {
+		return this.driver.connect(u, p);
+	}
+	
+	@Override
+	public int getMajorVersion() {
+		return this.driver.getMajorVersion();
+	}
+	
+	@Override
+	public int getMinorVersion() {
+		return this.driver.getMinorVersion();
+	}
+	
+	@Override
+	public DriverPropertyInfo[] getPropertyInfo(String u, Properties p) throws SQLException {
+		return this.driver.getPropertyInfo(u, p);
+	}
+	
+	@Override
+	public boolean jdbcCompliant() {
+		return this.driver.jdbcCompliant();
+	}
+	
+	@Override
+	public Logger getParentLogger() throws SQLFeatureNotSupportedException {
+		return driver.getParentLogger();
+	}
+	
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/1682d62d/nifi/nifi-nar-bundles/nifi-standard-services/nifi-dbcp-service-bundle/nifi-dbcp-service/src/test/java/org/apache/nifi/dbcp/DBCPServiceTest.java
----------------------------------------------------------------------
diff --git a/nifi/nifi-nar-bundles/nifi-standard-services/nifi-dbcp-service-bundle/nifi-dbcp-service/src/test/java/org/apache/nifi/dbcp/DBCPServiceTest.java b/nifi/nifi-nar-bundles/nifi-standard-services/nifi-dbcp-service-bundle/nifi-dbcp-service/src/test/java/org/apache/nifi/dbcp/DBCPServiceTest.java
index 07d1398..cb9c208 100644
--- a/nifi/nifi-nar-bundles/nifi-standard-services/nifi-dbcp-service-bundle/nifi-dbcp-service/src/test/java/org/apache/nifi/dbcp/DBCPServiceTest.java
+++ b/nifi/nifi-nar-bundles/nifi-standard-services/nifi-dbcp-service-bundle/nifi-dbcp-service/src/test/java/org/apache/nifi/dbcp/DBCPServiceTest.java
@@ -51,7 +51,7 @@ public class DBCPServiceTest {
 	 *	Unknown database system.  
 	 * 
 	 */
-//    @Test
+    @Test
     public void testUnknownDatabaseSystem() throws InitializationException {
         final TestRunner runner = TestRunners.newTestRunner(TestProcessor.class);
         final DBCPConnectionPool service = new DBCPConnectionPool();
@@ -64,7 +64,7 @@ public class DBCPServiceTest {
     /**
      *  Missing property values.
      */    
-//    @Test
+    @Test
     public void testMissingPropertyValues() throws InitializationException {
         final TestRunner runner = TestRunners.newTestRunner(TestProcessor.class);
         final DBCPConnectionPool service = new DBCPConnectionPool();
@@ -78,7 +78,7 @@ public class DBCPServiceTest {
      * Connect, create table, insert, select, drop table. 
      * 
      */
-//    @Test
+    @Test
     public void testCreateInsertSelect() throws InitializationException, SQLException {
         final TestRunner runner = TestRunners.newTestRunner(TestProcessor.class);
         final DBCPConnectionPool service = new DBCPConnectionPool();
@@ -120,7 +120,7 @@ public class DBCPServiceTest {
      * Connect, create table, insert, select, drop table. 
      * 
      */
-//    @Test
+    @Test
     public void testExternalJDBCDriverUsage() throws InitializationException, SQLException {
         final TestRunner runner = TestRunners.newTestRunner(TestProcessor.class);
         final DBCPConnectionPool service = new DBCPConnectionPool();
@@ -136,7 +136,7 @@ public class DBCPServiceTest {
         runner.setProperty(service, DBCPConnectionPool.DB_DRIVER_JAR_URL, "file:///var/tmp/mariadb-java-client-1.1.7.jar");
         
         
-        runner.setProperty(service, DBCPConnectionPool.DB_HOST, "127.0.0.1");	// localhost
+        runner.setProperty(service, DBCPConnectionPool.DB_HOST, "localhost");	// localhost
         runner.setProperty(service, DBCPConnectionPool.DB_NAME, "testdb");
         runner.setProperty(service, DBCPConnectionPool.DB_USER, 	"tester");
         runner.setProperty(service, DBCPConnectionPool.DB_PASSWORD, "testerp");
@@ -163,7 +163,7 @@ public class DBCPServiceTest {
      * Get many times, after a while pool should not contain any available connection
      * and getConnection should fail.    
      */
-//    @Test
+    @Test
     public void testExhaustPool() throws InitializationException, SQLException {
         final TestRunner runner = TestRunners.newTestRunner(TestProcessor.class);
         final DBCPConnectionPool service = new DBCPConnectionPool();
@@ -197,7 +197,7 @@ public class DBCPServiceTest {
      * Get many times, release immediately
      * and getConnection should not fail.    
      */
-//    @Test
+    @Test
     public void testGetManyNormal() throws InitializationException, SQLException {
         final TestRunner runner = TestRunners.newTestRunner(TestProcessor.class);
         final DBCPConnectionPool service = new DBCPConnectionPool();
@@ -226,7 +226,7 @@ public class DBCPServiceTest {
     }
     
     
-//    @Test
+    @Test
     public void testDriverLoad() throws ClassNotFoundException {
     	Class<?> clazz = Class.forName("org.apache.derby.jdbc.EmbeddedDriver");
     	assertNotNull(clazz);
@@ -244,29 +244,36 @@ public class DBCPServiceTest {
     	
     	ClassLoader parent = Thread.currentThread().getContextClassLoader();
     	URLClassLoader ucl = new URLClassLoader(urls,parent);
+//    	URLClassLoader ucl = new URLClassLoader(urls);
     	
     	Class<?> clazz = Class.forName("org.mariadb.jdbc.Driver", true, ucl);
     	assertNotNull(clazz);
     	
     	Driver driver = (Driver) clazz.newInstance();
+    	Driver shim   = new DriverShim(driver);
+    	DriverManager.registerDriver( shim );
     	
     	// Driver is found when using URL ClassLoader
     	assertTrue( isDriverAllowed(driver, ucl) );
     	
     	// Driver is not found when using parent ClassLoader
     	// unfortunately DriverManager will use caller ClassLoadar and driver is not found !!!  
-    	assertTrue( isDriverAllowed(driver, parent) );
+//    	assertTrue( isDriverAllowed(driver, parent) );
     	
-//    	DriverManager.registerDriver( (Driver) clazz.newInstance());
     	Enumeration<Driver> drivers = DriverManager.getDrivers();
     	while (drivers.hasMoreElements()) {
 			driver = (Driver) drivers.nextElement();
 			System.out.println(driver);
 		}
+
+    	Driver driver2 = DriverManager.getDriver("jdbc:mariadb://localhost:3306/testdb");
+    	assertNotNull(driver2);
     	
+    	Connection connection = DriverManager.getConnection("jdbc:mariadb://localhost:3306/testdb","tester","testerp");
+    	assertNotNull(connection);
+    	connection.close();
     	
-   // 	Driver driver = DriverManager.getDriver("jdbc:mariadb://127.0.0.1:3306/testdb");
-   // 	assertNotNull(driver);
+    	DriverManager.deregisterDriver(shim);
     }
 
     
@@ -299,7 +306,7 @@ public class DBCPServiceTest {
     }
 
     //==================================== problem solving - no suitable driver found, mariadb =========================================
-    
+    // method isDriverAllowed is from DriverManager
     private static boolean isDriverAllowed(Driver driver, ClassLoader classLoader) {
         boolean result = false;
         if(driver != null) {
@@ -318,6 +325,4 @@ public class DBCPServiceTest {
     }
     
     
-    
-    
 }