You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tapestry.apache.org by Michael Sims <mi...@crye-leike.com> on 2007/06/20 00:19:55 UTC

Help with handling exceptions while using Hibernate's open-session-in-view pattern in Tapestry

Sorry again for the not 100% Tapestry related question, but I got such helpful
responses from my last question, and it's clear that there are a lot of people on
this list that have already solved these issues that I'm running into (and I'm
getting jack from the Hibernate forums ;) )...

I've implemented the "open session in view" pattern in my Tapestry application in
the fairly conventional way. I inject a threaded Session via Hivemind using a
service factory, and the service factory activates a transaction and creates a
ThreadCleanupListener to commit() the transaction and close the session when the
thread is done processing the user's request.  So far so good.

What I'm not sure how to do is handle situations where I may need to inform the user
that their transaction failed.  For example, let's say I have a typical CRUD
application to create new users for my system, and I want to be able to correctly
handle the scenario where an administrator attempts to create a new user with a name
that is already in use (a primary or unique key violation). I can't simply let the
ThreadCleanupListener handle the commit() in this case; if I do this, and an
exception is thrown, it is too late to inform the user since the request has already
been rendered.

The "Open Session in View" page on the Hibernate web site [1] states that a good
approach is to use two transactions in one Session.  If I took this approach, I
would attempt to commit the transaction in my listener method, and catch the
exception thrown from the database, and convert this into a validation error which
states that the username is already taken.

The problem with this is that the Hibernate documentation is quite clear that if any
exception occurs, the transaction should be rolled back, and the Session should be
closed and discarded.  Rolling back is not a problem, but if I close and discard the
Session, I'm no longer using "open session in view".  I'll have to go to the trouble
to initialize any lazy collections or proxies that the view might need before I
attempt the commit, otherwise I'll get a LazyInitializationException.

But I've read one of the Spring guys saying [2] that it's ok to begin a new
transaction on the same Session that has been rolled back, if you're only using it
to initialize lazy collections.  This would be nice if it were actually true; it
would simplify things for me quite a bit.  But I hestitate to rely on that, since
the Hibernate documentation says otherwise.

Can someone with a bit more experience with give me some advice on how to approach
this?  Thanks in advance...

[1] http://www.hibernate.org/43.html
[2] http://forum.springframework.org/showpost.php?p=29579&postcount=6


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


RE: Help with handling exceptions while using Hibernate's open-session-in-view pattern in Tapestry

Posted by Michael Sims <mi...@crye-leike.com>.
Sam wrote:
> I suppose Spring's transaction management would start a second
> transaction after rolling back the first one, but ONLY if you call a
> second service method that is wrapped in a transaction after getting
> an exception in a prior one.  Generally, my code is written such that
> a listener will probably only call a single service method directly,
> and any others will be called from inside the first, so the
> transaction that surrounds the first method will be inherited by any
> methods that are called from within it.  However, Spring's transaction
> manager will most definitely leave the session open after a
> transaction has been rolled back, which allows any lazily loaded
> objects to be loaded from the session during the rendering phase.

Thanks for the info.  Just to nitpick, if you're accessing lazily loaded objects,
you actually are starting a second transaction, just not explicitly.  Your database
driver must be in auto-commit mode if that works.  This is explicit in the Hibernate
reference manual (section 11.1.1), and also is mentioned on
http://www.hibernate.org/43.html under "Can I commit the transaction before
rendering the view?".

My only point is that you'll get a second transaction if a service method is called
OR if a not-yet-initialized collection or property is accessed in your view.  If
you're in auto-commit mode you may be more than just two, depending on how many lazy
properties are fetched.

> I
> can't guarantee it isn't a problem, but we've never had any issues
> with it, so I suspect the warning against reusing a rolledback session
> is related to writing objects baxck to the db, not simply reading
> them.

Yes, that's what I'm hoping.  I suppose I will find out soon. ;)  Thanks...


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


Re: Help with handling exceptions while using Hibernate's open-session-in-view pattern in Tapestry

