Hi Fabrizio,
it seems that you alread have a very elaborate solution. I do not
understand some points completely yet, so let me ask some further
questions:
I tend to be more pragmatic, rather than philosophical ;-)
Therefore I ran various stress-tests using the 'ab' tool ('apache
benchmark', included in the httpd distribution), in which several
thousand requests (with configurable concurrency levels) are launched
against a Cocoon/Hibernate webapp.
During simulations of denial-of-service attacks it proved to be robust
(slowdowns during high loads, but no hangs) and its memory requirements
were stable (no memory leaks!)
Your 'HibernateFilter' never missed a Hibernate session - the JDBC
connections were always properly returned to the pool (I could
observe live which ones were being used using the Oracle 'TopSessions'
tool)
As a side-effect I found out that a Cocoon pool of only 8 JDBC
connections, was able to handle any reasonable load occuring in
our organization (ca. 1500 users) but that's another story...
I am aware of ab and use it alot myself, but just for "one-shot" testing
(massive requests on one, or more, single URLs, but each request being
isolated without sessions), For testing the "long sessions", wouldn't
you need to craft HTTP requests that open and maintain sessions, span
multiple pages etc.? (think 100 peope working with the form at the same
time)
For the long-session approach, I've modified the HibernateFilter so that
it will always disconnect the underlying JDBC connection from the
Hibernate session, thus returning it to Cocoon's connection pool, but
the Hibernate session is left open (except when a 'end-of-conversation'
flag is being set)
OK. But how do you provide Hibernate with a new connection the next time
you need one?
The Hibernate session is just an additional object that is being stored
as a local variable, along with the other objects in the continuation.
The only side-effect that comes to mind when keeping open (but
disconnected) Hibernate Sessions around, is that they won't be
automatically cleaned up when the continuation expires (I found that
out using SessionFactory.getStatistics())
That makes sense, since a Hibernate Session is not a "regular" JS
object. When cocoon (or rhino) disposes the continuation, it will
probably just set the pointer to the session to null, not derigistering
it from the SessionFactory which would require calling close() on the
session.
I've never delved into the Java Transaction API ...I probably will when
I stumble upon a distributed transaction issue :-/
Hmm I do think you have used this. I'm referring to something like
openHibernateSession( ); // stores session in global var hs
var tx = hs.openTransaction(); // this is atomary
form2medium(form,medium); // store CForms user input into medium
hs.save( medium );
tx.commit(); // close transaction, ensuring that changes are written to DB
Depending on your setup, openTransaction() could mean JTA or JDBC
transactions.
I've somewhat limited the impact of this Flowscript/Hibernate code mix
by encapsulating the Hibernate session setup in a generic dispatch method
(invoked by the sitemap) and by using transaction defaults which apply
to most (over 90%) cases.
Thus, the only flowscript methods where you will see explicit transaction
demarcation statements are those dealing with CForms.
Does that mean your dispatch method always calls "openTransaction()"?
Maybe you could paste this method and some other related code here?
Opening and closing sessions in DAOs?
Hmm, here I have to agree with some philosophers out there that do not
quite agree (see http://www.hibernate.org/328.html)
The bit that troubles me is that you lose transaction atomicity when
changes to multiple DAOs have to be performed in the same transaction...
No, I've just moved the task of "ensure that session is open" to the DAO
level. Transactions are demarked in the DAOs as needed. I'll paste some
example code below which I hope explains it better than my words could,
would be nice to hear your comments.
Regards,
Johannes
public class DAO {
public boolean assertSession(){
return User.getHibernateSession() == null
&& User.getHibernateSession().isOpen();
// "User" is the glue between cocoon and DAO level, see
below
}
public Session session(){
return User.getHibernateSession();
}
}
public class IconsDAO extends DAO {
public Icon getIcon(int id) {
if (!assertSession())
return null; // could throw an exception here, or print some
warning
try {
return (Icon) session().load(Icon.class, new Long(id));
} catch (HibernateException e) {
e.printStackTrace();
return null;
}
}
public List alleIcons() {
if( !assertSession() ) return null;
try {
return session().createQuery("from Icon i order by id
asc").list();
} catch (HibernateException e) {
e.printStackTrace();
return null;
}
}
}
public class User {
/* This object is local only to the current thread. Since a new
thread is opened
for each request, this allows passing the HibernateSession from
flowscript
(where it is opened) to java (where it is used). It would still
be better to create
the session in the Java layer in the first place. Only reason I'm
not doing this yet
is that I still use the cocoon connection pooling. */
private static InheritableThreadLocal scope = new
InheritableThreadLocal() {
protected Object initialValue() {
return null;
}
};
/* This is called in the servlet filter, see below. */
public static void init(){
scope.set( new HashMap() );
}
public static Session getHibernateSession(){
return (Session) scope().get("hibernateSession");
}
public static void setHibernateSession(Session hs){
scope().put("hibernateSession",hs);
}
/* Null-Safe getter for scope.
*
*/
private static HashMap scope(){
if( (HashMap) scope.get() == null )
scope.set( new HashMap() );
return (HashMap) scope.get();
}
}
/** servlet filter: getters / setters */
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException,
ServletException {
// Create request-local scope in User Object
User.init();
// Pass the request on to cocoon
chain.doFilter(request, response);
// After cocoon has finished processing, close the
// corresponding Hibernate session if it has been opened
if( User.getHibernateSession() != null )
{
Session hs = User.getHibernateSession();
try{
hs.connection().close();
hs.close();
//System.out.println("Session closed.");
}
catch( HibernateException e ){
e.printStackTrace();
}
catch( SQLException e ){
e.printStackTrace();
}
User.setHibernateSession(null);
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]