-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 6 posts ] 
Author Message
 Post subject: How to dynamically load Drivers from a JAR
PostPosted: Wed Feb 17, 2010 7:17 pm 
Newbie

Joined: Wed Feb 17, 2010 7:09 pm
Posts: 3
I'm new to the Hibernate architecture.
I loaded the Hibernate Tool into the eclipse framework. The Tool has a configuration that can add the driver jar to the classpath.
When the HSQL run he loads the JAR dynamically and the query works.

I want to create my own plugin with the hibernate core, and use a configuration file that the customer can change and point to different JAR driver files depends on the database they are using.

I tried different mechanism (including using the system class loader), but I always get an exception from the Hibernate (either the driver class does not exists , or the correct driver does not exists).

How does the Tool loads dynamically the JAR file and drivers?

A sample code will be greatly appreciated.

Yigal


Top
 Profile  
 
 Post subject: Re: How to dynamically load Drivers from a JAR
PostPosted: Thu Feb 18, 2010 6:50 am 
Regular
Regular

Joined: Thu May 07, 2009 5:56 am
Posts: 94
Location: Toulouse, France
hi,

how do you create your classloader? in my case, I've been created my own java ClassLoader and just before to initiliaze hibernate sessionFactory I was set Thread.currentThread().setContextClassLoader(myClassLoader)

e.g

Code:
File jarf = new File("path_to/jdbc_driver.jar");
if (!jarf.exists())
{
throw new IllegalArgumentException("file does exists!");
}

URL urls[] = { jarf.toURI().toURL() };
URLClassLoader loader = new URLClassLoader(urls, Thread.currentThread().getContextClassLoader());

Thread.currentThread().setContextClassLoader(loader);

//Hibernate can start
//you should restore your old classloader when hibernate services end

You can better understand how to work hibernate jdbc connection taking a look at org.hibernate.connection.DriverManagerConnectionProvider class (or ConnectionProvider subclasses)

_________________
everything should be made as simple as possible, but not simpler (AE)


Top
 Profile  
 
 Post subject: Re: How to dynamically load Drivers from a JAR
PostPosted: Thu Feb 18, 2010 11:00 am 
Newbie

Joined: Wed Feb 17, 2010 7:09 pm
Posts: 3
Hi hallmit,
My code was similar to your code with the exception that I would restore the ClassLoader immediately after opening a session (which you indicate is a mistake).
I change my code to keep the class loader and replace it only when the session ic closed.

However now I get the following errors:
org.hibernate.exception.JDBCConnectionException: Cannot open connection
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:97)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:52)
at org.hibernate.jdbc.ConnectionManager.openConnection(ConnectionManager.java:449)
at org.hibernate.jdbc.ConnectionManager.getConnection(ConnectionManager.java:167)
at org.hibernate.jdbc.AbstractBatcher.prepareQueryStatement(AbstractBatcher.java:161)
at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:1577)
at org.hibernate.loader.hql.QueryLoader.iterate(QueryLoader.java:422)
at org.hibernate.hql.ast.QueryTranslatorImpl.iterate(QueryTranslatorImpl.java:405)
at org.hibernate.engine.query.HQLQueryPlan.performIterate(HQLQueryPlan.java:248)
at org.hibernate.impl.SessionImpl.iterate(SessionImpl.java:1220)
at org.hibernate.impl.QueryImpl.iterate(QueryImpl.java:69)
at com.swx.tools.repo.QueryRepo.getWindows(QueryRepo.java:38)
at com.swx.tools.hbmupdater.popup.actions.TestHibernateAction.run(TestHibernateAction.java:36)
at org.eclipse.ui.internal.PluginAction.runWithEvent(PluginAction.java:251)
at org.eclipse.jface.action.ActionContributionItem.handleWidgetSelection(ActionContributionItem.java:584)
at org.eclipse.jface.action.ActionContributionItem.access$2(ActionContributionItem.java:501)
at org.eclipse.jface.action.ActionContributionItem$5.handleEvent(ActionContributionItem.java:411)
at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:84)
at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1003)
at org.eclipse.swt.widgets.Display.runDeferredEvents(Display.java:3880)
at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3473)
at org.eclipse.ui.internal.Workbench.runEventLoop(Workbench.java:2405)
at org.eclipse.ui.internal.Workbench.runUI(Workbench.java:2369)
at org.eclipse.ui.internal.Workbench.access$4(Workbench.java:2221)
at org.eclipse.ui.internal.Workbench$5.run(Workbench.java:500)
at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:332)
at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:493)
at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:149)
at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:113)
at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:194)
at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:110)
at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:79)
at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:368)
at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:179)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:559)
at org.eclipse.equinox.launcher.Main.basicRun(Main.java:514)
at org.eclipse.equinox.launcher.Main.run(Main.java:1311)
at org.eclipse.equinox.launcher.Main.main(Main.java:1287)
Caused by: java.sql.SQLException: No suitable driver found for jdbc:oracle:thin:@10.12.89.31:1521:orcl
at java.sql.DriverManager.getConnection(Unknown Source)
at java.sql.DriverManager.getConnection(Unknown Source)
at org.hibernate.connection.DriverManagerConnectionProvider.getConnection(DriverManagerConnectionProvider.java:133)
at org.hibernate.jdbc.ConnectionManager.openConnection(ConnectionManager.java:446)
... 39 more

