• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Ron McLeod
  • Paul Clapham
  • Tim Cooke
  • Devaka Cooray
Sheriffs:
  • Liutauras Vilda
  • paul wheaton
  • Rob Spoor
Saloon Keepers:
  • Tim Moores
  • Stephan van Hulst
  • Tim Holloway
  • Piet Souris
  • Mikalai Zaikin
Bartenders:
  • Carey Brown
  • Roland Mueller

Stateless SB and Synchronization

 
Ranch Hand
Posts: 89
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Long winded explanation of question commences:

There is a popular pattern when using Hibernate within a web application where a filter is used to open a hibernate session when a request has begun and closes it when the request ends.

I would like to be able to do something similar with my Stateless session beans. However, what I would like to be able to do is listen for when the CMT Transaction ends and close the hibernate session then. So, it would go something like this:

1. A transaction is begun when a stateless session bean method is called (the transaction setting is 'Required'). This may or may not be the bean that makes use of Hibernate.
2. A SLSB method that uses Hibernate checks a ThreadLocal to see if a hibernate session exists on this thread. If not, it creates the session, and also registers some kind of listener on the container-provided JTA transaction via the Synchronization interface (presumbaly). Note that I said Synchronization...not SessionSynchronization. I can't use SessionSynchronization because this is a SLSB.
3. The method does its database work using Hibernate.
4. The method ends. This does not necessarily mean the transaction ends, so I don't necessarily want to have the hibernate session closed yet. I may want to use the same hibernate session again within the same transaction but from another method call or SLSB.
5. The transaction ends. At this time, my listener is informed and I close the Hibernate session, thus committing any database changes. I also remove the Hibernate session from the ThreadLocal.

I know that this is possible, because Spring does it (or something very similar). However, I am unable to use Spring for political reasons within my company. So I need to make a home grown solution.

The part that I haven't figured out yet is how to attach a listener to the CMT (JTA) Transaction. I think I can do this within a SLSB method:

TransactionManager mgr =
(TransactionManager)sessionCtx.getUserTransaction();

Transaction tran = mgr.getTransaction();

tran.registerSynchronization(myImplementationOfSynchronization);

But is it okay to assume that the UserTransaction returned from the SessionContext can be cast to a TransactionManager?

Is there a better way to do what I want? I've done a lot of searching without success for an answer...

Thanks!
[ August 11, 2005: Message edited by: Jeff Wisard ]
 
Ranch Hand
Posts: 30
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hello Jeff,

The code you provided is not possible.
===============
TransactionManager mgr =
(TransactionManager)sessionCtx.getUserTransaction();

Transaction tran = mgr.getTransaction();

tran.registerSynchronization(myImplementationOfSynchronization);
===============
An UserTransaction cannot be casted to a TransactionManager. See for more information about JTA http://java.sun.com/products/jta
You do not have access to the TransactionManager via the sessionCtx in a SLSB. I doubt if you have access to the TransactionManager at all in an EJB container.

Regarding your problem: Check out paragraph 4.8.3 of the Hibernate ref manual 3.0.5. It says there:
"For non-managed environments we suggested HibernateUtil with a static SessionFactory, and ThreadLocal
management of the Hibernate Session. This approach isn't easy to use in an EJB environment, as several EJB's
may execute inside the same transaction but not the same thread. We recommend that you bind the Session-
Factory to JNDI in a managend environment.
Instead of rolling your own ThreadLocal utility, use the getCurrentSession() method on the SessionFactory
to obtain a Hibernate Session. If there is no Hibernate Session in current JTA transaction, one will be started
and assigned. Both the hibernate.transaction.flush_before_completion and hibernate.
transaction.auto_close_session configuration option, will be set automatically for every Session you
retrieve with getCurrentSession(), so they will also be flushed and closed automatically when the container
ends the JTA transactions."

Hopes this helps you in finding a solution.

Regards,
Lars
 
