Issue Details (XML | Word | Printable)

Key: SPR-1633
Type: Improvement Improvement
Status: Resolved Resolved
Resolution: Won't Fix
Priority: Major Major
Assignee: Juergen Hoeller
Reporter: Costin Leau
Votes: 0
Watchers: 0
Operations

If you were logged in you would be able to see more operations.
Spring Framework

LocalSessionFactoryBean getConfigTimeDataSource should not be resetted

Created: 20/Jan/06 11:13 AM   Updated: 23/Jan/06 10:28 AM   Resolved: 21/Jan/06 12:14 PM
Component/s: SpringDA
Affects Version/s: 1.2.6
Fix Version/s: None

Time Tracking:
Not Specified


 Description  « Hide

The current implementation of LocalSessionFactoryBean resets the config time data source before leaving afterPropertiesSet. However, other frameworks that use Hibernate namely jbpm will not find a datasource when trying to create the schema as they will unfortunately reinstantiates a ConnectionProvider which will reuse the datasource which will return null. The issue is similar with (http://opensource2.atlassian.com/projects/spring/browse/SPR-1547) but the Spring-provided DataSource will be request during the HB sessionFactory life-time (between afterPropertiesSet and destroy).
The javadoc mention that :

  • This instance will be set before initialization of the corresponding
  • SessionFactory, and reset immediately afterwards. It is thus only available
  • during configuration.
    What's the reason for that?

You can find more details about the issue occuring in JBPM here: http://opensource2.atlassian.com/projects/spring/browse/MOD-75



Juergen Hoeller added a comment - 20/Jan/06 05:35 PM

Well, the issue is that Hibernate does not offer a straightforward way to pass in a DataSource reference. So we have to resort to using a ThreadLocal there. But that ThreadLocal is of course attached to a single thread: namely, the thread that starts up the application. For any operation at runtime, the call will occur within a thread from the application server's HTTP thread pool - none of which has the DataSource in a ThreadLocal. We can't access the init-time ThreadLocal at runtime anymore, hence we reset it before application startup completes.

I'm afraid that there is no proper solution to get around this... other than not using a "dataSource" on LocalSessionFactoryBean. Specifying a JNDI DataSource in standard Hibernate properties should work fine, even with reinstantiated ConnectionProviders at runtime.

Juergen


Costin Leau added a comment - 21/Jan/06 05:53 AM

LocalDataSourceConnectionProvider refers back to LocalSessionFactoryBean.getConfigTimeDataSource(); why is the DataSource available only on a thread local? what are the side effects of getConfigTimeDataSource returning LocalSessionFactoryBean's datasource always?
Moreover, the datasource actually is nullified at the end of afterPropertiesSet so other components that execute on the same thread (like jbpm factorybean which exectues after HB factorybean) will retrieve null. Is there any way to clean the threadlocal later?


Costin Leau added a comment - 21/Jan/06 06:00 AM

I have answered myself the first question - because all the methods are static, retrieving the datasource becomes tricky. The only solution would be to clean the threadlocal later but that might become a problem in appservers that reuse them and do not clean them up.


Juergen Hoeller added a comment - 21/Jan/06 06:05 AM

Well, "getConfigTimeDataSource()" is a static method - since Hibernate does not give us any chance to pass an object reference to a ConnectionProvider. If we'd keep the DataSource in an actual static field there, we'd have trouble setting up multiple SessionFactory instances within the same application - since we'd effectively have resorted to a static singleton there. Imagine that two SessionFactory instances point to two different DataSources... Hence, a ThreadLocal is still the most appropriate workaround to pass an object reference along, I'm afraid.

We can't clean the ThreadLocal later on either, since that would have to happen after LocalSessionFactoryBean finished its initialization already.

What exactly does JBPM do here? Does it search through Hibernate's configuration settings and reinstantiate the ConnectionProvider itself? Why does it do such a thing in the first place?

Juergen


Costin Leau added a comment - 21/Jan/06 06:16 AM

When creating a schema, it will try to get a connection by calling directly on HB connection provider:

connectionProvider = ConnectionProviderFactory.newConnectionProvider(properties);

I agree that there is not much to do around here and the issue can be closed. I'll see if there is a why to overwrite the method from JbpmSchema to make it work. Rob was suggesting the usage of AspectJ since a lot of session handling is happening in a hard-coded way inside Jbpm - I hope to not be 'forced' to use that but we'll see. jbpm 3.1.0 should come out in the near future and deprecates the current code hopefully in a better way. However, it would be nice to provide compatibility with 3.0.x generation even though there are only 3 versions out(3.0.0-3.0.2).


Juergen Hoeller added a comment - 21/Jan/06 12:14 PM

OK, thanks for the info. I hope we can customize JBPM accordingly, at least for JBPM 3.1.

It's really a pain that Hibernate considers ConnectionProviders as something to be recreated... After all, even in case of a local connection pool within the connection provider, this means recreated connection pools... Only in case of a JNDI DataSource, it's pointing to the same connection pool - or more correctly, re-pointing to it.

Juergen


Costin Leau added a comment - 23/Jan/06 10:21 AM

Just for the record I've ended up implementing the same mechanism used within orm.hibernate3. One thing that would remove some duplication would be:

1. have a getDataSource() for LocalSessionFactoryBean - other FactoryBean can overcome the problem by setting their own threadlocals to the datasource. Right now the user needs to inject it into jBPM SessionFactoryBean.
2. make LocalDataSourceConnectionProvider more pluggable:
~ change the datasources from private to protected or add some (protected) setters for them.
~ move this.dataSource = LocalJbpmSessionFactoryBean.getConfigTimeDataSource() to a separate method (which subclasses can overwrite with their own implementation).

The changes would not 'expose' too many internals and would make the copy of hibernate connectionProvider hack simpler.


Costin Leau added a comment - 23/Jan/06 10:28 AM

I rushed to make the comment - 1. should be removed since the code is anyway unaware of Spring FactoryBean (it uses a Hibernate SessionFactory).