Hi Fabrizio,
I wrote most of the tutorial you cite two years ago, but from the
discussions on the list got the impression that most people switched to
the CHS (Cocoon, Hibernate, Swing). Thus it is interesting to see that
someone is actually still using this technique. I do it still, as well,
since it "works for me" for medium-sized projects. So let me comment on
the issues you bring up:
However, for more complex scenarios which involve displaying a sequence of
forms to the user, this 'session-per-request' approach is cumbersome - as
whenever the Flowscript continuation is suspended/resumed, you have to
manually re-associate any detached objects to the new Hibernate session...
This is true, and sometimes unconvenient, e.g. when you have a complex
form spanning multiple pages.
So I've taken a closer look on the long session / conversation approach
described by the Hibernate authors - although it is generally considered
an anti-pattern by most web frameworks, due to its wasteful memory
requirements and potential garbage collection issues.
This is not the only problem really, but I go into this in more detail
below.
Correct me if I'm wrong, but all the objects which I fetch before a
continuation is suspended (and which I don't explicitly care to dispose
of!) just stay there, hogging memory ...until the user decides to resume
the continuation or until the continuation times out, right?
Exactly.
But is my reasoning above, that a 'Flowscript continuation is indeed a
long session', correct, or did I overlook something obvious?
This is precisely what flowscript continuations are doing. However,
there is a tricky philosophical issue here. A Flowscript connection
holds exactly the information that is necessary to continue program
execution at the point it was interrupted by e.g.
cocoon.sendPageAndWait(). This usually boils down to local and global
variables. In fact, if you have a global variable in your flowscript,
Cocoon will automatically create an HTTP session to store it in, even if
its value is never accessed or modified. Otherwise, an HTTP session will
only be created when you call sendPageAndWait() or something similar.
Of course, the global variables you are storing can also be "real" Java
objects instead of trivial javascript variables containing just integers
and strings. I used this, for example, in an online shop application
where the shopping basket is a java.util.Vector containing objects which
were initially fetched by Hibernate. This is when I first ran into the
problem you described: After the first continuation, Hibernate would
complain about accessing an object whose session had been closed. I
actually solved this problem by copying the fetched objects to
non-persistent instances.
In theory, it is of course also possible to store the Hibernate session
itself in the HTTP session, or as a global variable in the flowscript.
However, there are several reasons why I think this is a bad idea:
(1) Connection pooling. In my setup - which is also described in the
wiki - Hibernate uses pooled connections. If a lot of sessions are
opened and not closed properly, or by a timeout, I am not sure whether
the underlying JDBC connection would be properly closed and returned to
the pool. In any case, you will run out of connections faster than when
returning each JDBC connection to the pool when the view was rendered.
Actually, it is a classical and frustrating problem to run out of JDBC
connections, and it is one of the main strengths of the
OpenSessionInView design patterns that it gets rid of this issue.
(2) I think that it is against the philosophy of flowscript
continuations to store objects which have side non-obvious side effects,
such as keeping a JDBC connection open or needing an open Hibernate
session to call the setter methods, across sessions.
(3) Most "write" operations should be wrapped in a JTA transaction to
make sure that they are actually executed. Since these transactions are
atomary, this might block other JTA transactions for a much too long
time (although I am not 100% sure on this one)
(4) Architecture. I never felt good about using Hibernate directly in
flowscript anyway, since it is supposed to be on the "M" (model) layer
of the MVC pattern, while flowscript is IMHO on the C (control) layer.
With the current setup in wiki, sessions are opened in flowscript, but
closed in Java, which is ugly. I think that the way to go is the
classical "DAO" (data access object) pattern, which should wrap calls to
Hibernate - which brings you closer to what Spring is supposed to do,
but of course you can implement DAO yourself without using Spring, which
is what I do. In this setup, Hibernate sessions are openened and closed
as needed in the Data Access Objects. In flowscript, you only interact
with the data access objects. This makes it necessary to provide
Hibernate with a different connection pool than Cocoon's, but that makes
perfect sense to me since it decouples cocoon from all the database and
hibernate stuff, thus leading to a "clean" MVC structure (apart from the
OpenSessionInView filter, but this is a standard issue).
I hope to have enough time to document this setup in wiki soon, since I
like it much more than the described one. However, I would also be glad
to hear more from your experiences with the open session across
continuations - it is certainly (to me) one of the more interesting
aspects of Java web development that you have a variety of philosophies
and approaches.
Apologies for the lengthy reply and best regards,
Johannes
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]