Revision: 4630
          http://sourceforge.net/p/jump-pilot/code/4630
Author:   edso
Date:     2015-12-17 18:58:28 +0000 (Thu, 17 Dec 2015)
Log Message:
-----------
allow loading of jdbc drivers from lib/ext/<subfolder/>

Modified Paths:
--------------
    
core/trunk/src/com/vividsolutions/jump/datastore/oracle/OracleValueConverterFactory.java
    
core/trunk/src/com/vividsolutions/jump/datastore/spatialdatabases/SpatialDatabasesDataStoreDriver.java
    
core/trunk/src/com/vividsolutions/jump/datastore/spatialite/SpatialiteDataStoreDriver.java
    core/trunk/src/com/vividsolutions/jump/workbench/plugin/PlugInManager.java

Added Paths:
-----------
    core/trunk/src/com/vividsolutions/jump/datastore/jdbc/DelegatingDriver.java

Added: 
core/trunk/src/com/vividsolutions/jump/datastore/jdbc/DelegatingDriver.java
===================================================================
--- core/trunk/src/com/vividsolutions/jump/datastore/jdbc/DelegatingDriver.java 
                        (rev 0)
+++ core/trunk/src/com/vividsolutions/jump/datastore/jdbc/DelegatingDriver.java 
2015-12-17 18:58:28 UTC (rev 4630)
@@ -0,0 +1,59 @@
+package com.vividsolutions.jump.datastore.jdbc;
+
+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;
+
+/**
+ * a jdbc driver wrapper to allow loading the driver with custon classloader
+ * from an arbitrary location during runtime. 
+ * DatabaseManager.registerDriver() only registers drivers loaded with the
+ * system classloader so we trick it into accepting our driver by wrapping it
+ * into this one.
+ *
+ * @see
+ *   
https://stackoverflow.com/questions/288828/how-to-use-a-jdbc-driver-from-an-arbitrary-location
+ */
+public class DelegatingDriver implements Driver {
+  private final Driver driver;
+
+  public DelegatingDriver(Driver driver) {
+    if (driver == null) {
+      throw new IllegalArgumentException("Driver must not be null.");
+    }
+    this.driver = driver;
+  }
+
+  public Connection connect(String url, Properties info) throws SQLException {
+    return driver.connect(url, info);
+  }
+
+  public boolean acceptsURL(String url) throws SQLException {
+    return driver.acceptsURL(url);
+  }
+
+  public DriverPropertyInfo[] getPropertyInfo(String url, Properties info)
+      throws SQLException {
+    return driver.getPropertyInfo(url, info);
+  }
+
+  public int getMajorVersion() {
+    return driver.getMajorVersion();
+  }
+
+  public int getMinorVersion() {
+    return driver.getMinorVersion();
+  }
+
+  public boolean jdbcCompliant() {
+    return driver.jdbcCompliant();
+  }
+
+  public Logger getParentLogger() throws SQLFeatureNotSupportedException {
+    return driver.getParentLogger();
+  }
+}
\ No newline at end of file


Property changes on: 
core/trunk/src/com/vividsolutions/jump/datastore/jdbc/DelegatingDriver.java
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: 
core/trunk/src/com/vividsolutions/jump/datastore/oracle/OracleValueConverterFactory.java
===================================================================
--- 
core/trunk/src/com/vividsolutions/jump/datastore/oracle/OracleValueConverterFactory.java
    2015-12-16 12:15:55 UTC (rev 4629)
+++ 
core/trunk/src/com/vividsolutions/jump/datastore/oracle/OracleValueConverterFactory.java
    2015-12-17 18:58:28 UTC (rev 4630)
@@ -5,6 +5,8 @@
 import com.vividsolutions.jump.datastore.jdbc.ValueConverterFactory;
 import 
com.vividsolutions.jump.datastore.spatialdatabases.SpatialDatabasesValueConverterFactory;
 import com.vividsolutions.jump.feature.AttributeType;
+import com.vividsolutions.jump.workbench.JUMPWorkbench;
+
 import java.io.IOException;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
