🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: borland.public.jbuilder.java.language
10 messages
10 total messages Started by George Tue, 28 Mar 2006 14:18
changing class path at run time
#248
Author: George
Date: Tue, 28 Mar 2006 14:18
15 lines
1256 bytes
I want to load JDBC drivers on demand.  The user tells me the driver class name and where the jar files are located and my app loads the driver.  Or so I would like.  The following code does not work:

try {
  System.setProperty("java.class.path", path + ";"    + "C:\\MyDrivers\\ojdbc14.jar" );
     Class.forName("oracle.jdbc.OracleDriver");
    } catch (Exception ex) {
      ex.printStackTrace();
    }


The code works if I include the jar file on the java command line invocation.  What am I doing wrong?

TIA
George
Re: changing class path at run time
#249
Author: George
Date: Tue, 28 Mar 2006 15:12
19 lines
1383 bytes
"George" <me@here.com> wrote:
>
>I want to load JDBC drivers on demand.  The user tells me the driver class name and where the jar files are located and my app loads the driver.  Or so I would like.  The following code does not work:
>
>try {
>  System.setProperty("java.class.path", path + ";"    + "C:\\MyDrivers\\ojdbc14.jar" );
>     Class.forName("oracle.jdbc.OracleDriver");
>    } catch (Exception ex) {
>      ex.printStackTrace();
>    }
>
>
>The code works if I include the jar file on the java command line invocation.  What am I doing wrong?
>
>TIA
>George
>
>Never mind.  I just found out about URLClassLoader.  
Re: changing class path at run time
#250
Author: Paul Furbacher [TeamB]
Date: Tue, 28 Mar 2006 16:23
42 lines
2335 bytes
George wrote:
> "George" <me@here.com> wrote:
>> I want to load JDBC drivers on demand.  The user tells me the
>> driver class name and where the jar files are located and my app
>> loads the driver.  Or so I would like.  The following code does
>> not work:
>> 
>> try { System.setProperty("java.class.path", path + ";"    +
>> "C:\\MyDrivers\\ojdbc14.jar" ); 
>> Class.forName("oracle.jdbc.OracleDriver"); } catch (Exception ex)
>> { ex.printStackTrace(); }
>> 
>> 
>> The code works if I include the jar file on the java command line
>> invocation.  What am I doing wrong?
>> 
>> TIA George
>> 
>> Never mind.  I just found out about URLClassLoader.

Yes.  There are several open source projects (e.g., OR mappers)
which have tools that provide you with this capability.  One
which comes to mind is objectstyle.org's Cayenne Modeler.
You might want to study their code to see if you can enhance
what you already have accomplished.  (It's always good to see
how other folks approach a problem.)


-- 


Paul Furbacher (TeamB)

   Save time, search the archives:
        http://info.borland.com/newsgroups/ngsearch.html

   Is it in Joi Ellis's Faq-O-Matic?
        http://www.visi.com/~gyles19/fom-serve/cache/1.html

   Finally, please send responses to the newsgroup only.
   That means, do not send email directly to me.
   Thank you.
Re: changing class path at run time
#251
Author: George
Date: Tue, 28 Mar 2006 20:00
62 lines
3120 bytes
"Paul Furbacher [TeamB]" <pfurbacher@mac.com> wrote:
>George wrote:
>> "George" <me@here.com> wrote:
>>> I want to load JDBC drivers on demand.  The user tells me the
>>> driver class name and where the jar files are located and my app
>>> loads the driver.  Or so I would like.  The following code does
>>> not work:
>>> 
>>> try { System.setProperty("java.class.path", path + ";"    +
>>> "C:\\MyDrivers\\ojdbc14.jar" ); 
>>> Class.forName("oracle.jdbc.OracleDriver"); } catch (Exception ex)
>>> { ex.printStackTrace(); }
>>> 
>>> 
>>> The code works if I include the jar file on the java command line
>>> invocation.  What am I doing wrong?
>>> 
>>> TIA George
>>> 
>>> Never mind.  I just found out about URLClassLoader.
>
>Yes.  There are several open source projects (e.g., OR mappers)
>which have tools that provide you with this capability.  One
>which comes to mind is objectstyle.org's Cayenne Modeler.
>You might want to study their code to see if you can enhance
>what you already have accomplished.  (It's always good to see
>how other folks approach a problem.)
>
>
>-- 
>
>
>Paul Furbacher (TeamB)
>
>   Save time, search the archives:
>        http://info.borland.com/newsgroups/ngsearch.html
>
>   Is it in Joi Ellis's Faq-O-Matic?
>        http://www.visi.com/~gyles19/fom-serve/cache/1.html
>
>   Finally, please send responses to the newsgroup only.
>   That means, do not send email directly to me.
>   Thank you.

