You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tapestry.apache.org by Glen Stampoultzis <gs...@iinet.net.au> on 2003/11/18 00:54:27 UTC
Hibernate session management in tapestry pages
Hi,
I'm currently using the following pattern when obtaining hibernate sessions
in my pages.
Visit visit = ( (Visit) getVisit() );
Session session = visit.openSession();
Transaction transaction = null;
try
{
transaction = session.beginTransaction();
transaction.commit();
}
catch ( HibernateException e )
{
HibernateUtil.rollback( transaction );
throw e;
}
catch ( RuntimeException e )
{
HibernateUtil.rollback( transaction );
throw e;
}
finally
{
HibernateUtil.tryClose( session );
}
The problem here is that I'm repeating the same logic all over the
place. I'm wondering if it would be possible to subclass BasePage so that
I can setup a session at the start of the page cycle, tear it down when the
page cycle is finished and commit or rollback depending whether things went
well or badly. Where would be the best place to hook these functions?
Regards,
Glen Stampoultzis
gstamp@iinet.net.au
http://members.iinet.net.au/~gstamp/glen/
---------------------------------------------------------------------
To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tapestry-user-help@jakarta.apache.org
Re[2]: Hibernate session management in tapestry pages
Posted by Richard Perfect <ri...@rperfect.net>.
Hi Glen,
You can also get more architecturally pure and separate database code
into one layer that doesn't know anything about Tapestry - that way
it's easier to migrate at a later time. I'm quite new to Tapestry but
have been using Hibernate for well over a year now and what we've done
is write a "Service" approach that intercepts calls to services in
order to handle transaction management - a bit like EJBs but without
all of the weight of EJBs.
Our Tapestry code looks like;
public void saveAction(IRequestCycle requestCycle) {
IPersonService personService = (IPersonService)ServiceFactory.getInstance().find(IPersonService.class);
personService.save(getPerson());
// Go back to the PersonSearch page
PersonSearchPage personSearchPage = (PersonSearchPage)requestCycle.getPage("PersonSearch");
personSearchPage.search();
requestCycle.activate(personSearchPage);
}
Where the ServiceFactory returns a interceptor ServiceProxy (a Dynamic
Proxy) that deals with the transaction management.
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
Throwable thrown = null;
try {
//System.out.println("before method " + method.getName());
targetService.begin();
result = method.invoke(targetService, args);
// only reached this if no exception is thrown
targetService.commit();
}
catch (InvocationTargetException e) {
targetService.rollback();
thrown = e.getTargetException();
}
catch (Exception e) {
targetService.rollback();
thrown = e;
}
finally {
//System.out.println("after method " + method.getName());
}
if( thrown != null ) {
throw thrown;
}
else {
return result;
}
}
The design consequences are;
- There's only one ServiceProxy
- Transaction management is isolated within one place
- Concrete Service classes must implement an interface (a bit like
the Remote interface from EJBs)
- Service level code has no import dependancy on Tapestry and can be
used independantly of Tapestry
- Services can call other services but there's only one transaction
(it's not easy to see here but it does happen)
- The ServiceFactory can potentially return different kinds of
services for different reasons. For example we started out with
Castor but then migrated to Hibernate, for about five development
releases there were a mixture of some services using Castor and
some using Hibernate - but the application code doesn't care.
Not all of the code has been shown here, if anyone would like to see
more send me an email.
- Richard Perfect.
Tuesday, November 18, 2003, 2:26:16 PM, you wrote:
GS> Thanks Paul,
GS> You've given me a lot to think about. Comments inline.
GS> At 11:42 AM 18/11/2003, you wrote:
>>Personally, I think that since most pages will not perform transactions
>>that it's best not to hard wire a transaction context to a page. Since
>>transactions will most likely occur in IActionListeners (triggered from
>>form submissions),
GS> Well I was thinking that you might not necessarily start the transaction
GS> until you call something like super.beginTrans(). This way you don't start
GS> anything unless you need it.
>>you might want to implement a custom action listener -
>>something like this perhaps:
>>
>>public class TransactableActionListener implements IActionListener
>>{
>> public abstract void transact(Session session, IComponent component,
>> IRequestCycle cycle) throws HibernateException;
>>
>> public final void trigger(IComponent component, IRequestCycle cycle)
>> {
>> // Wouldn't it be better to store your SessionFactory in the
>> global object
>> // rather than a reference in each Visit object (i.e. servlet
>> context instead of HttpSession)?
>> Visit visit = ( (Visit) cycle.getPage().getVisit() );
>> Session session = visit.openSession();
>> Transaction transaction = null;
>> try
>> {
>> transaction = session.beginTransaction();
>> transact(session, component, cycle);
>> transaction.commit();
>> }
>> catch ( HibernateException e )
>> {
>> HibernateUtil.rollback( transaction );
>> throw e;
>> }
>> catch ( RuntimeException e )
>> {
>> HibernateUtil.rollback( transaction );
>> throw e;
>> }
>> finally
>> {
>> HibernateUtil.tryClose( session );
>> }
>> }
>>}
>>
>>In your page, rather than supplying an action listener the traditional way
>>(which uses Tapestry class enhancement), you would provide an accessor to
>>your own action listener impl:
>>
>>public IActionListener getFormSubmitListener()
>>{
>> return new TransactableActionListener()
>> {
>> public void transact(Session session, IComponent component,
>> IRequestCycle requestCycle) throws HibernateException
>> {
>> // Put business logic here
>> }
>> };
>>}
>>
>>What do you think?
GS> Nice. It doesn't completely solve my needs at the moment but comes
GS> close. I also have an issue with passing sessions to component models
GS> (tacos tree) which the ThreadLocal pattern might handle for me nicely.
>>As an alternative solution, you may also want to check out the ThreadLocal
>>Session pattern if you haven't already:
>>http://www.hibernate.org/42.html
GS> I hadn't. It looks like it might be what I need too.
>>Hope this helps,
>>
>>Paul Ferraro
GS> Big help, thanks.
---------------------------------------------------------------------
To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tapestry-user-help@jakarta.apache.org
Re: Hibernate session management in tapestry pages
Posted by Glen Stampoultzis <gs...@iinet.net.au>.
Thanks Paul,
You've given me a lot to think about. Comments inline.
At 11:42 AM 18/11/2003, you wrote:
>Personally, I think that since most pages will not perform transactions
>that it's best not to hard wire a transaction context to a page. Since
>transactions will most likely occur in IActionListeners (triggered from
>form submissions),
Well I was thinking that you might not necessarily start the transaction
until you call something like super.beginTrans(). This way you don't start
anything unless you need it.
>you might want to implement a custom action listener -
>something like this perhaps:
>
>public class TransactableActionListener implements IActionListener
>{
> public abstract void transact(Session session, IComponent component,
> IRequestCycle cycle) throws HibernateException;
>
> public final void trigger(IComponent component, IRequestCycle cycle)
> {
> // Wouldn't it be better to store your SessionFactory in the
> global object
> // rather than a reference in each Visit object (i.e. servlet
> context instead of HttpSession)?
> Visit visit = ( (Visit) cycle.getPage().getVisit() );
> Session session = visit.openSession();
> Transaction transaction = null;
> try
> {
> transaction = session.beginTransaction();
> transact(session, component, cycle);
> transaction.commit();
> }
> catch ( HibernateException e )
> {
> HibernateUtil.rollback( transaction );
> throw e;
> }
> catch ( RuntimeException e )
> {
> HibernateUtil.rollback( transaction );
> throw e;
> }
> finally
> {
> HibernateUtil.tryClose( session );
> }
> }
>}
>
>In your page, rather than supplying an action listener the traditional way
>(which uses Tapestry class enhancement), you would provide an accessor to
>your own action listener impl:
>
>public IActionListener getFormSubmitListener()
>{
> return new TransactableActionListener()
> {
> public void transact(Session session, IComponent component,
> IRequestCycle requestCycle) throws HibernateException
> {
> // Put business logic here
> }
> };
>}
>
>What do you think?
Nice. It doesn't completely solve my needs at the moment but comes
close. I also have an issue with passing sessions to component models
(tacos tree) which the ThreadLocal pattern might handle for me nicely.
>As an alternative solution, you may also want to check out the ThreadLocal
>Session pattern if you haven't already:
>http://www.hibernate.org/42.html
I hadn't. It looks like it might be what I need too.
>Hope this helps,
>
>Paul Ferraro
Big help, thanks.
Re: Hibernate session management in tapestry pages
Posted by Paul Ferraro <pm...@columbia.edu>.
Personally, I think that since most pages will not perform transactions
that it's best not to hard wire a transaction context to a page. Since
transactions will most likely occur in IActionListeners (triggered from
form submissions), you might want to implement a custom action listener -
something like this perhaps:
public class TransactableActionListener implements IActionListener
{
public abstract void transact(Session session, IComponent component,
IRequestCycle cycle) throws HibernateException;
public final void trigger(IComponent component, IRequestCycle cycle)
{
// Wouldn't it be better to store your SessionFactory in the
global object
// rather than a reference in each Visit object (i.e. servlet
context instead of HttpSession)?
Visit visit = ( (Visit) cycle.getPage().getVisit() );
Session session = visit.openSession();
Transaction transaction = null;
try
{
transaction = session.beginTransaction();
transact(session, component, cycle);
transaction.commit();
}
catch ( HibernateException e )
{
HibernateUtil.rollback( transaction );
throw e;
}
catch ( RuntimeException e )
{
HibernateUtil.rollback( transaction );
throw e;
}
finally
{
HibernateUtil.tryClose( session );
}
}
}
In your page, rather than supplying an action listener the traditional
way (which uses Tapestry class enhancement), you would provide an
accessor to your own action listener impl:
public IActionListener getFormSubmitListener()
{
return new TransactableActionListener()
{
public void transact(Session session, IComponent component,
IRequestCycle requestCycle) throws HibernateException
{
// Put business logic here
}
};
}
What do you think?
As an alternative solution, you may also want to check out the
ThreadLocal Session pattern if you haven't already:
http://www.hibernate.org/42.html
Hope this helps,
Paul Ferraro
Glen Stampoultzis wrote:
>
> Hi,
>
> I'm currently using the following pattern when obtaining hibernate
> sessions in my pages.
>
> Visit visit = ( (Visit) getVisit() );
> Session session = visit.openSession();
> Transaction transaction = null;
> try
> {
> transaction = session.beginTransaction();
>
> transaction.commit();
> }
> catch ( HibernateException e )
> {
> HibernateUtil.rollback( transaction );
> throw e;
> }
> catch ( RuntimeException e )
> {
> HibernateUtil.rollback( transaction );
> throw e;
> }
> finally
> {
> HibernateUtil.tryClose( session );
> }
>
>
> The problem here is that I'm repeating the same logic all over the
> place. I'm wondering if it would be possible to subclass BasePage so
> that I can setup a session at the start of the page cycle, tear it
> down when the page cycle is finished and commit or rollback depending
> whether things went well or badly. Where would be the best place to
> hook these functions?
>
> Regards,
>
>
> Glen Stampoultzis
> gstamp@iinet.net.au
> http://members.iinet.net.au/~gstamp/glen/
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: tapestry-user-help@jakarta.apache.org
>
---------------------------------------------------------------------
To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tapestry-user-help@jakarta.apache.org