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]