@@ -33,20 +35,29 @@
         IllegalAccessException, IllegalArgumentException,
         InvocationTargetException {
       Object geometryObject = rs.getObject(columnIndex);
-      Class converterClazz = Class
-          .forName("org.geotools.data.oracle.sdo.GeometryConverter");
-      Class connectionClazz = Class.forName("oracle.jdbc.OracleConnection");
-      Class structClazz = Class.forName("oracle.sql.STRUCT");
+
+      // we need to use the plugin classloader to find the dependenciy
+      // jars under lib/ext/<subfolder>/ , additionally we apply some
+      // reflection to allow the dependencies to be only available
+      // during runtime
+      ClassLoader cl = JUMPWorkbench.getInstance().getPlugInManager()
+          .getClassLoader();
+      Class converterClazz = Class.forName(
+          "org.geotools.data.oracle.sdo.GeometryConverter", true, cl);
+      Class connectionClazz = Class.forName("oracle.jdbc.OracleConnection",
+          true, cl);
+      Class structClazz = Class.forName("oracle.sql.STRUCT", true, cl);
       Method converterMethod = converterClazz.getMethod("asGeometry",
-          new Class[]{structClazz});
+          new Class[] { structClazz });
 
       Constructor constructor = converterClazz
           .getDeclaredConstructor(connectionClazz);
       Object converter = constructor.newInstance(connectionClazz.cast(rs
           .getStatement().getConnection()));
 
-      return converterMethod.invoke(converter, 
structClazz.cast(geometryObject));
-    
+      return converterMethod
+          .invoke(converter, structClazz.cast(geometryObject));
+
       /**
        * below is the original implementation w/o reflection 
        * KEEP FOR REFERENCE!!!

Modified: 
core/trunk/src/com/vividsolutions/jump/datastore/spatialdatabases/SpatialDatabasesDataStoreDriver.java
===================================================================
--- 
core/trunk/src/com/vividsolutions/jump/datastore/spatialdatabases/SpatialDatabasesDataStoreDriver.java
      2015-12-16 12:15:55 UTC (rev 4629)
+++ 
core/trunk/src/com/vividsolutions/jump/datastore/spatialdatabases/SpatialDatabasesDataStoreDriver.java
      2015-12-17 18:58:28 UTC (rev 4630)
@@ -2,12 +2,15 @@
 
 import com.vividsolutions.jump.datastore.DataStoreConnection;
 import com.vividsolutions.jump.datastore.DataStoreDriver;
+import com.vividsolutions.jump.datastore.jdbc.DelegatingDriver;
 import com.vividsolutions.jump.datastore.mariadb.MariadbDSConnection;
 import com.vividsolutions.jump.datastore.oracle.OracleDSConnection;
 import com.vividsolutions.jump.datastore.postgis.PostgisDSConnection;
 import com.vividsolutions.jump.datastore.spatialite.SpatialiteDSConnection;
 import com.vividsolutions.jump.parameter.ParameterList;
 import com.vividsolutions.jump.parameter.ParameterListSchema;
+import com.vividsolutions.jump.workbench.JUMPWorkbench;
+
 import java.sql.Connection;
 import java.sql.Driver;
 import java.sql.DriverManager;
@@ -34,6 +37,8 @@
   protected String[] paramNames = null;
   protected Class[] paramClasses = null;
   protected ParameterListSchema schema = null;
+  
+  protected boolean registered = false;
 
   public SpatialDatabasesDataStoreDriver() {
     // Nicolas Ribot:
@@ -103,8 +108,21 @@
     String url
         = String.valueOf(new 
StringBuffer(urlPrefix).append(host).append(":").append(port).append("/").append(database));
 
-    Driver driver = (Driver) Class.forName(this.getJdbcClass()).newInstance();
-    DriverManager.registerDriver(driver);
+    // only register once per driver
+    if (!this.registered) {
+      // we always use the plugin classloader to find jdbc jars
+      // under lib/ext/<subfolder>/
+      ClassLoader cl = JUMPWorkbench.getInstance().getPlugInManager()
+          .getClassLoader();
+      Driver driver = (Driver) Class.forName(this.getJdbcClass(), true, cl)
+          .newInstance();
+      // DriverManager insists on jdbc drivers loaded with the default
+      // classloader, so we wrap our foreign one into a simple wrapper
+      // see
+      // 
https://stackoverflow.com/questions/288828/how-to-use-a-jdbc-driver-from-an-arbitrary-location
+      DriverManager.registerDriver(new DelegatingDriver(driver));
+      this.registered = true;
+    }
 
     // mmichaud 2013-08-27 workaround for ticket #330
     String savePreferIPv4Stack = 
System.getProperty("java.net.preferIPv4Stack");

Modified: 
core/trunk/src/com/vividsolutions/jump/datastore/spatialite/SpatialiteDataStoreDriver.java
===================================================================
--- 
core/trunk/src/com/vividsolutions/jump/datastore/spatialite/SpatialiteDataStoreDriver.java
  2015-12-16 12:15:55 UTC (rev 4629)
+++ 
core/trunk/src/com/vividsolutions/jump/datastore/spatialite/SpatialiteDataStoreDriver.java
  2015-12-17 18:58:28 UTC (rev 4630)
@@ -8,79 +8,98 @@
 import java.util.Properties;
 
 import com.vividsolutions.jump.datastore.DataStoreConnection;
+import com.vividsolutions.jump.datastore.jdbc.DelegatingDriver;
 import 
com.vividsolutions.jump.datastore.spatialdatabases.SpatialDatabasesDataStoreDriver;
 import com.vividsolutions.jump.parameter.ParameterList;
 import com.vividsolutions.jump.parameter.ParameterListSchema;
+import com.vividsolutions.jump.workbench.JUMPWorkbench;
 
 //import org.sqlite.SQLiteConfig;
 
 /**
  * A driver for supplying {@link SpatialDatabaseDSConnection}s
  */
