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 NickWestgate:
http://wiki.apache.org/tapestry/Tapestry4Spring

------------------------------------------------------------------------------
  = Combining Tapestry 4 and Spring =
  
- How can you reference Spring beans from Tapestry 4? In earlier versions of 
Tapestry, the most common method was to extend the BaseEngine class. However, 
in Tapestry 4 the BaseEngine class is deprecated, and we now need to extend 
SpringBeanFactoryHolder.
+ How can you reference Spring beans from Tapestry 4? In earlier versions of 
Tapestry, the most common method was to extend the BaseEngine class. However, 
in Tapestry 4 the BaseEngine class is deprecated, and we now need to use or 
extend SpringBeanFactoryHolder.
+ 
+ In the following varying methods are described of setting up Spring support 
in Tapestry.
  
  (''Basic knowledge of Java, Tapestry, and Spring assumed.'')
  
  == Step 1: Hivemind Configuration ==
  
  Note: You can skip this step by downloading tapestry-spring.jar from 
http://sourceforge.net/projects/diaphragma and placing it on your classpath.
+ 
+ If you already take care of Spring elsewhere, you can avoid implementing your 
own SpringBeanFactoryHolder implementation class, just add an entry in your 
hivemodule.xml:
+ {{{
+ <implementation service-id="hivemind.lib.DefaultSpringBeanFactoryHolder">
+   <invoke-factory>
+     <construct autowire-services="false" 
class="engine.PersonalSpringBeanFactoryHolder">
+       <event-listener service-id="hivemind.ShutdownCoordinator" />
+       <set-object property="context" 
value="service:tapestry.globals.WebContext" />
+     </construct>
+   </invoke-factory>
+ </implementation>
+ }}}
+ 
  
  Continue reading, if you're interested in how it works...
  
@@ -196, +211 @@

  
  NandaFirdausi: I've seen your implementation, and I like it too, just like 
your other code ;). I thing your implementation doesn't need spring listener 
anymore, am I right? If so, then the choice to the user is if they do have 
another spring wep application with nothing to do with tapestry, it's better to 
set the spring listener and do like this page says. If your web application is 
all tapestry based (with spring as back-end support), then your code looks 
cleaner for me ;) 
  