I guess I spoke too soon.

I'm having trouble going the URLClassLoader route.  The code below succeeds in loading the Oracle jdbc driver...however the call to DriverManager.getConnection() returns saying "No suitable driver"...

George

    try {
      File f = new File(System.getProperty("user.dir") + "\\ojdbc14.jar");
      URL url = new URL("file:///"+ f.getAbsolutePath());
      URL [] urlList = new URL[1];
      urlList[0] = url;
      URLClassLoader cld = new URLClassLoader(urlList);
      Class cl = cld.loadClass("oracle.jdbc.OracleDriver");
      Connection connection = DriverManager.getConnection("jdbc:oracle:thin:@STPDB1P:1521:STP20P1", "fo", "fo");
    } catch (Exception ex) {
        ex.printStackTrace();
    }
Re: changing class path at run time
#164
Author: Paul Furbacher [TeamB]
Date: Tue, 28 Mar 2006 21:50
62 lines
2944 bytes
George wrote:

> I guess I spoke too soon.
> 
> I'm having trouble going the URLClassLoader route.  The code below
> succeeds in loading the Oracle jdbc driver...however the call to
> DriverManager.getConnection() returns saying "No suitable
> driver"...
> 
> George
> 
>     try {
>       File f = new File(System.getProperty("user.dir") + "\\ojdbc14.jar");
>       URL url = new URL("file:///"+ f.getAbsolutePath());
>       URL [] urlList = new URL[1];
>       urlList[0] = url;
>       URLClassLoader cld = new URLClassLoader(urlList);
>       Class cl = cld.loadClass("oracle.jdbc.OracleDriver");
>       Connection connection = 
           DriverManager.getConnection(
            "jdbc:oracle:thin:@STPDB1P:1521:STP20P1", "fo", "fo");
>     } catch (Exception ex) {
>         ex.printStackTrace();
>     }

If I look at how the Cayenne folks do it (Andrei Adamchik,
specifically) in

   org.objectstyle.cayenne.modeler.FileClassLoadingService

I notice that the new classloader is instantiated with a
parent classloader.

That's different from how you have done it.  Maybe that's
the difference; try

   URLClassLoader cld =
     new URLClassLoader(
       new URL [] { url },
       this.getClass().getClassLoader() );

Also, have you stepped through the above code in the
debugger and ascertained that "cl" is not null?  You
hinted that you have when you wrote "... succeeds in
loading the Oracle jdbc driver...", but I just want to
be sure.


-- 


Paul Furbacher (TeamB)

   Save time, search the archives:
        http://info.borland.com/newsgroups/ngsearch.html

   Is it in Joi Ellis's Faq-O-Matic?
        http://www.visi.com/~gyles19/fom-serve/cache/1.html

   Finally, please send responses to the newsgroup only.
   That means, do not send email directly to me.
   Thank you.
Re: changing class path at run time
#165
Author: Shankar Unni
Date: Wed, 29 Mar 2006 01:51
41 lines
2878 bytes
George wrote:

>       URLClassLoader cld = new URLClassLoader(urlList);
>       Class cl = cld.loadClass("oracle.jdbc.OracleDriver");
>       Connection connection = DriverManager.getConnection("jdbc:oracle:thin:@STPDB1P:1521:STP20P1", "fo", "fo");

This is really unlikely to work. Even if you had created "cld" with its 
parent set to ThisClass.getClass().getClassLoader(), you'd still have 
this hierarchy:

     ThisClass  <-     loaded by base class loader

     OracleDriver <-   loaded by "cld" (assuming that ojdbc14.jar is not 
in your regular classpath)

Remember that each class is loaded *in its own classloader* only. It is 
not visible to classes loaded by its parent classloader, or by classes 
loaded by other classloaders unrelated to its classloader.

So, OracleDriver in the above example is only visible to classes loaded 
by "cld", or by other classloaders that are children of "cld".

There's more to what Cayenne is doing than just making cld's parent the 
calling class' classloader. Check carefully to see how they make the 
driver visible.

I strongly suspect that they are doing something like this:

     URLClassLoader cld = new URLClassLoader(urlList);
     Class driverClass = cld.loadClass("oracle.jdbc.OracleDriver");
     // call the default constructor of the driver class
     // using reflection:
     Object driverObj = driverClass.newInstance();