-public class SpatialiteDataStoreDriver
-    extends SpatialDatabasesDataStoreDriver {
-    
-    public final static String JDBC_CLASS = "org.sqlite.JDBC";
-    
-    public SpatialiteDataStoreDriver() {
-        this.driverName = "Spatialite";
-        this.jdbcClass = "org.sqlite.JDBC";
-        //TODO: prompt for filename
-        this.urlPrefix = "jdbc:sqlite:";
-        
-        // Panel parameters: adds a file chooser for db name
-        paramNames = new String[]{PARAM_DB_File};
-        paramClasses = new Class[]{File.class};
-        schema = new ParameterListSchema(paramNames, paramClasses);
-    }
-    
-    /**
-     * returns a spatialite JDBC connexion with spatialite extension loaded if 
possible
-     * if not, a property will tell so
-     * 
-     * @param params
-     * @return
-     * @throws Exception 
-     */
+public class SpatialiteDataStoreDriver extends SpatialDatabasesDataStoreDriver 
{
+
+  public final static String JDBC_CLASS = "org.sqlite.JDBC";
+  private static boolean initialized = false;
+
+  public SpatialiteDataStoreDriver() {
+    this.driverName = "Spatialite";
+    this.jdbcClass = "org.sqlite.JDBC";
+    // TODO: prompt for filename
+    this.urlPrefix = "jdbc:sqlite:";
+
+    // Panel parameters: adds a file chooser for db name
+    paramNames = new String[] { PARAM_DB_File };
+    paramClasses = new Class[] { File.class };
+    schema = new ParameterListSchema(paramNames, paramClasses);
+  }
+
+  /**
+   * returns a spatialite JDBC connection with spatialite extension loaded if
+   * possible if not, a property will tell so
+   * 
+   * @param params
+   * @return
+   * @throws Exception
+   */
   @Override
   public DataStoreConnection createConnection(ParameterList params)
       throws Exception {
     // PARAM_DB_File is a fileChooser: the default mechanism used will store a
-    // DefaultAwtShell on OSX. Do not cast to this internal type but gets its 
toString() method
+    // DefaultAwtShell on OSX. Do not cast to this internal type but gets its
+    // toString() method
     // returning the choosen filename.
     String database = params.getParameter(PARAM_DB_File).toString();
-    
-    // First checks if the file exists: cannot manage newly created Spatialite 
files yet:
+
+    // First checks if the file exists: cannot manage newly created Spatialite
+    // files yet:
     // File must exists
     File sqliteFile = new File(database);
     if (!sqliteFile.exists() || !sqliteFile.canRead()) {
       // TODO: I18N
-      throw new Exception("Spatialite file: " + database + " does not exist. 
cannot create connection");
+      throw new Exception("Spatialite file: " + database
+          + " does not exist. cannot create connection");
     }
-    
-    // mandatory to load spatialite extension
-    Class configClazz = Class.forName("org.sqlite.SQLiteConfig");
+
+    String url = String.valueOf(new StringBuffer(urlPrefix).append(database));
+
+    ClassLoader cl = JUMPWorkbench.getInstance().getPlugInManager()
+        .getClassLoader();
+
+    // we register only once
+    if (!initialized) {
+      Driver driver = (Driver) cl.loadClass(this.getJdbcClass()).newInstance();
+      // DriverManager insists on jdbc drivers loaded with the default
+      // classloader, so we wrap our foreign one into a simple wrapper
+      // see 
https://stackoverflow.com/questions/288828/how-to-use-a-jdbc-driver-from-an-arbitrary-location
+      DriverManager.registerDriver(new DelegatingDriver(driver));
+      initialized = true;
+//      Enumeration<Driver> ds = DriverManager.getDrivers();
+//      while (ds.hasMoreElements()) {
+//        System.out.println(ds.nextElement());
+//      }
+    }
+
+    // mandatory to enable loading extensions
+    Class configClazz = cl.loadClass("org.sqlite.SQLiteConfig");
     Method enableMethod = configClazz.getMethod("enableLoadExtension",
-        new Class[]{boolean.class});
-    
+        new Class[] { boolean.class });
+
     Object config = configClazz.newInstance();
     enableMethod.invoke(config, true);
 
     // this is the code above w/o reflection, KEEP FOR REFERENCE!!!
     // mandatory to load spatialite extension
-    //SQLiteConfig config = new SQLiteConfig();
-    //config.enableLoadExtension(true);
+    // SQLiteConfig config = new SQLiteConfig();
+    // config.enableLoadExtension(true);
 
-    String url
-        = String.valueOf(new StringBuffer(urlPrefix).append(database));
-
-    Driver driver = (Driver) Class.forName(this.getJdbcClass()).newInstance();
-    DriverManager.registerDriver(driver);
-
     Method getPropsMethod = configClazz.getMethod("toProperties");
-    Properties props = (Properties)getPropsMethod.invoke(config);
+    Properties props = (Properties) getPropsMethod.invoke(config);
     Connection conn = DriverManager.getConnection(url, props);
 
     return new SpatialiteDSConnection(conn);
   }
+  
 }

Modified: 
core/trunk/src/com/vividsolutions/jump/workbench/plugin/PlugInManager.java
===================================================================
--- core/trunk/src/com/vividsolutions/jump/workbench/plugin/PlugInManager.java  
2015-12-16 12:15:55 UTC (rev 4629)
+++ core/trunk/src/com/vividsolutions/jump/workbench/plugin/PlugInManager.java  
2015-12-17 18:58:28 UTC (rev 4630)
@@ -84,15 +84,48 @@
         if ( plugInDirectory instanceof File ) {
           ArrayList<File> files = new ArrayList();
           files.add( plugInDirectory );
-          files.addAll( findFilesRecursively(plugInDirectory,true) );
-          classLoader = new URLClassLoader(toURLs(files));
+          files.addAll( findFilesRecursively( plugInDirectory,true) );
+          //System.out.println(Arrays.toString(files.toArray()));
+          class ExtendedURLClassLoader extends URLClassLoader{
+
+            public ExtendedURLClassLoader(URL[] urls) {
+              super(urls);
+            }
+
+            /**
+             * not really necessary now, but we keep it for reference for a 
future
+             * classloader per extension for allowing extensions to use 
differently
+             * versioned dependency jars in separate subfolders under
+             * lib/ext/<extension_subfolder>/
+             */
+            @Override
+            public Class loadClass(String name) throws ClassNotFoundException {
+              Class c = findLoadedClass(name);
+              if (c == null) {
+                try {
+                  c = getParent().loadClass(name);
+                } catch (ClassNotFoundException e) {
+                }
+                if (c == null)
+                  c = findClass(name);
+              }
+              return c;
+            }
+            
+            public void addUrls( URL[] urls ){
+              for (URL url : urls) {
+                addURL(url);
+              }
+            }
+          };
+          
+          ExtendedURLClassLoader mycl = new ExtendedURLClassLoader(new 
URL[]{});
+          mycl.addUrls(toURLs(files));
+          classLoader = mycl;
         } else {
           classLoader = getClass().getClassLoader();
         }
 
-//        classLoader = plugInDirectory != null ? new URLClassLoader(
-//            toURLs(findFilesRecursively(plugInDirectory,true))) : 
getClass().getClassLoader();
-        
         I18N.setClassLoader(classLoader);
         this.context = context;
         this.plugInDirectory = plugInDirectory;


------------------------------------------------------------------------------
_______________________________________________
Jump-pilot-devel mailing list
Jump-pilot-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/jump-pilot-devel

Reply via email to