+ 
+ == Tapestry 4 (another solution) ==
+ 
+ JarekWoloszyn: Here is another solution for Tapestry4.
+ 
+ We need a helper class which will create WebApplicationContext for the 
ServletContext. Hivemind can't call factory methods (from 
WebApplicationContextUtils), so we create a POJO. Spring Context is re-created 
everytime we change ServletContext.
+ {{{
+ package org.your.application;
+ 
+ import javax.servlet.ServletContext;
+ 
+ import org.springframework.web.context.WebApplicationContext;
+ import org.springframework.web.context.support.WebApplicationContextUtils;
+ 
+ 
+ public class SpringContextFactory {
+     private ServletContext servletContext;
+     private WebApplicationContext appContext;
+     
+     public WebApplicationContext getAppContext() {
+         return appContext;
+     }    
+     
+     public ServletContext getServletContext() {
+         return servletContext;
+     }
+ 
+     public void setServletContext(ServletContext servletContext) {
+         this.servletContext = servletContext;
+         appContext = 
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
+     }     
+ }
+ }}}
+ 
+ Tapestry 4 has Spring integration out of the box. We must only say which 
BeanFactory should be used.
+ In hivemind.xml, we define a service-point for our helper class. This class 
takes ServletContext as parameter. 
+ We configure then Hivemind to use appContext member as spring-bean factory.
+ {{{
+ <?xml version="1.0"?>
+ <module id="app" version="1.0.0" package="org.your.application">
+   
+   <contribution configuration-id="hivemind.ApplicationDefaults">
+     <default symbol="hivemind.lib.spring-bean-factory" 
value="service-property:app.SpringContextFactory:appContext"/>
+   </contribution>
+   
+     <service-point id="SpringContextFactory">        
+         Create WebApplicatonContext for Spring
+         <invoke-factory>
+             <construct class="SpringContextFactory">
+                 <set-service property="servletContext" 
service-id="tapestry.globals.ServletContext"/>
+             </construct>
+         </invoke-factory>        
+         
+     </service-point>
+     
+ </module>
+ }}}
+ 
+ And that's all. Now you can use spring: prefix to access Spring beans:
+ {{{
+     @InjectObject("spring:DAOFactory")
+     public abstract DAOFactory getDao();
+ }}}
+ 
+ == Injecting Spring Beans ==
+ 
+ You may inject beans managed by Spring into pages and components just like 
you inject anything else as described by 
[http://tapestry.apache.org/tapestry4/UsersGuide/injection.html]. You can 
describe the injection in the .page/.jwc file or using an @InjectObject 
annotation. Just use the 'spring:' prefix like:
+ {{{
+ @InjectObject("spring:name.from.applicationContext.xml")
+ }}}
+ 
+ You may also wire Spring managed beans in HiveMind services such as IEngine 
services.
+ {{{
+ <service-point id="MyService" 
interface="org.apache.tapestry.engine.IEngineService">
+   <invoke-factory>
+     <construct class="engine.MyService">
+     <set-object property="springBean" value="spring:name.of.spring.bean"/>
+     </construct>
+   </invoke-factory>
+ </service-point>
+ }}}
+ 
+ 
+ == Spring, Tapestry and Hibernate ==
+ 
+ In order to use lazy loading and for most Spring Hibernate templates, you 
need access to a Hibernate Session. The traditionnal Spring solution is to use 
the "OpenSessionInView" pattern where a Hibernate session is open for the whole 
request.
+ However, OpenSessionInView has to be configured in the web.xml which is not 
very friendly when you setup some particular Tapestry URLs.
+ 
+ A better solution is to integrate the session opening/closing in Hivemind by 
using the WebRequestServicerFilter interface. Also, for Tapestry assets, it is 
not necessary to create a session. This code is based on the Spring 
OpenSessionInViewFilter.
+ 
+ This requires to implement a class and wire it into Tapestry.
+ Here is the code for the class:
+ 
+ {{{
+ package actualis.web.tapestry.framework;
+ 
+ import java.io.IOException;
+ 
+ import org.apache.commons.logging.Log;
+ import org.apache.commons.logging.LogFactory;
+ import org.apache.hivemind.lib.SpringBeanFactoryHolder;
+ import org.apache.tapestry.Tapestry;
+ import org.apache.tapestry.services.ServiceConstants;
+ import org.apache.tapestry.services.WebRequestServicer;
+ import org.apache.tapestry.services.WebRequestServicerFilter;
+ import org.apache.tapestry.web.WebRequest;
+ import org.apache.tapestry.web.WebResponse;
+ import org.hibernate.FlushMode;
+ import org.hibernate.Session;
+ import org.hibernate.SessionFactory;
+ import org.springframework.dao.DataAccessResourceFailureException;
+ import org.springframework.orm.hibernate3.SessionFactoryUtils;
+ import org.springframework.orm.hibernate3.SessionHolder;
+ import 
org.springframework.transaction.support.TransactionSynchronizationManager;
+ 
+ public class HibernateRequestFilter implements WebRequestServicerFilter {
+ 
+   private static Log logger = LogFactory.getLog(HibernateRequestFilter.class);
+ 
+   public static final String DEFAULT_SESSION_FACTORY_BEAN_NAME = 
"sessionFactory";
+ 
+   private String sessionFactoryBeanName = DEFAULT_SESSION_FACTORY_BEAN_NAME;
+ 
+   private SpringBeanFactoryHolder _beanFactoryHolder;
+ 
+   /**
+    * Set the bean name of the SessionFactory to fetch from Spring's root
+    * application context. Default is "sessionFactory".
+    * 
+    * @see #DEFAULT_SESSION_FACTORY_BEAN_NAME
+    */
+   public void setSessionFactoryBeanName(String sessionFactoryBeanName) {
+     this.sessionFactoryBeanName = sessionFactoryBeanName;
+   }
+ 
+   /**
+    * Return the bean name of the SessionFactory to fetch from Spring's root
+    * application context.
+    */
+   protected String getSessionFactoryBeanName() {
+     return sessionFactoryBeanName;
+   }
+ 
+   public void service(WebRequest request, WebResponse response,
+       WebRequestServicer servicer) throws IOException {
+     String svcValue = request.getParameterValue(ServiceConstants.SERVICE);
+     if (Tapestry.ASSET_SERVICE.equals(svcValue)) {
+       servicer.service(request, response);
+       return;
+     }
+     logger.debug("entering into Hibernate Request Filter " + " service:" + 
svcValue
+         + " context:" + request.getContextPath() + " activation:"
+         + request.getActivationPath() + " path:" + request.getPathInfo());
+     SessionFactory sessionFactory = lookupSessionFactory(request);
+     Session session = null;
+ 
+     // single session mode
+ 
+     logger.debug("Opening single Hibernate Session in 
OpenSessionInViewFilter");
+     session = getSession(sessionFactory);
+     TransactionSynchronizationManager.bindResource(sessionFactory, new 
SessionHolder(
+         session));
+ 
+     try {
+       servicer.service(request, response);
+     }
+ 
+     finally {
+       // single session mode
+       TransactionSynchronizationManager.unbindResource(sessionFactory);
+       logger.debug("Closing single Hibernate Session in 
OpenSessionInViewFilter");
+       try {
+         closeSession(session, sessionFactory);
+       } catch (RuntimeException ex) {
+         logger.error("Unexpected exception on closing Hibernate Session", ex);
+       }
+     }
+ 
+   }
+ 
+   /** For injection. */
+   public final void setBeanFactoryHolder(SpringBeanFactoryHolder 
beanFactoryHolder) {
+     _beanFactoryHolder = beanFactoryHolder;
+   }
+ 
+   protected SessionFactory lookupSessionFactory(WebRequest request) {
+     if (logger.isDebugEnabled()) {
+       logger.debug("Using SessionFactory '" + getSessionFactoryBeanName()
+           + "' for OpenSessionInViewFilter");
+     }
+     return (SessionFactory) _beanFactoryHolder.getBeanFactory().getBean(
+         getSessionFactoryBeanName(), SessionFactory.class);
+   }
+ 
+   protected Session getSession(SessionFactory sessionFactory)
+       throws DataAccessResourceFailureException {
+     return openSession(sessionFactory);
+   }
+ 
+   protected Session openSession(SessionFactory sessionFactory)
+       throws DataAccessResourceFailureException {
+     Session session = SessionFactoryUtils.getSession(sessionFactory, true);
+     // session.setFlushMode(FlushMode.NEVER);
+     session.setFlushMode(FlushMode.COMMIT);
+     return session;
+   }
+ 
+   protected void closeSession(Session session, SessionFactory sessionFactory) 
{
+     session.close();
+     // SessionFactoryUtils.releaseSession(session, sessionFactory);
+   }
+ 
+ }
+ 
+ }}}
+ 
+ 
+ The wiring into tapestry is the following:
+ {{{
+     <service-point id="HibernateServicerFilter"
+         interface="org.apache.tapestry.services.WebRequestServicerFilter">
+         <invoke-factory>
+             <construct 
class="actualis.web.tapestry.framework.HibernateRequestFilter">
+                                 <set-object property="beanFactoryHolder" 
value="service:hivemind.lib.DefaultSpringBeanFactoryHolder"/>
+           </construct>
+         </invoke-factory>
+     </service-point>
+     
+     <contribution 
configuration-id="tapestry.request.WebRequestServicerPipeline">
+         <filter name="HibernateServicerFilter"
+             object="service:HibernateServicerFilter"/>
+     </contribution>
+ }}}
+ 

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

Reply via email to