At this point, assuming that oracle.jdbc.OracleDriver has a default 
constructor (should have), you'll see that the driver is now registered, 
and DriverManager.getConnection() should now work.

PS. Check the documentation to see if the preferred class is 
oracle.jdbc.OracleDriver, or oracle.jdbc.driver.OracleDriver. My memory 
is that Oracle now prefers that you use the latter name..
Re: changing class path at run time
#167
Author: George X
Date: Wed, 29 Mar 2006 20:31
68 lines
3811 bytes
Shankar Unni <shankarunni@netscape.net> wrote:
>George wrote:
>
>>       URLClassLoader cld = new URLClassLoader(urlList);
>>       Class cl = cld.loadClass("oracle.jdbc.OracleDriver");
>>       Connection connection = DriverManager.getConnection("jdbc:oracle:thin:@STPDB1P:1521:STP20P1", "fo", "fo");
>
>This is really unlikely to work. Even if you had created "cld" with its 
>parent set to ThisClass.getClass().getClassLoader(), you'd still have 
>this hierarchy:
>
>     ThisClass  <-     loaded by base class loader
>
>     OracleDriver <-   loaded by "cld" (assuming that ojdbc14.jar is not 
>in your regular classpath)
>
>Remember that each class is loaded *in its own classloader* only. It is 
>not visible to classes loaded by its parent classloader, or by classes 
>loaded by other classloaders unrelated to its classloader.
>
>So, OracleDriver in the above example is only visible to classes loaded 
>by "cld", or by other classloaders that are children of "cld".
>
>There's more to what Cayenne is doing than just making cld's parent the 
>calling class' classloader. Check carefully to see how they make the 
>driver visible.
>
>I strongly suspect that they are doing something like this:
>
>     URLClassLoader cld = new URLClassLoader(urlList);
>     Class driverClass = cld.loadClass("oracle.jdbc.OracleDriver");
>     // call the default constructor of the driver class
>     // using reflection:
>     Object driverObj = driverClass.newInstance();
>
>At this point, assuming that oracle.jdbc.OracleDriver has a default 
>constructor (should have), you'll see that the driver is now registered, 
>and DriverManager.getConnection() should now work.
>
>PS. Check the documentation to see if the preferred class is 
>oracle.jdbc.OracleDriver, or oracle.jdbc.driver.OracleDriver. My memory 
>is that Oracle now prefers that you use the latter name..

Paul & Shankar,

Please excuse my obtuseness.

I think I have incorporated your suggestions as in the code below.  However, DriverManager.getConnection still throws a SQLException of "No suitable driver".

Paul, to answer your question, yes, the call to cld.loadClass does return a non-null reference.

Thanks.
George

    try {
      TestSys testSys = new TestSys();  // an instance of this class
      File f = new File(System.getProperty("user.dir") + "\\ojdbc14.jar");
      URL url = new URL("file:///"+ f.getAbsolutePath());
      URL [] urlList = new URL[1];
      urlList[0] = url;
      URLClassLoader cld = new URLClassLoader(urlList, testSys.getClass().getClassLoader());
      Class cl = cld.loadClass("oracle.jdbc.driver.OracleDriver");
      Object driverObj = cl.newInstance();
      Connection connection = DriverManager.getConnection("jdbc:oracle:thin:@STPDB1P:1521:STP20P1", "fo", "fo");
    } catch (Exception ex) {
        ex.printStackTrace();
    }
Re: changing class path at run time
#168
Author: Paul Furbacher [TeamB]
Date: Thu, 30 Mar 2006 03:34
62 lines
3010 bytes
Try this:

   public void getConnection(
       String classname,
       String filename,
       String dbUrl,
       Properties props) {
     try {
       File f = new File(filename);
       URL[] urlList = new URL[] { f.toURL() };
       URLClassLoader cld =
           new URLClassLoader(
               urlList,
               this.getClass().getClassLoader());
       Driver driver =
           (Driver)cld.loadClass(classname).newInstance();
       Connection connection = driver.connect(dbUrl, props);
       /* instead of
       Connection connection =
           DriverManager.getConnection(dbUrl, props);
       */
     }
     catch (Exception ex) {
       ex.printStackTrace();
     }
   }


What I missed was the fact that you have to use
the driver instance itself in this scenario, not
the DriverManager whose class loader will never
know about the dynamically loaded class ... at least
I think that's the explanation.  [Feel free to correct
me if I'm wrong.]