Posted by Sam Gendler <sg...@ideasculptor.com>.
I suppose Spring's transaction management would start a second
transaction after rolling back the first one, but ONLY if you call a
second service method that is wrapped in a transaction after getting
an exception in a prior one.  Generally, my code is written such that
a listener will probably only call a single service method directly,
and any others will be called from inside the first, so the
transaction that surrounds the first method will be inherited by any
methods that are called from within it.  However, Spring's transaction
manager will most definitely leave the session open after a
transaction has been rolled back, which allows any lazily loaded
objects to be loaded from the session during the rendering phase.  I
can't guarantee it isn't a problem, but we've never had any issues
with it, so I suspect the warning against reusing a rolledback session
is related to writing objects baxck to the db, not simply reading
them.  Regardless, if you always catch the exception and go to an
error page, you'll never need to worry about lazily loading objects
after the excpetion causes a rollback, and that's about 98% of our
cases.

--sam

On 6/20/07, Michael Sims <mi...@crye-leike.com> wrote:
> Sam wrote:
> > In my case, I'm using Spring's transaction management code to inject,
> > via AOP, transaction semantics around service method calls.  This
> > means that my transaction commits when the service method (called from
> > the listener, almost always) returns, so I can catch any exceptions
> > before I even start rendering a response.  In the vast majority of
> > cases, if I get an error, I'm going to show an error page, so
> > accessing objects that may cause lazy loading after the exception and
> > rollback really isn't a problem, but I will say that in the few
> > instances where it does occur, it doesn't appear to be a problem,
> > precisely because anything involving lazy loading while rendering the
> > view is guaranteed to be a read-only operation.
>
> So, Spring's transaction management does in fact start a second transaction on the
> same session, even after an exception has been thrown, and you haven't seen an issue
> from this?  I think I'm going to go this route too, and only worry about it if a
> problem comes up.  If it does, I'll just make sure to eager fetch everything I might
> need on a listener method that might throw an "expected" exception, before the first
> transaction is committed, and then I'll just close the session rather that start a
> second transaction.
>
> > So in our case, we don't have to explicitly handle a transaction
> > manager, cause Spring is automatically injecting the start and commit
> > of each transaction, as appropriate, and that is all defined in a
> > config file rather than in code.
>
> That's very cool.  At this point in time the explicit calls to manage the
> transactions aren't bothering me, although I will probably refactor them out in the
> future.  I haven't gotten into AOP just yet and I'm not ready to introduce another
> complication, but it's definitely on my to-do list.
>
> Thanks...
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> For additional commands, e-mail: users-help@tapestry.apache.org
>
>

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


RE: Help with handling exceptions while using Hibernate's open-session-in-view pattern in Tapestry

Posted by Michael Sims <mi...@crye-leike.com>.
Sam wrote:
> In my case, I'm using Spring's transaction management code to inject,
> via AOP, transaction semantics around service method calls.  This
> means that my transaction commits when the service method (called from
> the listener, almost always) returns, so I can catch any exceptions
> before I even start rendering a response.  In the vast majority of
> cases, if I get an error, I'm going to show an error page, so
> accessing objects that may cause lazy loading after the exception and
> rollback really isn't a problem, but I will say that in the few
> instances where it does occur, it doesn't appear to be a problem,
> precisely because anything involving lazy loading while rendering the
> view is guaranteed to be a read-only operation.

So, Spring's transaction management does in fact start a second transaction on the
same session, even after an exception has been thrown, and you haven't seen an issue
from this?  I think I'm going to go this route too, and only worry about it if a
problem comes up.  If it does, I'll just make sure to eager fetch everything I might
need on a listener method that might throw an "expected" exception, before the first
transaction is committed, and then I'll just close the session rather that start a
second transaction.

> So in our case, we don't have to explicitly handle a transaction
> manager, cause Spring is automatically injecting the start and commit
> of each transaction, as appropriate, and that is all defined in a
> config file rather than in code.

That's very cool.  At this point in time the explicit calls to manage the
transactions aren't bothering me, although I will probably refactor them out in the
future.  I haven't gotten into AOP just yet and I'm not ready to introduce another
complication, but it's definitely on my to-do list.

Thanks...


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


Re: Help with handling exceptions while using Hibernate's open-session-in-view pattern in Tapestry

Posted by Sam Gendler <sg...@ideasculptor.com>.
In my case, I'm using Spring's transaction management code to inject,
via AOP, transaction semantics around service method calls.  This
means that my transaction commits when the service method (called from
the listener, almost always) returns, so I can catch any exceptions
before I even start rendering a response.  In the vast majority of
cases, if I get an error, I'm going to show an error page, so
accessing objects that may cause lazy loading after the exception and
rollback really isn't a problem, but I will say that in the few
instances where it does occur, it doesn't appear to be a problem,
precisely because anything involving lazy loading while rendering the
view is guaranteed to be a read-only operation.

So in our case, we don't have to explicitly handle a transaction
manager, cause Spring is automatically injecting the start and commit
of each transaction, as appropriate, and that is all defined in a
config file rather than in code.  There's almost certainly a way to
use the classes provided by spring to do that work from within
hiveming without actually using the spring aplpication context itself,
if you don't want to eal with yet another IoC container\, and the
mechanism works really well, allowing your application code to be
completely independent of transaction semantics.  To the listener
method that makes the service call, it just looks like an exception
was thrown in the service call if the transaction commit fails, and
you can handle that case from within the listener pretty trivially.

--sam

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


RE: Help with handling exceptions while using Hibernate's open-session-in-view pattern in Tapestry

Posted by Michael Sims <mi...@crye-leike.com>.
Steve Shucker wrote:
> You're right and now I feel stupid.

It's an easy mistake to make, I think.  Especially if it used to work and something
in the internals of Tapestry changed at some point.  I didn't mention it before
because I just assumed you weren't using friendly URLs...

> (needed it in a regular servlet filter once), so here's a version
> that works:

Nice, I'll use that, thanks.  That's better than my hack, for sure...


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


Re: Help with handling exceptions while using Hibernate's open-session-in-view pattern in Tapestry

Posted by Steve Shucker <ss...@vmsinfo.com>.
You're right and now I feel stupid.  I'm actually using tapestry 4.1.1, 
but I fired up the debugger to  double check.  Sure enough, it was 
applying my filter to asset requests.  I could swear this worked at one 
point.  Anyway, I had the code lying around to decode manually (needed 
it in a regular servlet filter once), so here's a version that works:

    private ServiceEncoder[] serviceEncoders;
   
    public void service(WebRequest request, WebResponse response, 
WebRequestServicer servicer)
        throws IOException {
        // don't filter asset requests
        ServiceEncodingImpl encoding = new 
ServiceEncodingImpl(request.getActivationPath(),request.getPathInfo(),extractParameters(request));
        for(ServiceEncoder serviceEncoder: serviceEncoders){
            serviceEncoder.decode(encoding);
            if(encoding.isModified()){
                break;
            }
        }
        if 
(Tapestry.ASSET_SERVICE.equals(encoding.getParameterValue(ServiceConstants.SERVICE))) 
{
            servicer.service(request, response);
        } else {
            filterRequest(request, response, servicer);
        }
    }
   
    // copied from somewhere in tapestry
    private QueryParameterMap extractParameters(WebRequest request) {
        QueryParameterMap result = new QueryParameterMap();
        Iterator i = request.getParameterNames().iterator();
        while (i.hasNext()) {
            String name = (String) i.next();
            String[] values = request.getParameterValues(name);
            if (values.length == 1) {
                result.setParameterValue(name, values[0]);
            } else {
                result.setParameterValues(name, values);
            }
        }
        return result;
    }

Here's the hivemind config to inject the encoders:

           <construct 
class="com.vms.infrastructure.websession.TapestrySessionTxFilter">
                   <set-object property="serviceEncoders" 
value="service-property:tapestry.url.LinkFactory:serviceEncoders"/>
            </construct>

Thanks for catching my bug!

-Steve


Michael Sims wrote:
> Steve Shucker wrote:
>   
>> Unless I'm really screwing up, my check works with friendly URLs.  I'm
>> using them.  They way I understand the pipeline is that service
>> encoders take the original http request and do some preprocessing
>> before you end up with a WebRequest.  Look at RequestCycleFactoryImpl
>> and AssetEncoder to see where this happens.  The short version is
>> that the WebRequest should have a parameter set that identifies the
>> tapestry service being called.
>>     
>
> What version of Tapestry?  In 4.0.2, the pipeline calls the
> WebRequestServicerFilter's before the RequestCycleFactory and the encoders have done
> their work.  With friendly URLs, a typical path for an asset is something like:
>
> /assets/031a6b16419c47ad157a817021baa2d6/class/path/file
>
> This is still the form it is in when it hits the filter.  getParameterNames()
> returns an empty list, getParameterValue(ServiceConstants.SERVICE) returns null.
> I'm currently using the following to recognize an asset request:
>
> "/assets".equals(request.getActivationPath())
>
> You can verify this in the debugger by setting a breakpoint in both the filter and
> line 81 of RequestCycleFactoryImpl (where decodeParameters() is called), and then
> issuing a request for an asset.  The filter will be reached first.
>
> The problem with this too, is that it's not immediately obvious that something is
> wrong.  The filter will still do its job, namely synchronizing the requests, but it
> will do it unnecessarily in the case of the asset requests.
>
> If you're on a different version where things have changed, please disregard.
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> For additional commands, e-mail: users-help@tapestry.apache.org
>
>   

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


RE: Help with handling exceptions while using Hibernate's open-session-in-view pattern in Tapestry

Posted by Michael Sims <mi...@crye-leike.com>.
Steve Shucker wrote:
> Unless I'm really screwing up, my check works with friendly URLs.  I'm
> using them.  They way I understand the pipeline is that service
> encoders take the original http request and do some preprocessing
> before you end up with a WebRequest.  Look at RequestCycleFactoryImpl
> and AssetEncoder to see where this happens.  The short version is
> that the WebRequest should have a parameter set that identifies the
> tapestry service being called.

What version of Tapestry?  In 4.0.2, the pipeline calls the
WebRequestServicerFilter's before the RequestCycleFactory and the encoders have done
their work.  With friendly URLs, a typical path for an asset is something like:

/assets/031a6b16419c47ad157a817021baa2d6/class/path/file

This is still the form it is in when it hits the filter.  getParameterNames()
returns an empty list, getParameterValue(ServiceConstants.SERVICE) returns null.
I'm currently using the following to recognize an asset request:

"/assets".equals(request.getActivationPath())

You can verify this in the debugger by setting a breakpoint in both the filter and
line 81 of RequestCycleFactoryImpl (where decodeParameters() is called), and then
issuing a request for an asset.  The filter will be reached first.

The problem with this too, is that it's not immediately obvious that something is
wrong.  The filter will still do its job, namely synchronizing the requests, but it
will do it unnecessarily in the case of the asset requests.

If you're on a different version where things have changed, please disregard.


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


Re: Help with handling exceptions while using Hibernate's open-session-in-view pattern in Tapestry

Posted by Steve Shucker <ss...@vmsinfo.com>.
Unless I'm really screwing up, my check works with friendly URLs.  I'm 
using them.  They way I understand the pipeline is that service encoders 
take the original http request and do some preprocessing before you end 
up with a WebRequest.  Look at RequestCycleFactoryImpl and AssetEncoder 
to see where this happens.  The short version is that the WebRequest 
should have a parameter set that identifies the tapestry service being 
called.

Thanks for the link.

-Steve