Jeff Wisard
Ranch Hand
Posts: 89
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Yea, I've seen the getCurrentSession() method and how it works. Two problems, though. First, we're stuck on Hibernate 2.1.6 for the immediate future. The getCurrentSession() method was introduced in Hibernate 3. Secondly, I have requirements to be able to run our code external to the container. This means that we can't manage the session factory from JNDI (at least without some logic to determine where we are running). It also means that even when we upgrade to Hibernate 3, we can't use the getCurrentSession() method.

So, I'm back to the same problem. I know that what I want to do is possible, because the Spring Framework does it using its JtaTransactionManager that hooks into the container provided transaction framework. But, like I said, I can't use Spring.

Any other help?
 
Lars Vonk
Ranch Hand
Posts: 30
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Okay I see what you mean... you have some tough requirements there!
I have not tried this myself but maybe its worth a try:
In Hibernate you can also access the TransactionManager via the TransactionManagerLookup interface, there are some implementations for this interface like the WebSphereTransactionManagerLookup. I am not sure how you can get a hold an implementation of the TransactionManagerLookup. Try to downcast the SessionFactory to a SessionFactoryImplementor, there you have a method getTransactionManager(). This will return the TransactionManager defined in your hibernate config file (hibernate.transaction.manager_lookup_class).
TransactionManager transactionManager = ((SessionFactoryImplementor)sessionFactory).getTransactionManager();
Or just try to instantiate the TransactionManagerLookup .
TransactionManagerLookup tLookup = new WebSphereTransactionManagerLookup();
TransactionManager transactionManager = tLookup.getTransactionManager(Properties);
What properties you give to getTransactionManager probably depends on your application server.
If you have the TransactionManager then you can say:
Transaction t = transactionManager.getTransaction();
t.registerSynchronization(myImplementationOfSynchronization);


Good luck and please let me now if this works for you.

PS
I think the requirement "should run outside a container" is very difficult and expensive to achieve when you are relying on j2ee services like CMT and you are not allowed to use frameworks like Spring (yeh, i know politics...).
[ August 12, 2005: Message edited by: Lars Vonk ]
 
Jeff Wisard
Ranch Hand
Posts: 89
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thanks! I'll try that and see what happens. We're running in Weblogic, so I'll see if there is an associated class.

FYI UPDATE:
Hibernate has the TransactionManagedLookupFactory that can appropriately return the transaction manager given your context properties.
[ August 12, 2005: Message edited by: Jeff Wisard ]
 
Jeff Wisard
Ranch Hand
Posts: 89
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Okay, I have a solution to the problem of getting a reference to the containers transaction manager. Here it is:


The only wildcard here is the string to send to the lookup method. What you see here is the string that is needed for Weblogic...and possibly other servers. This may be different dependent on the server and I intend to make it configurable.

I did this within a SLSB method and I my Synchronization implementation successfully recieved the message, so I'm good to go. Thanks a lot for your insight, Lars. You definitely pointed me in the right direction.

The only thing that I am not sure of is whether this is considered 'legal' in the context of a SLSB. Considering that the TransactionManager is not exposed from the SessionContext, it may not be. However, this is exactly what Hibernate is doing when it needs to get a reference to the container provided transaction....and Hibernate is used from with SLSBs frequently. So, I'm going to go with it.

I'm actually thinking of writing a dynamic proxy (because AOP has not yet broken our corporate IT wall yet either) to make sure this code is being called before each Hibernated business object method. I will only call this code if a Hibernate session is not already attached to the thread via a ThreadLocal.

I'll post later to let you know how it works out. Thanks, again.
 
Lars Vonk
Ranch Hand
Posts: 30
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thanks for your feedback Jeff, and thanks for sharing your findings.
In my opinion I don't think it's recommended (or 'legal') to interact with Transaction's directly in a container. But for the purpose your using it, and seeing your requirements, I would not worry about that. Good idea using the dynamic proxy. (It's starting to look like a nice framework )

Lars
 
Did you just should on me? You should read this tiny ad:
We need your help - Coderanch server fundraiser
https://coderanch.com/wiki/782867/Coderanch-server-fundraiser
reply
    Bookmark Topic Watch Topic
  • New Topic