Thread: 8.0 drivers released.

8.0 drivers released.

From
Kris Jurka
Date:
With the 8.0 server release coming later this week, I've put up a new set
of JDBC drivers.  I haven't had time to write up a full set of release
notes, so this email will have to suffice for now...

Naturally there are a huge number of minor improvements and fixes,
but these are the big things in 8.0:

- True V3 protocol support.
- Savepoints.
- No more "idle in transaction" problems.
- Binary data doesn't use fifty times the necessary memory.
- SSL connection customization
- driver configuration via properties file
- 5.0 JDK compiles

Major compatibility issues that come to mind immediately.

The driver now always uses some form of server prepared statement.  This
means that all data is now strongly typed instead of mashed together into
a query string for the server to figure out.  If you have an application
that uses setString(x, myString) for every type, you are not going to be
happy.  The driver needs to know what the real column type is in the
database and it infers this from the setXXX call you make.  This presents
some tricky problems when dealing with postgresql datatypes that do not
match up exactly with Java datatypes that are only solved by using a
custom PGobject subclass to pass both the data and the correct type to the
driver.  This also extends to null values, no longer is setObject(x, null)
valid because it does not contain type information for the driver to use.

Previously Statement.executeQuery("INSERT ... ; SELECT currval('myseq')");
would return a ResultSet.  This is no longer true and I don't believe it
was ever strictly legal.  This should be correctly written in separate
queries or:

Statement.execute("INSERT ...; SELECT currval('myseq')");
Statement.getMoreResults();
ResultSet rs = Statement.getResultSet();

Calling PreparedStatement.setBinaryStream now requires a correct length
argument.  Previously Integer.MAX_VALUE or similar could be used and it
would read the stream to completion, but with the ability to stream data
directly to the server and not use up outrageous amounts of memory means
that we need to know the correct length from the outset.

Kris Jurka

Re: 8.0 drivers released.

From
Andreas Joseph Krogh
Date:
On Monday 17 January 2005 13:48, Kris Jurka wrote:
> With the 8.0 server release coming later this week, I've put up a new set
> of JDBC drivers.  I haven't had time to write up a full set of release
> notes, so this email will have to suffice for now...
>
> Naturally there are a huge number of minor improvements and fixes,
> but these are the big things in 8.0:
>
> - True V3 protocol support.
> - Savepoints.
> - No more "idle in transaction" problems.
> - Binary data doesn't use fifty times the necessary memory.
> - SSL connection customization
> - driver configuration via properties file
> - 5.0 JDK compiles
>
> Major compatibility issues that come to mind immediately.
>
> The driver now always uses some form of server prepared statement.  This
> means that all data is now strongly typed instead of mashed together into
> a query string for the server to figure out.  If you have an application
> that uses setString(x, myString) for every type, you are not going to be
> happy.  The driver needs to know what the real column type is in the
> database and it infers this from the setXXX call you make.  This presents
> some tricky problems when dealing with postgresql datatypes that do not
> match up exactly with Java datatypes that are only solved by using a
> custom PGobject subclass to pass both the data and the correct type to the
> driver.  This also extends to null values, no longer is setObject(x, null)
> valid because it does not contain type information for the driver to use.
>
> Previously Statement.executeQuery("INSERT ... ; SELECT currval('myseq')");
> would return a ResultSet.  This is no longer true and I don't believe it
> was ever strictly legal.  This should be correctly written in separate
> queries or:
>
> Statement.execute("INSERT ...; SELECT currval('myseq')");
> Statement.getMoreResults();
> ResultSet rs = Statement.getResultSet();
>
> Calling PreparedStatement.setBinaryStream now requires a correct length
> argument.  Previously Integer.MAX_VALUE or similar could be used and it
> would read the stream to completion, but with the ability to stream data
> directly to the server and not use up outrageous amounts of memory means
> that we need to know the correct length from the outset.
>
> Kris Jurka

Hi!
I tried using postgresql-8.0.309.jdbc2.jar (and jdbc3) and got the following
NullPointerException:
Caused by: java.lang.NullPointerException
        at org.postgresql.Driver.getDefaultProperties(Driver.java:84)
        at org.postgresql.Driver.connect(Driver.java:167)
        at org.apache.catalina.realm.JDBCRealm.open(JDBCRealm.java:599)

Any explaination?