Michael Sims wrote:
> Steve Shucker wrote:
>   
>> I'm really fishing for a hivemind guru to tell me how to inject some
>> code in the tail end of the WebRequestServicer.service() method.
>>     
>
> Looks like something similar was discussed here:
>
> http://www.mail-archive.com/dev@tapestry.apache.org/msg00316.html
>
> Howard mentioned a possible feature addition to support this, and the original
> poster said that he would add a JIRA issue, but I wasn't able to locate it if it was
> ever added.
>
> This would come in handy for something unrelated... I'm implementing your
> WebRequestServicerFilter that handles synchronization for non-asset requests, but
> your code doesn't detect asset requests if friendly URLs (AssetEncoder) are enabled.
> I tried my best to find a way to leverage Tapestry's existing code to determine
> which service was scheduled for a particular request, but the only thing that can
> determine that is the IRequestCycle, and this isn't available in a
> WebRequestServicerFilter.  I had to resort to code similar to yours that handles the
> scheme AssetEncoder uses, but this code is fragile; if a new encoding method is
> employed the filter will not be able to detect asset requests.  Oh well, for now the
> kludge will have to do, I suppose.
>
>   
>> I'd consider a
>> dedicated session in pageBeginRender of my error page (with some
>> extra error handling) to set up the state for your error page.
>>     
>
> Thanks, but that won't work for two reasons: (1) I don't have an error page as such,
> many pages may need to handle these types of constraint violations, and sometimes
> only when certain listeners are called, and (2) that would require me to basically
> have two copies of all my persistent objects, one copy for each session.  I'd rather
> manually eager fetch everything that my template is going to need before attempting
> the commit than to do that...
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> For additional commands, e-mail: users-help@tapestry.apache.org
>
>   

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


RE: Help with handling exceptions while using Hibernate's open-session-in-view pattern in Tapestry

Posted by Michael Sims <mi...@crye-leike.com>.
Steve Shucker wrote:
> I'm really fishing for a hivemind guru to tell me how to inject some
> code in the tail end of the WebRequestServicer.service() method.

Looks like something similar was discussed here:

http://www.mail-archive.com/dev@tapestry.apache.org/msg00316.html

Howard mentioned a possible feature addition to support this, and the original
poster said that he would add a JIRA issue, but I wasn't able to locate it if it was
ever added.

This would come in handy for something unrelated... I'm implementing your
WebRequestServicerFilter that handles synchronization for non-asset requests, but
your code doesn't detect asset requests if friendly URLs (AssetEncoder) are enabled.
I tried my best to find a way to leverage Tapestry's existing code to determine
which service was scheduled for a particular request, but the only thing that can
determine that is the IRequestCycle, and this isn't available in a
WebRequestServicerFilter.  I had to resort to code similar to yours that handles the
scheme AssetEncoder uses, but this code is fragile; if a new encoding method is
employed the filter will not be able to detect asset requests.  Oh well, for now the
kludge will have to do, I suppose.

> I'd consider a
> dedicated session in pageBeginRender of my error page (with some
> extra error handling) to set up the state for your error page.

Thanks, but that won't work for two reasons: (1) I don't have an error page as such,
many pages may need to handle these types of constraint violations, and sometimes
only when certain listeners are called, and (2) that would require me to basically
have two copies of all my persistent objects, one copy for each session.  I'd rather
manually eager fetch everything that my template is going to need before attempting
the commit than to do that...


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


Re: Help with handling exceptions while using Hibernate's open-session-in-view pattern in Tapestry

