File APIs for Java Developers
Manipulate DOC, XLS, PPT, PDF and many others from your application.
http://aspose.com/file-tools
The moose likes EJB and other Java EE Technologies and the fly likes Stateless SB and Synchronization Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Spring in Action this week in the Spring forum!
JavaRanch » Java Forums » Java » EJB and other Java EE Technologies
Bookmark "Stateless SB and Synchronization" Watch "Stateless SB and Synchronization" New topic
Author

Stateless SB and Synchronization

Jeff Wisard
Ranch Hand

Joined: Jan 07, 2002
Posts: 89
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 ]

Jeff Wisard<br />Sun Certified Java Programmer (Java 2)<br />Sun Certified Web Component Developer
Lars Vonk
Ranch Hand

Joined: Aug 05, 2005
Posts: 30
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

Joined: Jan 07, 2002
Posts: 89
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

Joined: Aug 05, 2005
Posts: 30
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

Joined: Jan 07, 2002
Posts: 89
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

Joined: Jan 07, 2002
Posts: 89
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

Joined: Aug 05, 2005
Posts: 30
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
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: Stateless SB and Synchronization