[Thanks to the Cayenne contributors, Andrei Adamchik in particular,
for this solution.  If you want to see it yourself, see the class,
org.objectstyle.cayenne.conn.DriverDataSource.  It's unfortunate
that Cayenne is not more widely known -- my gut feeling is that
it's a heck of a lot smoother an experience than Hibernate, which
to me is very quirky.  Cayenne has just admitted as a Jakarta
Incubator project.

   http://incubator.apache.org/projects/cayenne.html

I'm hoping that will boost its prominence.]


-- 


Paul Furbacher (TeamB)

   Save time, search the archives:
        http://info.borland.com/newsgroups/ngsearch.html

   Is it in Joi Ellis's Faq-O-Matic?
        http://www.visi.com/~gyles19/fom-serve/cache/1.html

   Finally, please send responses to the newsgroup only.
   That means, do not send email directly to me.
   Thank you.
Re: changing class path at run time
#171
Author: George Xavier
Date: Sat, 01 Apr 2006 02:28
83 lines
3774 bytes
Yes, this works.  Thank you.

I guess my mental block was here :  "...you have to use  the driver instance
itself in this scenario,
not  the DriverManager whose class loader will never know about the
dynamically loaded class .....".

Anyway to get back to the issue which started this all:  looks like the
runtime never revisits the value of java.class.path after the VM has
started.  Wonder why.

Thanks again.
George X.


P.S Sorry I accidentally emailed you instead of the newsgroup in  posting my 
reply.


"Paul Furbacher [TeamB]" <pfurbacher@mac.com> wrote in message 
news:442b51bb$1@newsgroups.borland.com...
> Try this:
>
>   public void getConnection(
>       String classname,
>       String filename,
>       String dbUrl,
>       Properties props) {
>     try {
>       File f = new File(filename);
>       URL[] urlList = new URL[] { f.toURL() };
>       URLClassLoader cld =
>           new URLClassLoader(
>               urlList,
>               this.getClass().getClassLoader());
>       Driver driver =
>           (Driver)cld.loadClass(classname).newInstance();
>       Connection connection = driver.connect(dbUrl, props);
>       /* instead of
>       Connection connection =
>           DriverManager.getConnection(dbUrl, props);
>       */
>     }
>     catch (Exception ex) {
>       ex.printStackTrace();
>     }
>   }
>
>
> What I missed was the fact that you have to use
> the driver instance itself in this scenario, not
> the DriverManager whose class loader will never
> know about the dynamically loaded class ... at least
> I think that's the explanation.  [Feel free to correct
> me if I'm wrong.]
>
> [Thanks to the Cayenne contributors, Andrei Adamchik in particular,
> for this solution.  If you want to see it yourself, see the class,
> org.objectstyle.cayenne.conn.DriverDataSource.  It's unfortunate
> that Cayenne is not more widely known -- my gut feeling is that
> it's a heck of a lot smoother an experience than Hibernate, which
> to me is very quirky.  Cayenne has just admitted as a Jakarta
> Incubator project.
>
>   http://incubator.apache.org/projects/cayenne.html
>
> I'm hoping that will boost its prominence.]
>
>
> -- 
>
>
> Paul Furbacher (TeamB)
>
>   Save time, search the archives:
>        http://info.borland.com/newsgroups/ngsearch.html
>
>   Is it in Joi Ellis's Faq-O-Matic?
>        http://www.visi.com/~gyles19/fom-serve/cache/1.html
>
>   Finally, please send responses to the newsgroup only.
>   That means, do not send email directly to me.
>   Thank you. 
Re: changing class path at run time
#173
Author: Shankar Unni
Date: Mon, 03 Apr 2006 19:26
18 lines
2019 bytes
George Xavier wrote:

> Anyway to get back to the issue which started this all:  looks like the
> runtime never revisits the value of java.class.path after the VM has
> started.  Wonder why.

That's definitely true. The system class loader reads the value of this 
property *once*, and that's it.

It probably has to do with the overhead of getting the value and parsing 
it, and it would be rather expensive to do that for each class loaded 
(even a trivial program loads over a hundred classes).

If you want a dynamic system class path, you need to interpose a 
URLClassLoader in between. Or create your own class loader class (not 
hard to do) which can extend from URLClassLoader, and make it the system 
class loader by passing in 
"-Djava.system.class.loader=your.classloader.class.Name".
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads