Dear Wiki user,

You have subscribed to a wiki page or wiki category on "Tapestry Wiki" for 
change notification.

The following page has been changed by michaelcourcy:
http://wiki.apache.org/tapestry/First_project_with_Tapestry5,_Spring_and_Hibernate

------------------------------------------------------------------------------
  This tutorial is in two parts : a blank application with Spring-Hibernate and 
in the second part we integrate Tapestry 5. With this separation you'll be able 
to reuse the first part with another front framework.
  
  The source of this tutorial could be found  
[ftp://ftp-developpez.com/baptiste-meurant/tutoriaux/tapestry5-spring-hibernate/tuto-Tapestry5-Spring-Hibernate-src.zip
 here] or 
[http://baptiste-meurant.ftp-developpez.com/tutoriaux/tapestry5-spring-hibernate/tuto-Tapestry5-Spring-Hibernate-src.zip
 Http Mirror ]
+ 
  The pdf version of this tutorial is available [ 
http://baptiste-meurant.ftp-developpez.com/tutoriaux/tapestry5-spring-hibernate/tutoriel-tapestry5-spring-hibernate.pdf
 here] 
  
- === Hibernate 3 ===
- Hibernate 3 offers several major improvements over the 2.1. A preliminary 
support for Hibernate 3 and Spring is available at 
http://opensource.atlassian.com/projects/spring/browse/SPR-300
+ === Before you start ===
+ ==== Installation ====
  
+ coming soon ....
- === Using Spring in Tapestry ===
- With Spring, the way to go is to use the "OpenSessionInViewFilter" which 
opens and closes hibernate sessions for you in a transparent way. These lines 
are required in the web.xml to enable the session management:
  
- ==== web.xml excerpt ====
- {{{
-       <filter>
-               <filter-name>hibernateFilter</filter-name>
-               
<filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
-       </filter>
- 
-       <filter-mapping>
-               <filter-name>hibernateFilter</filter-name>
-                 <!-- put here your own path for your Tapestry url-pattern -->
-               <url-pattern>/exec</url-pattern>
-       </filter-mapping>
- 
-       <listener>
-               
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
-       </listener>
- }}}
- 
- For the applicationContext.xml, my file is based on 
https://betterpetshop.dev.java.net/ example:
- ==== applicationContext.xml excerpt ====
- {{{
-       <!-- ========================= GENERAL DEFINITIONS 
========================= -->
- 
-       <bean id="propertyConfigurer" 
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
-               <property 
name="location"><value>classpath:jdbc.properties</value></property>
-       </bean>
- 
-       <!-- Message source for this context, loaded from localized 
"messages_xx" files -->
-       <bean id="messageSource" 
class="org.springframework.context.support.ResourceBundleMessageSource">
-               <property name="basename"><value>messages</value></property>
-       </bean>
- 
- 
-       <!-- ========================= RESOURCE DEFINITIONS 
========================= -->
- 
-       <!-- Local DataSource that works in any environment -->
-       <bean id="dataSource" 
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
-               <property 
name="driverClassName"><value>${jdbc.driverClassName}</value></property>
-               <property name="url"><value>${jdbc.url}</value></property>
-               <property 
name="username"><value>${jdbc.username}</value></property>
-               <property 
name="password"><value>${jdbc.password}</value></property>
-       </bean>
- 
-       <!-- Hibernate SessionFactory -->
-       <bean id="sessionFactory" 
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
-               <property name="dataSource"><ref local="dataSource"/></property>
-               <property name="mappingResources">
-                       <list>
-                                       <!-- Write here your list of Hibernate 
files -->
-                               
<value>hibernate/catalogue/Article.hbm.xml</value>
- 
-                       </list>
-               </property>
-               <property name="hibernateProperties">
-                       <props>
-                               <prop 
key="hibernate.dialect">${hibernate.dialect}</prop>
-                               <prop key="hibernate.show_sql">true</prop>
-                               <prop 
key="hibernate.c3p0.minPoolSize">${hibernate.c3p0.minPoolSize}</prop>
-                               <prop 
key="hibernate.c3p0.maxPoolSize">${hibernate.c3p0.maxPoolSize}</prop>
-                               <prop 
key="hibernate.c3p0.timeout">${hibernate.c3p0.timeout}</prop>
-                               <prop 
key="hibernate.c3p0.max_statement">${hibernate.c3p0.max_statement}</prop>
-                               <prop 
key="hibernate.generate_statistics">true</prop>
-                               <prop 
key="hibernate.cache.use_query_cache">true</prop>
-                       </props>
-               </property>
-       </bean>
- 
-       <!-- Transaction manager for a single Hibernate SessionFactory 
(alternative to JTA) -->
-       <bean id="transactionManager" 
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
-               <property name="sessionFactory"><ref 
local="sessionFactory"/></property>
-       </bean>
- 
- 
- 
-       <!-- ========================= BUSINESS OBJECT DEFINITIONS 
========================= -->
- 
-       <!-- Petclinic primary business object: Hibernate implementation -->
-       <bean id="WebServiceTarget" class="actualis.web.spring.WebManager"
-       singleton="false">
-               <property name="catalogue"><ref 
local="catalogueDAO"/></property>
-               <property name="commande"><ref local="commandeDAO"/></property>
-               <property name="clients"><ref local="clientsDAO"/></property>
-       </bean>
- 
-       <bean id="poolTargetSource"
-               class="org.springframework.aop.target.CommonsPoolTargetSource">
-               <property 
name="targetBeanName"><value>WebServiceTarget</value></property>
-               <property name="maxSize"><value>5</value></property>
-       </bean>
- 
-       <bean id="businessObject"
-               class="org.springframework.aop.framework.ProxyFactoryBean">
-               <property name="targetSource"><ref 
local="poolTargetSource"/></property>
-       </bean>
- 
-       <!-- Transactional proxy for the Petclinic primary business object -->
-       <bean id="WebService" 
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
-               <property name="target"><ref 
local="WebServiceTarget"/></property>
-               <property name="transactionManager"><ref 
local="transactionManager"/></property>
-                       <property name="transactionAttributes">
-                       <props>
-                               <!-- Avoid PROPAGATION_REQUIRED !! It could 
kill your performances by generating a new transaction on each request !! -->
- 
-                               <prop 
key="get*">PROPAGATION_SUPPORTS,readOnly</prop>
-                               <prop 
key="find*">PROPAGATION_REQUIRED,readOnly</prop>
-                               <prop 
key="load*">PROPAGATION_REQUIRED,readOnly</prop>
-                               <prop key="store*">PROPAGATION_REQUIRED</prop>
-                       </props>
-               </property>
-       </bean>
- 
-       <bean id="catalogueDAO" class="actualis.web.dao.CatalogueDAO">
-               <property name="sessionFactory"><ref 
local="sessionFactory"/></property>
-       </bean>
- 
-       <bean id="commandeDAO" class="actualis.web.dao.CommandeDAO">
-               <property name="sessionFactory"><ref 
local="sessionFactory"/></property>
-       </bean>
- 
-       <bean id="clientsDAO" class="actualis.web.dao.ClientsDAO">
-               <property name="sessionFactory"><ref 
local="sessionFactory"/></property>
-       </bean>
- 
-       <!-- ========================= WEB INTERCEPTORS DEFINITIONS 
========================= -->
-       <bean id="urlMapping"
-               
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
-               <property name="interceptors">
-                       <list>
-                               <ref bean="openSessionInViewInterceptor"/>
-                       </list>
-        </property>
-       </bean>
-       <bean name="openSessionInViewInterceptor"
-       
class="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor">
-               <property name="sessionFactory"><ref 
bean="sessionFactory"/></property>
-       </bean>
- }}}
- 
- === Hibernate Lazy mode ===
- The last trick is to get the lazy mode working. From one page to another, you 
are going to lose the session in the hibernate objects referenced, so you'll 
need to reattach those objects to the current session in order to perform 
operations on them.
- 
- One solution:
- 
-  1. Create an ordinary many-to-one Cat to Kittens, lazy=true.
-  1. Load Cat in page ListCats, but don't touch Kittens.
-  1. In page ListCats, instantiate a new Page instance ViewCat.
-  1. Set the Cat property for page ViewCat (ie - viewCat.setCat(cat)).
-  1. Page ViewCat is activated and begins rendering.
-  1. Page ViewCat tries to list this Cat's Kittens, for example in a Foreach 
as in <span jwcid="@Foreach" source="ognl:cat.kittens"
- value="ognl:kitten">.
- 
- Page rendering fails with a LazyInitializationException, even though the
- OpenSessionInViewFilter opened a session, since the Cat instance is not
- attached to the open session.
- 
- I've gotten around this by adding an attach() method to each of my service 
implementations.  This method invokes getSession().lock( object,
- LockMode.NONE) to reassociate the specified object.  I then manually invoke 
attach() to reassociate the detached objects for the given page.
- For example, in ViewCat.pageBeginRender(), I perform a 
getCatService().attach(getCat()).
- 
- For convenience, I've recently created a general-purpose HibernateService, 
which looks like this:
- 
- {{{
- package com.shawn.model.service;
- 
- import org.springframework.orm.hibernate.support.HibernateDaoSupport;
- import org.springframework.dao.DataAccessException;
- import org.apache.log4j.Logger;
- import org.apache.log4j.LogManager;
- import net.sf.hibernate.LockMode;
- import net.sf.hibernate.HibernateException;
- 
- /**
-  * @author Shawn M Church
-  * @version HibernateServiceImpl, Feb 28, 2005, 4:51:48 PM
-  */
- public class HibernateServiceImpl extends HibernateDaoSupport implements 
HibernateService
- {
-    private final static transient Logger _log = 
LogManager.getLogger(HibernateServiceImpl.class);
- 
-    /**
-     * Reattach the specified object to the open Hibernate session
-     *
-     * @param object
-     * @throws org.springframework.dao.DataAccessException
-     */
-    public void attach( Object object) throws DataAccessException
-    {
-       try
-       {
-          getSession().lock( object, LockMode.NONE);
-       }
-       catch (HibernateException e)
-       {
-          _log.error(e);
-       }
-    }
- }
- }}}
- 
- This is similar to my earlier solution, but it avoids the redundant attach() 
method having to exist in each DAO service implementation.  So now, I can do 
this in my Tapestry page (usually in PageBeginRender()):
- 
- getHibernateService().attach(getCat());
- 
- ==== With DataSqueezer ====
- Another solution consists in tweaking the Richard Hensley's DataSqueezer 
trick:
- http://thread.gmane.org/gmane.comp.java.tapestry.user/15398
- 
- He creates a custom DataSqueezer that tapestry will invoke automatically.
- Using this technique, a data object is squeezed into a short form (its
- id and classname) when tapestry builds a link or a hidden form field.
- When that url or form field comes back in a later request or form
- submission, tapestry invokes the datasqueezer to unsqueeze it.  The
- unsqueeze operation re loads the dataobject from the database (or cache)
- and hence it is in the current session.
- 
- There is also a wiki article on the data squeezer:
- http://wiki.apache.org/jakarta-tapestry/DataSqueezer
- 
- Here is my DataQueezer adaptor based on the Wiki article.
- 
- {{{
-   public DataSqueezer createDataSqueezer() {
- 
-     ISqueezeAdaptor keySqueezer = new ISqueezeAdaptor() {
- 
-       private static final String PREFIX = "k";
- 
-       private static final String SEPARATOR = ";";
- 
-       private ApplicationContext appContext = null;
- 
-       private DataOperations manager = null;
- 
-       /**
-        * @return the current hibernate session
-        */
-       private DataOperations getDataOperations() {
-         if (manager != null) {
-           return manager;
-         }
- 
-         if (appContext == null) {
-           Map global = (Map) getGlobal();
-           appContext = (ApplicationContext) 
global.get(APPLICATION_CONTEXT_KEY);
-         } 
-         
-         if (appContext != null) {
-           manager = (DataOperations) appContext
-               .getBean("DataOperations");
-         }
-         return manager;
- 
-       }
- 
-       public void register(DataSqueezer squeezer) {
-         squeezer.register(PREFIX, EnterpriseObject.class, this);
-       }
- 
-       public String squeeze(DataSqueezer squeezer, Object data)
-           throws IOException {
-         StringBuffer sb = new StringBuffer();
-         sb.append(PREFIX);
-         sb.append(data.getClass().getName());
-         sb.append(SEPARATOR);
-         Serializable id = getDataOperations().getIdentifier(data);
-         sb.append(squeezer.squeeze(id));
-         return sb.toString();
-       }
- 
-       public Object unsqueeze(DataSqueezer squeezer, String string)
-           throws IOException {
-         int pos_sep = string.indexOf(SEPARATOR);
-         String classname = string.substring(1, pos_sep);
-         String index = string.substring(pos_sep + 1);
-         Serializable id = (Serializable) squeezer.unsqueeze(index);
-         try {
-           return getDataOperations().load(classname, id);
-         } catch (ClassNotFoundException e) {
-           throw new IOException("Invalid class:" + classname);
-         }
-       }
-     };
-     ISqueezeAdaptor[] adapt = { keySqueezer };
-     return new DataSqueezer(getResourceResolver(), adapt);
-   }
- }}}
- 
- The load is straightforward but I've ran into some troubles on generating the 
identifiers: on my pages I reference objects and some of them might have been 
loaded in the previous session! And there is the trick:
- {{{
-   public Serializable getIdentifier(final Object data) {
-     return (Serializable) getHibernateTemplate().execute(
-         new HibernateCallback() {
-           public Object doInHibernate(Session session)
-               throws HibernateException {
-             //s_logger.debug("session=" + session.hashCode() + " 
getIdentifier:" + data.toString());
-             try {
-               return session.getIdentifier(data);
-             } catch (HibernateException hex) {
-               // ok then the entity was loaded with a different session
-               // it is too risky to try to attach it, it may already be loaded
-               Object copy = session.merge(data);
-               return session.getIdentifier(copy);
-             }
-           }
-         });
-   }
- }}}
- ==== Spring Beans in Tapestry Pages ====
- The Spring reference guide describes a convenient way to use Spring beans in 
Tapestry pages.  Here's the link:
- 
http://www.springframework.org/docs/reference/webintegration.html#view-tapestry-appctx
- 
- The code below is taken almost directly from the Spring reference, but I will 
include it here to provide relevant support for the above example.
- 
- In the HibernateService example, the .java page controller code includes an 
abstract accessor method which Tapestry enhances to provide access to the 
corresponding .page file property.  For example, the .java code would contain 
this line:
- 
- {{{
-    public abstract HibernateService getHibernateService();
- }}}
- 
- In the .page file, this code would be used to get the named Spring bean:
- 
- {{{
-    <property-specification name="hibernateService" 
type="com.shawn.model.service.HibernateService">
-       global.springContext.getBean("hibernateService")
-    </property-specification>
- }}}
- 
- And the Spring applicationContext.xml would contain this bean declaration:
- 
- {{{
-    <bean id="hibernateService" 
class="com.shawn.model.service.HibernateServiceImpl">
-       <property name="sessionFactory">
-          <ref local="sessionFactory"/>
-       </property>
-    </bean>
- }}}
- 
- This implementation has worked well to integrate Tapestry, Hibernate, and 
Spring, and it provides a reasonably clean separation between the presentation 
and persistence layers.  The Tapestry-based page code is not aware of 
Hibernate, and switching persistence layers in the future would involve 
changing only configuration files.  More importantly, Hibernate lazy loading 
can be used without too much difficulty, and it has so far worked reliably and 
without any surprises.
- 

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

Reply via email to