--
Andreas Joseph Krogh <andreak@officenet.no>
Senior Software Developer / Manager
gpg public_key: http://dev.officenet.no/~andreak/public_key.asc
------------------------+---------------------------------------------+
OfficeNet AS            | Can i wash my clothes with my dvd drive?    |
Hoffsveien 17           | Or do i need to replace it with a washing   |
PO. Box 425 Skøyen      | machine??                                   |
0213 Oslo               |                                             |
NORWAY                  |                                             |
Phone : +47 22 13 01 00 |                                             |
Direct: +47 22 13 10 03 |                                             |
Mobile: +47 909  56 963 |                                             |
------------------------+---------------------------------------------+

Attachment

Re: 8.0 drivers released.

From
Oliver Jowett
Date:
Andreas Joseph Krogh wrote:

> NullPointerException:
> Caused by: java.lang.NullPointerException
>         at org.postgresql.Driver.getDefaultProperties(Driver.java:84)
>         at org.postgresql.Driver.connect(Driver.java:167)
>         at org.apache.catalina.realm.JDBCRealm.open(JDBCRealm.java:599)

Driver.java:84 is:

Enumeration urlEnum =
getClass().getClassLoader().getResources("org/postgresql/driverconfig.properties");

I guess that org.postgresql.Driver is being loaded by the bootstrap
classloader (getClassLoader() returns null). How exactly are you getting
the driver jar into the classpath?

-O

Re: 8.0 drivers released.

