Do any of these problems exist if you get a session bean to do the work for you?

For example, a page to edit the user, using a session bean called OrderService and an entity bean (using Hibernate if you like, as I do) called Order.

When you're building the page...

IOrderServiceLocal orderService = getBusinessServicesLocator ().getOrderServiceLocal();
                Order order = orderService.findOrder(id);
                // order is a detached object.  Put it in the page.
                setOrder(order);

In the listener for the Save button...

                // Get the updated detached object from the page.
                Order order = getOrder();

                try {
IOrderServiceLocal orderService = getBusinessServicesLocator ().getOrderServiceLocal();
                        orderService.changeOrder(order);
                }
                catch (Exception e) {
                        handleBusinessServicesException(e);
                }

No threading issues to worry about. Isn't this simpler than roll- your-own?

HTH,

Geoff
http://files.doublenegative.com.au/jumpstart/

On 16/06/2007, at 8:16 AM, Norman Franke wrote:

I should note that I'm using Tapestry 4.0.x for my application. I'm also pretty new to both Hibernate and Tapestry, so this may not be the best. It does, however, seem to work well.

My application only uses detached objects that it persists in the client page for change detection (to determine if the record they were editing changed while they were editing, which I flag as an error.) Otherwise, I just re-query as needed for each page. I have a single session per page, so if it queries multiple times (say once during rewind and once not in rewind), the Hibernate session cache prevents excessive queries to the database.

I use HiveMind to inject DAOs for each class, and a SessionManager object (of my own design) as needed by each page. The session manager uses a threaded model in HiveMind, so I can get a call back when the page is done being rendered (implementing org.apache.hivemind.Discardable.) The first call to getSession() creates a HIbernate session, which is closed when the page is done rendering. Each DAO gets its session via HiveMind, so I don't have to worry about that either. Each page can inject as many DAOs as needed, and they all end up in the same Hibernate session.

I have a "setShouldRollback" function to flag the page's session to be rolled back when it finishes, to ensure we don't create two Hibernate sessions for a single page. If I want to rollback a page, I want it all to be rolled back.

To persist a detached object, I call a clone() function on all of my DB objects that converts it back to a normal POJO (from whatever Hibernate does to it.) I could, I assume, persist this clone in the session via Tapestry as well. One could then re-attach the object to Hibernate during the next page render. In my case, my DAO has an "assertUnchanged" method that throws an exception if the two objects differ, e.g. my detached object and the one read from the database. In this case, I tell the user that someone else changed their record and their changes have been lost.

The only glitches I noticed is when saving a record (i.e. not rolling back) from a listener and returning another page (i.e. a direct service.) I don't want them to be in the same session, since cached data from the page with the listener gets stuck on the next page. It also caused problems when a validator flagged errors. To get around these problems, if the validator has errors, I clear the session and flag a rollback. In the other case, the listener explicitly closes the transaction if everything went well. The next page (as a direct service) opens a new session like I want.

This approach uses no locks or mutexes. It allows multiple pages to render simultaneously, each in a different Hibernate session to keep things consistent.

-Norman

On Jun 15, 2007, at 5:14 PM, Michael Sims wrote:

I know this isn't strictly Tapestry related, but since there has been a lot of discussion here over the years related to integrating Hibernate with Tapestry, I was hoping I could draw on the community knowledge about this topic and get a little advice. My apologies if this has been discussed before, I did extensive searching
before posting but still might have missed something.

My specific dilemma at the moment is how to implement session-per- request with detached objects in a thread-safe manner. Chapter 8 of the _Hibernate in Action_ book discusses the issues of detached objects and thread safety. It gives the example of a user submitting a form twice, and I can think of several other scenarios which would cause two or more threads to access the HttpSession simultaneously. The book suggests a few solutions to this problem: rejecting additional requests if one is currently processing, serializing all requests from the same user by synchronizing on the HttpSession in a servlet filter, and finally maintaining a map of session information to separate windows in a multi-window
application.

None of these solutions seem to be workable in my situation. We are making extensive use of assets for all of our images and CSS files, so there really is no static content in our application; every request is going to be serviced by the servlet. The first two solutions aren't practical as even loading my application's login page will open at least 4 concurrent requests (two CSS files, several images, the HTML document, etc.) and if these requests are serialized I am of the opinion that this will noticeably impact perceived performance of the application and will impact scalability in the long run. The final solution (mapping between windows) doesn't solve the issue of users opening multiple tabs or windows as each window
will have the same name/identifier.

So, I'm struggling to come up with a solution to this that doesn't require me to abandon detached objects. I have an idea for a solution, but it seems cumbersome
and I was hoping to get some suggestions or feedback on this.

My idea is to explicitly synchronize only the sections of the code in my request action handlers that have to work with the potentially shared detached objects. My plan is to synchronize either on a mutex object, or one of the detached objects, and within the synchronized block update() the detached object, perform my model manipulations, commit the transaction, close the session, then end the lock. It would still be possible for more than one thread to share a given detached object, but this would prevent my code from attempting to attach the object (s) to more than
one session simultaneously.

(As an aside, I looked at the Tapernate code, since it includes persistence strategies that use Hibernate detached objects. However, unless I'm missing something, it doesn't seem to be taking thread safety of detached objects into
account at all, which I find curious.)

Can someone with a little more experience with this sort of thing give me some advice on this? Does my approach above sound workable, or is there something better that some of you are already doing? Should I just forget about detached objects and squeeze/unsqueeze my entities down to identifers and retrieve them anew on each
request?  Any help or advice would be greatly appreciated...


---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]




---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]


Reply via email to