Posted by Steve Shucker <ss...@vmsinfo.com>.
I'm really fishing for a hivemind guru to tell me how to inject some 
code in the tail end of the WebRequestServicer.service() method.  That 
would allow me to implement a general solution of flushing before the 
response is committed and forcing the exception to occur at a point 
where I can still notify the user.  I want things to be automatic rather 
than having to explicitly call Session.flush() in every listener 
method.  (If I was going to do that, I'd use an aspect.)

I know this doesn't quite solve your problem because you want to use 
another session to render your error response.  I'd consider a dedicated 
session in pageBeginRender of my error page (with some extra error 
handling) to set up the state for your error page.

-Steve

Michael Sims wrote:
> Steve Shucker wrote:
>   
>> Keep in mind the difference between a flush and a commit in hibernate.
>> A flush executes all the queued sql against the database without
>> committing the transaction.  Hibernate does this whenever it has
>> changes that needed to be sent to the database before a query is run.
>> Otherwise, it defers the flush until just before the commit.  Unless
>> you're using deferred constraints in oracle, constraint violations and
>> other db-related exceptions will be raised during the flush, not the
>> commit.
>>
>> What I'd really like to do is configure something in hivemind that
>> would run just before tapestry commits the response.  Then I could
>> call session.flush() there to force the exception before the response
>> is committed.  I just don't know how I can accomplish this.
>>     
>
> Ah, ok.  Sorry about that, I guess I need to learn to be a bit more precise in my
> interpretation of the terms.  Still, a "session manager" service would allow you to
> expose a method to flush() in a listener, yes?  Or you want to make this more
> transparent/automatic so you can just redirect to a static error page on any
> exception without having to explicitly flush()?
>
> That still doesn't help for my particular use case though... I need to catch the
> error and still render a response that might need to access lazily-initialized
> properties of Hibernate persisted objects...
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> For additional commands, e-mail: users-help@tapestry.apache.org
>
>   

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


RE: Help with handling exceptions while using Hibernate's open-session-in-view pattern in Tapestry

Posted by Michael Sims <mi...@crye-leike.com>.
Steve Shucker wrote:
> Keep in mind the difference between a flush and a commit in hibernate.
> A flush executes all the queued sql against the database without
> committing the transaction.  Hibernate does this whenever it has
> changes that needed to be sent to the database before a query is run.
> Otherwise, it defers the flush until just before the commit.  Unless
> you're using deferred constraints in oracle, constraint violations and
> other db-related exceptions will be raised during the flush, not the
> commit.
>
> What I'd really like to do is configure something in hivemind that
> would run just before tapestry commits the response.  Then I could
> call session.flush() there to force the exception before the response
> is committed.  I just don't know how I can accomplish this.

Ah, ok.  Sorry about that, I guess I need to learn to be a bit more precise in my
interpretation of the terms.  Still, a "session manager" service would allow you to
expose a method to flush() in a listener, yes?  Or you want to make this more
transparent/automatic so you can just redirect to a static error page on any
exception without having to explicitly flush()?

That still doesn't help for my particular use case though... I need to catch the
error and still render a response that might need to access lazily-initialized
properties of Hibernate persisted objects...


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


Re: Help with handling exceptions while using Hibernate's open-session-in-view pattern in Tapestry

Posted by Steve Shucker <ss...@vmsinfo.com>.
Keep in mind the difference between a flush and a commit in hibernate.  
A flush executes all the queued sql against the database without 
committing the transaction.  Hibernate does this whenever it has changes 
that needed to be sent to the database before a query is run.  
Otherwise, it defers the flush until just before the commit.  Unless 
you're using deferred constraints in oracle, constraint violations and 
other db-related exceptions will be raised during the flush, not the commit.

What I'd really like to do is configure something in hivemind that would 
run just before tapestry commits the response.  Then I could call 
session.flush() there to force the exception before the response is 
committed.  I just don't know how I can accomplish this.

-Steve

Michael Sims wrote:
> Steve Shucker wrote:
>   
>> I just realized I had a bug relating to this yesterday and I could
>> use a little help solving it.  I think the solution is to force the
>> hibernate session to flush before the response is committed, but I'm
>> not sure how/where to inject that call into tapestry.  If I knew
>> where to make tapestry call my code, getting hibernate to flush is
>> easy.
>>     
>
> If I need to commit or rollback the transaction in a listener method (or elsewhere),
> I inject a thread-bound transaction manager service into my pages.  The transaction
> manager has the request-wide session injected into it, and I call methods on the
> manager to commit, rollback, etc.  I got this idea from Tapestry 5's
> tapestry-hibernate project:
>
> http://tinyurl.com/3b3dok
>
> In my implementation, I have split out the ThreadCleanupListener responsibilities
> into another object, but the rest is pretty much the same.
>
> Does this help at all?
>
>   
>> In general, I think we should either use an open session in view or
>> DAO approach, not a hybrid.  The point of open session in view is that
>> developers don't have to worry about transactional contexts,
>> reenlistment and stuff like that.  If you're throwing those gains away
>> with separate request/response or listener/other transactions, you're
>> better off letting DAOs manage transactions and getting the benefits
>> of their narrower scope and cleaner definition of where transactions
>> start
>> and stop.
>>     
>
> The issue with that, in my case anyway, is that I'm using a SqueezeAdaptor to
> transparently squeeze a Hibernate persisted object into class + id, and then
> unsqueeze to the full entity on the next request.  I do this for client persistence
> and direct link parameters, etc., to keep my objects from being serialized into the
> query string.  My SqueezeAdaptor has to have an active session and transaction, and
> this occurs before any listener methods are called.  I could have the
> SqueezeAdaptor, or anything else that needs to use Hibernate, start and finish their
> own transactions via DAO calls, but this would result in a high number of
> transactions per request, so I don't think that would be worth anything.
>
> Worse still, if any of those transactions results in an error, you are supposed to
> close the Session, which detaches all persistent objects and makes it impossible to
> access lazily-initialized properties.
>
>   
>> Even if spring says it's ok to start a new transaction in a session
>> where the previous transaction was rolled back, I think it's a bad
>> idea.  I use open session in view, which is one transaction per
>> session
>> in its entire lifetime.
>>     
>
> Yes, but what about my scenario with the CRUD application?  An administrator tries
> to persist a new user, and there is a primary key violation, but using open session
> in view, you don't know this until the response has already been rendered, and by
> then it's too late to present an error.  So, how do you handle this without
> comitting the transaction early, before the response has been rendered?
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> For additional commands, e-mail: users-help@tapestry.apache.org
>
>   

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


RE: Help with handling exceptions while using Hibernate's open-session-in-view pattern in Tapestry

Posted by Michael Sims <mi...@crye-leike.com>.
Steve Shucker wrote:
> I just realized I had a bug relating to this yesterday and I could
> use a little help solving it.  I think the solution is to force the
> hibernate session to flush before the response is committed, but I'm
> not sure how/where to inject that call into tapestry.  If I knew
> where to make tapestry call my code, getting hibernate to flush is
> easy.

If I need to commit or rollback the transaction in a listener method (or elsewhere),
I inject a thread-bound transaction manager service into my pages.  The transaction
manager has the request-wide session injected into it, and I call methods on the
manager to commit, rollback, etc.  I got this idea from Tapestry 5's
tapestry-hibernate project:

http://tinyurl.com/3b3dok

In my implementation, I have split out the ThreadCleanupListener responsibilities
into another object, but the rest is pretty much the same.

Does this help at all?

> In general, I think we should either use an open session in view or
> DAO approach, not a hybrid.  The point of open session in view is that
> developers don't have to worry about transactional contexts,
> reenlistment and stuff like that.  If you're throwing those gains away
> with separate request/response or listener/other transactions, you're
> better off letting DAOs manage transactions and getting the benefits
> of their narrower scope and cleaner definition of where transactions
> start
> and stop.

The issue with that, in my case anyway, is that I'm using a SqueezeAdaptor to
transparently squeeze a Hibernate persisted object into class + id, and then
unsqueeze to the full entity on the next request.  I do this for client persistence
and direct link parameters, etc., to keep my objects from being serialized into the
query string.  My SqueezeAdaptor has to have an active session and transaction, and
this occurs before any listener methods are called.  I could have the
SqueezeAdaptor, or anything else that needs to use Hibernate, start and finish their
own transactions via DAO calls, but this would result in a high number of
transactions per request, so I don't think that would be worth anything.

Worse still, if any of those transactions results in an error, you are supposed to
close the Session, which detaches all persistent objects and makes it impossible to
access lazily-initialized properties.

> Even if spring says it's ok to start a new transaction in a session
> where the previous transaction was rolled back, I think it's a bad
> idea.  I use open session in view, which is one transaction per
> session
> in its entire lifetime.

Yes, but what about my scenario with the CRUD application?  An administrator tries
to persist a new user, and there is a primary key violation, but using open session
in view, you don't know this until the response has already been rendered, and by
then it's too late to present an error.  So, how do you handle this without
comitting the transaction early, before the response has been rendered?


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


Re: Help with handling exceptions while using Hibernate's open-session-in-view pattern in Tapestry

Posted by Steve Shucker <ss...@vmsinfo.com>.
I just realized I had a bug relating to this yesterday and I could use a 
little help solving it.  I think the solution is to force the hibernate 
session to flush before the response is committed, but I'm not sure 
how/where to inject that call into tapestry.  If I knew where to make 
tapestry call my code, getting hibernate to flush is easy.

I just spent a few minutes this morning trying to explicitly call 
response.sendError, but once the WebRequestServicer has called its 
service method, the response is committed so I get an IllegalStateException.

In general, I think we should either use an open session in view or DAO 
approach, not a hybrid.  The point of open session in view is that 
developers don't have to worry about transactional contexts, 
reenlistment and stuff like that.  If you're throwing those gains away 
with separate request/response or listener/other transactions, you're 
better off letting DAOs manage transactions and getting the benefits of 
their narrower scope and cleaner definition of where transactions start 
and stop.

Even if spring says it's ok to start a new transaction in a session 
where the previous transaction was rolled back, I think it's a bad 
idea.  I use open session in view, which is one transaction per session 
in its entire lifetime.  For daemon processes, a session will go through 
multiple transactions, but the moment something goes wrong, I start with 
a new session.

-Steve

Michael Sims wrote:
> Sorry again for the not 100% Tapestry related question, but I got such helpful
> responses from my last question, and it's clear that there are a lot of people on
> this list that have already solved these issues that I'm running into (and I'm
> getting jack from the Hibernate forums ;) )...
>
> I've implemented the "open session in view" pattern in my Tapestry application in
> the fairly conventional way. I inject a threaded Session via Hivemind using a
> service factory, and the service factory activates a transaction and creates a
> ThreadCleanupListener to commit() the transaction and close the session when the
> thread is done processing the user's request.  So far so good.
>
> What I'm not sure how to do is handle situations where I may need to inform the user
> that their transaction failed.  For example, let's say I have a typical CRUD
> application to create new users for my system, and I want to be able to correctly
> handle the scenario where an administrator attempts to create a new user with a name
> that is already in use (a primary or unique key violation). I can't simply let the
> ThreadCleanupListener handle the commit() in this case; if I do this, and an
> exception is thrown, it is too late to inform the user since the request has already
> been rendered.
>
> The "Open Session in View" page on the Hibernate web site [1] states that a good
> approach is to use two transactions in one Session.  If I took this approach, I
> would attempt to commit the transaction in my listener method, and catch the
> exception thrown from the database, and convert this into a validation error which
> states that the username is already taken.
>
> The problem with this is that the Hibernate documentation is quite clear that if any
> exception occurs, the transaction should be rolled back, and the Session should be
> closed and discarded.  Rolling back is not a problem, but if I close and discard the
> Session, I'm no longer using "open session in view".  I'll have to go to the trouble
> to initialize any lazy collections or proxies that the view might need before I
> attempt the commit, otherwise I'll get a LazyInitializationException.
>
> But I've read one of the Spring guys saying [2] that it's ok to begin a new
> transaction on the same Session that has been rolled back, if you're only using it
> to initialize lazy collections.  This would be nice if it were actually true; it
> would simplify things for me quite a bit.  But I hestitate to rely on that, since
> the Hibernate documentation says otherwise.
>
> Can someone with a bit more experience with give me some advice on how to approach
> this?  Thanks in advance...
>
> [1] http://www.hibernate.org/43.html
> [2] http://forum.springframework.org/showpost.php?p=29579&postcount=6
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> For additional commands, e-mail: users-help@tapestry.apache.org
>
>   

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org