From
Andreas Joseph Krogh
Date:
On Tuesday 18 January 2005 12:58, you wrote:
> Andreas Joseph Krogh wrote:
> > NullPointerException:
> > Caused by: java.lang.NullPointerException
> >         at org.postgresql.Driver.getDefaultProperties(Driver.java:84)
> >         at org.postgresql.Driver.connect(Driver.java:167)
> >         at org.apache.catalina.realm.JDBCRealm.open(JDBCRealm.java:599)
>
> Driver.java:84 is:
>
> Enumeration urlEnum =
> getClass().getClassLoader().getResources("org/postgresql/driverconfig.prope
>rties");
>
> I guess that org.postgresql.Driver is being loaded by the bootstrap
> classloader (getClassLoader() returns null). How exactly are you getting
> the driver jar into the classpath?

I saw that line too, but would never have guessed that getClassLoader()
returnes null(don't know much about classloaders). I'm trying to load a
ConnectionPool in Tomcat-5.0.28 and had my pg.jar in
$TOMCAT_HOME/common/endorsed/, when I moved it to $TOMCAT_HOME/common/lib/ it
works ok. It used to work in common/endorsed with previous releases(including
8.0.beta4 which is the last one I tried before 8.0 final).

Anyway, the problem is now gone, thanks!

--
Andreas Joseph Krogh <andreak@officenet.no>
Senior Software Developer / Manager
gpg public_key: http://dev.officenet.no/~andreak/public_key.asc
------------------------+---------------------------------------------+
OfficeNet AS            | Can i wash my clothes with my dvd drive?    |
Hoffsveien 17           | Or do i need to replace it with a washing   |
PO. Box 425 Skøyen      | machine??                                   |
0213 Oslo               |                                             |
NORWAY                  |                                             |
Phone : +47 22 13 01 00 |                                             |
Direct: +47 22 13 10 03 |                                             |
Mobile: +47 909  56 963 |                                             |
------------------------+---------------------------------------------+

Attachment

Re: 8.0 drivers released.

From
Peter Eisentraut
Date:
Am Montag, 17. Januar 2005 13:48 schrieb Kris Jurka:
> With the 8.0 server release coming later this week, I've put up a new set
> of JDBC drivers.  I haven't had time to write up a full set of release
> notes, so this email will have to suffice for now...

Could you please not name the tarballs "postgresql-8.0.309.src.tar.gz" etc.  I
think there is a chance that this will be confused with postgresql proper.
Maybe "postgresql-jdbc" is a better stem.

--
Peter Eisentraut
http://developer.postgresql.org/~petere/

Re: 8.0 drivers released.

From
Oliver Jowett
Date:
Oliver Jowett wrote:
> Andreas Joseph Krogh wrote:
>
>> NullPointerException:
>> Caused by: java.lang.NullPointerException
>>         at org.postgresql.Driver.getDefaultProperties(Driver.java:84)
>>         at org.postgresql.Driver.connect(Driver.java:167)
>>         at org.apache.catalina.realm.JDBCRealm.open(JDBCRealm.java:599)
>
> Driver.java:84 is:
>
> Enumeration urlEnum =
> getClass().getClassLoader().getResources("org/postgresql/driverconfig.properties");
>
> I guess that org.postgresql.Driver is being loaded by the bootstrap
> classloader (getClassLoader() returns null). How exactly are you getting
> the driver jar into the classpath?

I can reproduce the exception by running test code when the driver is
loaded from the bootstrap classpath
('-Xbootclasspath/a:jars/postgresql.jar')

It seems reasonable to fall back to the system classloader if the driver
was loaded from the bootstrap classloader. I will commit a change to do
this shortly.

-O

context classloader (was: Re: 8.0 drivers released.)

From
Vadim Nasardinov
Date:
On Tuesday 18 January 2005 17:17, Oliver Jowett wrote:
> I can reproduce the exception by running test code when the driver
> is loaded from the bootstrap classpath
> ('-Xbootclasspath/a:jars/postgresql.jar')
>
> It seems reasonable to fall back to the system classloader if the
> driver was loaded from the bootstrap classloader. I will commit a
> change to do this shortly.

Another reasonable course of action might be to try the context classloader:
http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Thread.html#getContextClassLoader%28%29

This would typically have the system classloader in its parent hierarchy,
but it may also give you access to locations that the system classloader
cannot see.

Re: context classloader

From
Oliver Jowett
Date:
Vadim Nasardinov wrote:

> Another reasonable course of action might be to try the context classloader:
> http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Thread.html#getContextClassLoader%28%29
>
> This would typically have the system classloader in its parent hierarchy,
> but it may also give you access to locations that the system classloader
> cannot see.

I am of the opinion that thread context classloaders are evil and should
be avoided if at all possible -- they make code fragile and sensitive to
caller context (almost by definition!)

Also it'd mean that we would have to load the defaults on every call to
getConnection(), rather than once per Driver instance (i.e. most
probably exactly once). Does it make sense to have the driver defaults
change depending on who is obtaining the connection?

-O

Re: context classloader

From
Vadim Nasardinov
Date:
On Tuesday 18 January 2005 18:07, Oliver Jowett wrote:
> I am of the opinion that thread context classloaders are evil

If that's a moral judgment, I have no comment.  If a technical one --
where's the evidence?  (My ignorance prevents me from taking sides in
this argument.  I'm just curious.)

> and should be avoided if at all possible -- they make code fragile
> and sensitive to caller context (almost by definition!)

It doesn't have to be any more sensitive than the current situation.
Current code is also sensitive to caller context.  The Driver.class's
classloader depends on the caller.  The thrust of your argument seems
to be that this is a one-time dependency.  Once established, it
doesn't changed for the remainder of the class's lifecycle.

Well, the same could be true of a context-classloader-based
implementation.

When you register the Driver instance with the DriverManager in the
static initializer, a (weak) reference to the current context
classloader may be saved in a static field.  The field can be used
later on in the getDefaultProperties() method, if
getClass().getClassLoader() turns out to be null.  (BTW, couldn't this
be Driver.class.getClassLoader() instead?)

> Does it make sense to have the driver defaults change depending on
> who is obtaining the connection?

The fact that this is nonsensical is irrelevant.  Changing defaults on
a per connection basis has never been proposed.

More to the point, can someone explain what
/org/postgresql/driverconfig.properties files are actually used for?
Google doesn't seem to know:
  http://www.google.com/search?q=%22driverconfig.properties%22


Without knowing what this feature is actually used for, I'd speculate
groundlessly that the context-classloader-based implementation is more
likely to work in the application server scenario.  Within the same
app server instance, multiple *.properties files are likely to exist
for use by different apps.  These files aren't likely to be on the
CLASSPATH.  Rather, they're likely to be in a per-application config
directory that the system classloader can't see.

Re: context classloader

From
Oliver Jowett
Date:
Vadim Nasardinov wrote:
> On Tuesday 18 January 2005 18:07, Oliver Jowett wrote:
>
>>I am of the opinion that thread context classloaders are evil
>
>
> If that's a moral judgment, I have no comment.  If a technical one --
> where's the evidence?  (My ignorance prevents me from taking sides in
> this argument.  I'm just curious.)

It's just an opinion. I have been bitten by context classloader
weirdness often enough that I try to avoid it whenever I can.

If you use the CCL, you have added hidden coupling between whoever sets
the CCL and the use of the CCL. Hidden coupling is usually bad -- it
makes the code less obvious and more prone to context-sensitive
breakage. Many libraries depend on particular CCL settings *and do not
document this anywhere*. Really hidden coupling!

It gets worse if you are in a managed environment -- the environment may
be using the CCL for its own purposes, and your code may not even have
permission (security policy) to change the CCL.

To use a CCL-using library reliably in that sort of environment, you end
up setting and resetting the CCL on every call to the library (might
involve writing a privileged wrapper -- ugh!). This defeats the purpose
of having a CCL in the first place. Why not just configure the library
with the right ClassLoader via another mechanism, or explicitly pass a
ClassLoader to those methods that need to do class/resource loading?

Sorry .. it's a pet peeve of mine :)

Given that there is a non-ClassLoader-aware layer (DriverManager)
between the JDBC client and JDBC driver that we cannot change, if we
needed to pass a ClassLoader then using the CCL is probably the best
way. But I don't see that we *need* to pass a ClassLoader at all; see below.

> When you register the Driver instance with the DriverManager in the
> static initializer, a (weak) reference to the current context
> classloader may be saved in a static field.  The field can be used
> later on in the getDefaultProperties() method, if
> getClass().getClassLoader() turns out to be null.

Ok, but I don't understand why you'd want to jump through all these
hoops in the first place. It is even less predictable when the static
initializer will be run (and therefore what the CCL will be set to at
that point). What's the point?

> (BTW, couldn't this
> be Driver.class.getClassLoader() instead?)

Yes. getClass() tends to be a bit friendlier to anything that tweaks the
bytecode, though, since a .class reference compiles down to a call to
Class.forName() which breaks if the class is renamed, etc.

>>Does it make sense to have the driver defaults change depending on
>>who is obtaining the connection?
>
> The fact that this is nonsensical is irrelevant.  Changing defaults on
> a per connection basis has never been proposed.

*shrug* It's the logical conclusion of using the CCL to find the
defaults. The context can change -- why do the defaults *not* change if
you change the context? What is special about the context of the first
call to getConnection(), or the first action that happens to cause class
initialization (if you go with magic in the static initializer)?

> More to the point, can someone explain what
> /org/postgresql/driverconfig.properties files are actually used for?

Briefly, configuring driver defaults globally without having to mess
around with every application URL.

See http://archives.postgresql.org/pgsql-jdbc/2004-10/msg00023.php for
the thread that spawned it.

> Without knowing what this feature is actually used for, I'd speculate
> groundlessly that the context-classloader-based implementation is more
> likely to work in the application server scenario.  Within the same
> app server instance, multiple *.properties files are likely to exist
> for use by different apps.  These files aren't likely to be on the
> CLASSPATH.

I don't think it makes sense to allow a particular application to
override a bit of "global" data for the driver that is shared between
multiple applications. App servers can reconfigure the driver either
globally or on a per-application basis easily enough anyway.

> Rather, they're likely to be in a per-application config directory that the system classloader can't see.

The system classloader only gets involved when the driver has been
loaded in the *bootstrap* classpath. In all other cases, we use the
classloader that loaded the driver to load the defaults. Still, this
will usually be a classloader that cannot see the per-application resources.

If an application wants a customized set of defaults, it can arrange for
a separate instance of the driver packaged with the appropriate defaults
to be loaded with the application; in that case, there's no problem with
finding the right classloader.

-O

Re: context classloader

From
Vadim Nasardinov
Date:
On Tuesday 18 January 2005 23:12, Oliver Jowett wrote:
> Ok, but I don't understand why you'd want to jump through all these
> hoops in the first place.

Because you may want to be a good citizen in the app server world,
where defaulting to the system classloader still seems suboptimal to
me.  This use case has been adequately addressed in your reply though.
I don't want to press this line of reasoning any further.


> It is even less predictable when the static initializer will be run
> (and therefore what the CCL will be set to at that point). What's
> the point?

The same goes for getClass().getClassLoader().  It's not predictable
what this returns.


> It's the logical conclusion of using the CCL to find the defaults.

I don't see how that follows.

> What is special about [...] the first action that happens to cause
> class initialization (if you go with magic in the static
> initializer)?

It's special because it determines the result of
getClass().getClassLoader().  In other words, it's special because
current code treats as such:

        Enumeration urls = getClass().getClassLoader().
            getResources("/org/postgresql/driverconfig.properties");


For the sake of completeness, what do you think of doing nothing in
the case when the driver is loaded by the bootstrap classloader?  In
other words, wrap the affected chunk of code in the following
conditional:

        if (getClass().getClassLoader() != null) {
            // load the /org/postgresql/driverconfig.properties files
        }


Thanks,
Vadim




P.S.

> > (BTW, couldn't this be Driver.class.getClassLoader() instead?)
>
> Yes. getClass() tends to be a bit friendlier to anything that tweaks
> the bytecode, though, since a .class reference compiles down to a
> call to Class.forName() which breaks if the class is renamed, etc.

Out of curiosity, is it a formal policy of the pgsql-jdbc project to
be friendly to bytecode mungers?  What other guidelines does one need
to be mindful of?

Re: context classloader

From
Oliver Jowett
Date:
Vadim Nasardinov wrote:
> On Tuesday 18 January 2005 23:12, Oliver Jowett wrote:

>>It is even less predictable when the static initializer will be run
>>(and therefore what the CCL will be set to at that point). What's
>>the point?
>
> The same goes for getClass().getClassLoader().  It's not predictable
> what this returns.

Two comments:

Firstly, your statement is not true. getClass().getClassLoader() will
always return the classloader that was used to load the driver class,
which *is* predictable. You can always, for example, put
driverconfig.properties in the path of the same classloader that loads
the driver (at worst, by packaging it directly in the driver jar) and
the driver will find it. In contrast, if you're relying on the CCL, you
have essentially no guarantees about where it will search. It could be a
completely unrelated CL that can't even see the driver jar!

Secondly, I think you missed my point. It is the *timing* of
initialization that I am concerned about. Timing of class initialization
is hard to predict; how do you make sure that the CCL is correctly set
when this happens? How do you document this so that users don't get
confused? It seems unreasonable to require someone who just wants to use
the JDBC driver to have to understand the mechanics of class
initialization and guard against accidentally causing initialization
before they're ready!

>>What is special about [...] the first action that happens to cause
>>class initialization (if you go with magic in the static
>>initializer)?
>
> It's special because it determines the result of
> getClass().getClassLoader().

It does not. getClass().getClassLoader() always returns the classloader
that loaded org.postgresql.Driver, regardless of the environment when
class initialization is triggered. The returned classloader will not
change during the lifetime of a particular copy of the Driver class.

If you are using the CCL to locate the defaults, then either the context
set during initialization is somehow special (if you only load the
defaults once) or you must load the defaults on every getConnection()
and they can change depending on the caller's context. I don't like
either behaviour.

> For the sake of completeness, what do you think of doing nothing in
> the case when the driver is loaded by the bootstrap classloader?  In
> other words, wrap the affected chunk of code in the following
> conditional:
>
>         if (getClass().getClassLoader() != null) {
>             // load the /org/postgresql/driverconfig.properties files
>         }

It could do that (it does that if the system classloader is null) but it
seems less useful -- why can the driver suddenly no longer load defaults
if it ends up in the bootstrap classpath?

Ideally we need some way to get resources directly from the bootstrap
classloader, but ClassLoader does not give us a way to do that. Using
the system classloader seems like the best approximation.

>>Yes. getClass() tends to be a bit friendlier to anything that tweaks
>>the bytecode, though, since a .class reference compiles down to a
>>call to Class.forName() which breaks if the class is renamed, etc.
>
> Out of curiosity, is it a formal policy of the pgsql-jdbc project to
> be friendly to bytecode mungers?  What other guidelines does one need
> to be mindful of?

Personally I write lots of other code that has to be friendly to
bytecode mungers, so it becomes force of habit. It's not a formal
policy, just one of my own code hygiene rules.

-O

Re: context classloader

From
Vadim Nasardinov
Date:
On Wednesday 19 January 2005 15:53, Oliver Jowett wrote:
> Firstly, your statement is not true. getClass().getClassLoader()
> will always return the classloader that was used to load the driver
> class, which *is* predictable.

That part is predictable, yes.  What's not predictable is which
*particular* classloader this will be.

> You can always, for example, put driverconfig.properties in the path
> of the same classloader that loads the driver

Not always, you can't.

> In contrast, if you're relying on the CCL, you have essentially no
> guarantees about where it will search. It could be a completely
> unrelated CL that can't even see the driver jar!

Why is that so terrible?


> Secondly, I think you missed my point. It is the *timing* of
> initialization that I am concerned about. Timing of class
> initialization is hard to predict; how do you make sure that the CCL
> is correctly set when this happens?

I think I understood your point the first time around.  My
counterpoint is, the current getClass().getClassLoader() approach is
in a very similar boat.  If one can put
org/postgresql/driverconfig.properties on the same classpath as the
driver, then, yes, they're all set.  (Except for the bootstrap
classloader case.)  If they can't do that, then they're essentially in
the same boat.  How does one make sure that the classloader that loads
org.postgresql.Driver is also the one that can find their
driverconfig.properties?

> How do you document this so that users don't get confused?

As the first step, documenting the existence of
driverconfig.properties would be nice.   Other than
  http://archives.postgresql.org/pgsql-jdbc/2004-10/thrd2.php#00023

is it mentioned anywhere else?  Does anyone actually use this?

> It seems unreasonable to require someone who just wants to use the
> JDBC driver to have to understand the mechanics of class
> initialization and guard against accidentally causing initialization
> before they're ready!

It's an argument I wholeheartedly agree with.  I'd just like to point
out that it also applies to the current situation.


> It could do that (it does that if the system classloader is null)
> but it seems less useful -- why can the driver suddenly no longer
> load defaults if it ends up in the bootstrap classpath?

I keep forgetting to ask.  How do you put the driver in the bootstrap
classpath?  The only way that I know of is to use one of the following
flags under Sun's JRE:

 -Xbootclasspath
 -Xbootclasspath/a
 -Xbootclasspath/p

I was under the impression that using these is very uncommon.



Thanks for taking the time to answer my questions.


Vadim

Re: context classloader

From
Kris Jurka
Date:

On Fri, 21 Jan 2005, Vadim Nasardinov wrote:

> As the first step, documenting the existence of
> driverconfig.properties would be nice.   Other than
>   http://archives.postgresql.org/pgsql-jdbc/2004-10/thrd2.php#00023
>
> is it mentioned anywhere else?  Does anyone actually use this?
>

Well, it's a problem of limited resources.  We've had SSL support for a
year and half, but it wasn't until last week that how to set it up was
documented anywhere but the mailing list.  Writing documentation is
neither fun nor really necessary for the developers because we already
know how it works.  Not ideal, but that's kind of the way it has been.
As volunteer developers we're primarily users and only secondarily
maintainers for other users.

The need to actually use this mechanism is restricted to very specialized
applications.  The key addition is auto-registering custom class mappings,
the additional default settings were thrown in largely because we could.


Kris Jurka

Re: context classloader

From
Oliver Jowett
Date:
Vadim Nasardinov wrote:

> That part is predictable, yes.  What's not predictable is which
> *particular* classloader this will be.

It is a different class of predictability. If you know where the driver
is loaded from, you know at least one location checked by the driver's
classloader -- the driver jar. You have no information about the CCL in
effect at driver load time, though.

>>You can always, for example, put driverconfig.properties in the path
>>of the same classloader that loads the driver
>
> Not always, you can't.

Why not? If you could put the driver jar there, why can't you also put
properties there?

>>In contrast, if you're relying on the CCL, you have essentially no
>>guarantees about where it will search. It could be a completely
>>unrelated CL that can't even see the driver jar!
>
> Why is that so terrible?

It's much less predictable. Given information on where the driver is
loaded from, you have no idea where it will load defaults from. At least
with using getClass().getClassLoader(), you know at least one location
(the driver jar's location), and can probably infer several more from
knowledge about how you configure classpaths to load the driver from.

>  If one can put
> org/postgresql/driverconfig.properties on the same classpath as the
> driver, then, yes, they're all set.  (Except for the bootstrap
> classloader case.)  If they can't do that, then they're essentially in
> the same boat.  How does one make sure that the classloader that loads
> org.postgresql.Driver is also the one that can find their
> driverconfig.properties?

Know your environment; supply a classpath for loading the driver that
includes a location that you can modify. e.g. add it to CLASSPATH, or
include it in the classpath-to-load-driver-from configuration, or put it
in the magic directory whose contents are included at startup, etc.

> I keep forgetting to ask.  How do you put the driver in the bootstrap
> classpath?  The only way that I know of is to use one of the following
> flags under Sun's JRE:
>
>  -Xbootclasspath
>  -Xbootclasspath/a
>  -Xbootclasspath/p
>
> I was under the impression that using these is very uncommon.

Well, the case that triggered this thread happened by putting the driver
jar in a particular directory that apparently was in the appserver's
bootstrap classpath. It's not common, but I don't see why the driver
should break if it happens.

-O

Re: context classloader

From
Vadim Nasardinov
Date:
To draw a line under this thread, here are my takeaways.

The purpose of org/postgresql/driverconfig.properties is to globally
configure the driver.  The most consistent way to do this is to put
the config file on the same path as the driver's .jar file.

There are two distinct classes of users:

 (a) Those who have complete control over deployment of both the
     driver and the application that uses it.

 (b) Those who have limited control over their application's
     classpath.  (For a recent example, see [1].)


For Class A, the most consistent approach is to say,

 (a) Don't put pgsql-jdbc.jar on the boot classpath.  No reason to do
     this.

 (b) If you want to configure the driver globally, put
     org/postgresql/driverconfig.properties in the same location as
     the pgsql-jdbc.jar file.


For this class of users, then, the following works fine:

    if (getClass().getClassLoader() != null) {
        // load the config file
    }

For Class B, the most consistent approach is to say, Since you don't
have control over the driver's .jar file location, you're not meant to
have control over its global settings.  The same code works for this
class of users as well.

Defaulting to the system classloader strikes me as a fairly arbitrary
way to avoid an NPE.  I agree that using the context class loader is
an equally arbitrary cop-out.


On Friday 21 January 2005 15:07, Oliver Jowett wrote:
> Well, the case that triggered this thread happened by putting the
> driver jar in a particular directory that apparently was in the
> appserver's bootstrap classpath. It's not common, but I don't see
> why the driver should break if it happens.

It shouldn't break.  To prevent it from breaking, test the object for
nullity before calling a method on it.


Footnotes
  1. http://archives.postgresql.org/pgsql-jdbc/2004-12/msg00212.php

Re: context classloader

From
Oliver Jowett
Date:
Vadim Nasardinov wrote:

> It shouldn't break.  To prevent it from breaking, test the object for
> nullity before calling a method on it.

Yes, or replace the null object with something that isn't null. That's
what the change I made several days does :)

-O

Re: context classloader

From
Markus Schaber
Date:
Hi, Oliver and Vadim,

Oliver Jowett schrieb:

>> More to the point, can someone explain what
>> /org/postgresql/driverconfig.properties files are actually used for?
>
> Briefly, configuring driver defaults globally without having to mess
> around with every application URL.
>
> See http://archives.postgresql.org/pgsql-jdbc/2004-10/msg00023.php for
> the thread that spawned it.

One usage of it is that the new postgis.jar from PostGIS 1.0 includes
such a properties file, this auto-registers the PostGIS data type
extensions (PGobject subclasses) for geometry, box3d and box2d within
the jdbc driver just by throwing the postgis.jar into the classpath.

Note that users still can override this behaviour on a datasource or
connection basis via URL and addDataType().

Markus

--
markus schaber | dipl. informatiker
logi-track ag | rennweg 14-16 | ch 8001 zürich
phone +41-43-888 62 52 | fax +41-43-888 62 53
mailto:schabios@logi-track.com | www.logi-track.com

Attachment

Re: context classloader

From
Markus Schaber
Date:
Hi, Vadim,

Vadim Nasardinov schrieb:

>>How do you document this so that users don't get confused?
>
> As the first step, documenting the existence of
> driverconfig.properties would be nice.   Other than
>   http://archives.postgresql.org/pgsql-jdbc/2004-10/thrd2.php#00023
>
> is it mentioned anywhere else?  Does anyone actually use this?

PostGIS jdbc extension uses this since Version 1.0RC2 to auto-register
the PostGIS geometry types (PGobject subclasses).


Markus

--
markus schaber | dipl. informatiker
logi-track ag | rennweg 14-16 | ch 8001 zürich
phone +41-43-888 62 52 | fax +41-43-888 62 53
mailto:schabios@logi-track.com | www.logi-track.com