Implementing the Hibernate long-session-pattern
Being asked about how to use long hibernate sessions with Hivemind a couple of times on the Tapestry-Users-List - Here is what I did:
Overview
Basically all one needs to accomplish this is
- a persistence service which I called ClientStateStorage. It can be provided with an http session as the underlying storage mechanism for production (via a servlet filter). Otherwise it uses a simple Map for testing.
- a service-model extending AbstractServiceModelImpl which works much like the PooledServiceModel, the differences being firstly, that it comes with a different lifecycle and, secondly that it doesn't store service-implementations in a pool common to all clients but in the aforementioned ClientStateStorage.
Implementation
Here is the hivemodule.xml making the new service-model available to other modules. As well, it provides a very simple schema to configure the Hibernate Session Factory.
<?xml version="1.0"?> <module id="scm.hivemind" version="1.0.0" package="scm.hivemind.statefulservice"> <contribution configuration-id="hivemind.ServiceModels"> <service-model class="StatefulServiceModelFactory" name="stateful"/> </contribution> <service-point id="ClientStateStorage"> <invoke-factory model="pooled"> <construct class="ClientStateStorageImpl" /> </invoke-factory> </service-point> <schema id="HibernateSessionFactory"> <element name="property"> a hibernate property <attribute name="name" required="true"> the property name </attribute> <attribute name="value"> the value ( as in config.hbm.xml without the leading "hibernate.") </attribute> <conversion class="scm.hivemind.hibernate.HibernateProperty"/> </element> <element name="config-xml"> the hibernate config.xml File <attribute name="name" required="true"> the name of the config.xml file </attribute> <conversion class="scm.hivemind.hibernate.HibernateConfigFile"/> </element> </schema> </module>
Java-Code
Here's the Java Code:
Client-State-Store
service-model stuff
the hibernate session-factory
Usage
The following snippet from an applications hivemodule.xml shows how to configure long hibernate Session which then can be injected into the app-specific services.
<service-point id="DWKHibernateSession" interface="net.sf.hibernate.Session"> The hibernate-session itself. <invoke-factory service-id="webkit.awk.DWKSessionFactory" model="stateful"/> </service-point> <configuration-point id="DWKSessionFactory" schema-id="scm.hivemind.HibernateSessionFactory"/> <contribution configuration-id="DWKSessionFactory" > <config-xml name="/scm/extranet/domain/hibernate.cfg.xml"/> <property name="dialect" value="net.sf.hibernate.dialect.OracleDialect"/> <property name="cache.provider_class" value="net.sf.ehcache.hibernate.Provider"/> <property name="cache.use_query_cache" value="true"/> </contribution> <service-point id="DWKSessionFactory" interface="org.apache.hivemind.ServiceImplementationFactory"> <invoke-factory model="singleton"> <construct class="scm.hivemind.hibernate.HibernateSessionFactory" initialize-method="init"> <configuration>DWKSessionFactory</configuration> </construct> </invoke-factory> <interceptor service-id="hivemind.LoggingInterceptor"/> </service-point>
In a real web-application you would have to configure the StatefulHivemindFilter for your controller Servlet.
Precautions
- Take care to avoid concurrent requests to your controller servlet (sync on the session or something)
- While the stuff will work on a cluster, it won't support transparent failover of sessions, because the Hivemind-Proxies don't serialize instance state.