This still seems that Hibernate can not find the main Driver class or connection.

Any ideas?

Thanks
Yigal


Top
 Profile  
 
 Post subject: Re: How to dynamically load Drivers from a JAR
PostPosted: Thu Feb 18, 2010 1:01 pm 
Regular
Regular

Joined: Thu May 07, 2009 5:56 am
Posts: 94
Location: Toulouse, France
you're right! my snippet code works only when sessionFactory starts but not after...in fact, i saw in DriverManagerConnectionProvider (configure() method) that hibernate try to find the driver class using Thread.currentThread().getContextClassLoader() as last option
Code:
try {
            // trying via forName() first to be as close to DriverManager's semantics
            Class.forName(driverClass);
         }
         catch (ClassNotFoundException cnfe) {
            try {
               ReflectHelper.classForName(driverClass);
            }
            catch (ClassNotFoundException e) {
               String msg = "JDBC Driver class not found: " + driverClass;
               log.error( msg, e );
               throw new HibernateException(msg, e);
            }
         }

....
ReflectHelper.classForName() method:
try {
         ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
         if ( contextClassLoader != null ) {
            return contextClassLoader.loadClass(name);
         }
      }
      catch ( Throwable ignore ) {
      }


But when application (after hibernate initialization) requests to obtain a connection the follow code is used:
Connection conn = DriverManager.getConnection(url, connectionProps);

however, in this case, DriverManager looks for caller classloader (to find registered Driver) and not your custom ClassLoader (which registered the Driver).

I think either you must supply your own implementation of ConnectionProvider and use :
Code:
Class<?> clazz = Class.forName(driverClass, true, Thread.currentThread().getContextClassLoader());
Driver loadedDriver = (Driver) clazz.newInstance();
conn = loadedDriver.connect(jdbcUrl, infos);


or inspire you of org.hibernate.console.ConsoleConfiguration class and registerFakeDriver method. I noted they use DriverManager.registerDriver(Driver) method. the jars which contains this class is: org.hibernate.eclipse.jar

I hope it help you!

_________________
everything should be made as simple as possible, but not simpler (AE)


Top
 Profile  
 
 Post subject: Re: How to dynamically load Drivers from a JAR
PostPosted: Fri Feb 19, 2010 1:16 am 
Newbie

Joined: Mon Feb 15, 2010 2:39 am
Posts: 4
I recently was in a situation where I needed to load the MySQL driver in a Java application without modifying the classpath. Dynamically loading a database driver Jar can allow a java application to communicate with any database that supports jdbc with a minimal amount of configuration.

First step is to download the MySQL driver jar. The driver I used is mysql-connector-java-5.1.6-bin.jar, which is the standard jar you would want to use if you were going to add it to the classpath manually. You’ll need to create an account with Sun and agree to their terms of use.

Now we need to load this jar into the application. To do this we can extend the URLClassLoader class for our particular use, which is very simple:


public MySQLLoader extends URLClassLoader
{
public MySQLLoader (URL[] urls)
{
super (urls);
}
public void addFile (String path) throws MalformedURLException
{
String urlPath = “jar:file://” + path + “!/”;
addURL ( new URL (urlPath) );
}
//…

_________________
r4 gold ds


Top
 Profile  
 
 Post subject: Re: How to dynamically load Drivers from a JAR
PostPosted: Thu Feb 25, 2010 12:41 pm 
Beginner
Beginner

Joined: Wed Nov 21, 2007 8:02 am
Posts: 48
@syndony : I am new to this class loader thing. But how your solution differs from the URL class loader hallmit defined in his initial post.
And how do you register that the class loader you defined should be used when Class.forName(driverClass); is called.

thanks in advance.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 6 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.