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

------------------------------------------------------------------------------
- = Combining Tapestry 4.0, Hivemind 1.1 and Spring =
+ = 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.
- Many people ask how to combine the above solution, I was also curious about 
that and spent one-and-a-half-day to figure out the best way to do that. 
Reasons behind that are:
-   1. Tapestry is a good framework for web UI.
-   2. Spring is a good container framework. Spring is also a good example of 
software project development.
-   3. Hivemind for me, is not mature enough (and proved when I found bug while 
I do this project). Hivemind has good future, but I doubt it'll 100% replace 
Spring. Both of them have their own advantage.
  
- For release version, I like combination of Tapestry+Spring+Hibernate, but 
they are all growing very fast and I really like to try milestone version of 
Tapestry4+Spring+Hibernate30+(Hivemind11).  I'll omit Hibernate in my 
explanation since the hard part is between Tapestry and Spring. Once Spring is 
correctly configured, Hibernate solution is very pluggable.
- 
- Magic reference for Tapestry and Spring combination is in Spring Reference.  
We still can use that solution but we will lost the pretty combination offered 
by new Tapestry+Hivemind. Another disadvantage is the solution extend 
BaseEngine which will deprecated in Tapestry 4.
- 
- ''Basic knowledge of Java, Tapestry, and Spring assumed.''
+ (''Basic knowledge of Java, Tapestry, and Spring assumed.'')
+ 
- == Hivemind Configuration ==
+ == Step 1: Hivemind Configuration ==
- '''You can skip this step''' (Hivemind Configuration) by downloading 
tapestry-spring.jar from http://sourceforge.net/projects/diaphragma and placing 
it on your classpath. Then skip down to Spring Configuration and you should be 
able to reference Spring beans from Tapestry 4. ''Or, keep reading below if 
you're interested in how it works...''
  
- Hivemind is related intimately with Tapestry, even HLS has provide some way 
to easily play with Hivemind in Tapestry. Like Spring, Hivemind is working by 
special XML metadata. Hivemind also has its own metadata, and so Tapestry.  If 
we want to contribute to the whole Hivemind registry, the easiest way is by 
creating hivemodule.xml in your WEB-INF directory. Here is what you need in 
this project:
+ Note: You can skip this step by downloading tapestry-spring.jar from 
http://sourceforge.net/projects/diaphragma and placing it on your classpath.
+ 
+ Continue reading, if you're interested in how it works...
+ 
+ 
+ Tapestry uses Hivemind, behind the scenes, for dependency-injection. 
Hivemind's XML configuration is similar to Spring. The easiest way to 
contribute to the whole Hivemind registry is by creating hivemodule.xml in your 
WEB-INF directory. 
+ 
+ Here is what you need in this project to provide a new implementation of the 
DefaultSpringBeanFactoryHolder:
+ 
  {{{
  <?xml version="1.0"?>
  
- <module id="testing" version="1.0.0">
+ <module id="diaphragma.tapspr" version="1.0.0">
+     <implementation
-       <implementation 
service-id="hivemind.lib.DefaultSpringBeanFactoryHolder">
+         service-id="hivemind.lib.DefaultSpringBeanFactoryHolder">
-               <invoke-factory>
+         <invoke-factory>
-                       <construct autowire-services="false"
+             <construct autowire-services="false"
-                               
class="id.co.nincec.dymension.TestingSpringBeanFactoryHolderImpl">
+                 class="diaphragma.tapspr.XSpringBeanFactoryHolderImpl">
-                                 <event-listener
+                 <event-listener
-                                       
service-id="hivemind.ShutdownCoordinator" />
+                     service-id="hivemind.ShutdownCoordinator" />
-                               <set-object property="context"
+                 <set-object property="context"
-                                       
value="service:tapestry.globals.WebContext" />
+                     value="service:tapestry.globals.WebContext" />
-                       </construct>
+             </construct>
-               </invoke-factory>
+         </invoke-factory>
-       </implementation>
+     </implementation>
- <module>
+ </module>
  }}}
  
- Here, we define a service to override default service in Hivemind. We need to 
override it since we will work in web application only and we doesn't want any 
dependancy with class org.apache.tapestry.engine.BaseEngine (like I say, the 
class will be deprecated in Tapestry3.1)
- 
- Next job is to create TestingSpringBeanFactoryHolderImpl.java. It look like 
this:
+ Next job is to create XSpringBeanFactoryHolderImpl.java. It look like this:
  
  {{{
+ package diaphragma.tapspr;
- /**
-  * 
-  */
- package id.co.nincec.dymension;
  
+ import java.io.PrintStream;
+ import org.apache.hivemind.events.RegistryShutdownListener;
  import org.apache.hivemind.lib.impl.SpringBeanFactoryHolderImpl;
  import org.apache.tapestry.web.WebContext;
  import org.springframework.beans.factory.BeanFactory;
+ import org.springframework.context.ConfigurableApplicationContext;
  
- /**
-  * @author enefem
-  * 
-  */
- public class TestingSpringBeanFactoryHolderImpl extends
-               SpringBeanFactoryHolderImpl implements RegistryShutdownListener 
{
  
+ public class XSpringBeanFactoryHolderImpl extends SpringBeanFactoryHolderImpl
+     implements RegistryShutdownListener
+ {
-       private WebContext context;
+     private WebContext context;
  
+     public XSpringBeanFactoryHolderImpl()
+     {
+     }
+ 
-       public void setContext(WebContext context) {
+     public void setContext(WebContext webcontext)
-               this.context = context;
-       }
+     {
+         context = webcontext;
+     }
  
-       public WebContext getContext() {
+     public WebContext getContext()
+     {
-               return context;
+         return context;
-       }
+     }
  
-       public BeanFactory getBeanFactory() {
+     public BeanFactory getBeanFactory()
+     {
-               if (super.getBeanFactory() == null) {
+         if(super.getBeanFactory() == null)
+             
super.setBeanFactory(XWebApplicationContextUtils.getWebApplicationContext(getContext()));
-                       super.setBeanFactory(TestingWebApplicationContextUtils
-                                       
.getWebApplicationContext(getContext()));
-               }
-               return super.getBeanFactory();
+         return super.getBeanFactory();
-       }
+     }
  
-         public void registryDidShutdown() {
+     public void registryDidShutdown()
+     {
-                ((ConfigurableApplicationContext) 
super.getBeanFactory()).close();
+         ((ConfigurableApplicationContext)super.getBeanFactory()).close();
-         }
+     }
  
  }
  }}}
  
- As we can see, this class is extend default SpringBeanFactoryHolder. The 
important thing is what you see in getBeanFactory() method, there you define 
where our BeanFactory located. In this example, I use 
WebApplicationContextUtils.getRequiredWebApplicationContext() method. There is 
another method which doesn't throw exception 
WebApplicationContextUtils.getWebApplicationContext().
+ As we can see, this class extends the default SpringBeanFactoryHolder. The 
important thing is what you see in getBeanFactory() method, there you define 
where our BeanFactory located. In this example, I use 
WebApplicationContextUtils.getRequiredWebApplicationContext() method. There is 
another method which doesn't throw exception 
WebApplicationContextUtils.getWebApplicationContext().
  
- Next, we implement TestingWebApplicationContextUtils.java
+ Next, we implement XWebApplicationContextUtils.java
  
  {{{
+ package diaphragma.tapspr;
- /**
-  * 
-  */
- package id.co.nincec.dymension;
  
  import org.apache.tapestry.web.WebContext;
  import org.springframework.web.context.WebApplicationContext;
  import org.springframework.web.context.support.WebApplicationContextUtils;
  
+ public class XWebApplicationContextUtils extends WebApplicationContextUtils
+ {
- /**
-  * @author enefem
-  * 
-  */
- public class TestingWebApplicationContextUtils extends
-               WebApplicationContextUtils {
  
+     public XWebApplicationContextUtils()
+     {
+     }
+ 
-       public static WebApplicationContext getWebApplicationContext(WebContext 
wc) {
+     public static WebApplicationContext getWebApplicationContext(WebContext 
webcontext)
-               Object attr = wc
+     {
-                               
.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
+         Object obj = 
webcontext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
+         if(obj == null)
+             return null;
-               if (attr == null) {
-                       return null;
-               }
-               if (attr instanceof RuntimeException) {
+         if(obj instanceof RuntimeException)
+             throw (RuntimeException)obj;
+         if(obj instanceof Error)
+             throw (Error)obj;
-                       throw (RuntimeException) attr;
-               }
-               if (attr instanceof Error) {
-                       throw (Error) attr;
-               }
-               if (!(attr instanceof WebApplicationContext)) {
+         if(!(obj instanceof WebApplicationContext))
+             throw new IllegalStateException((new 
StringBuilder()).append("Root context attribute is not of type 
WebApplicationContext: ").append(obj).toString());
+         else
+             return (WebApplicationContext)obj;
+     }
-                       throw new IllegalStateException(
-                                       "Root context attribute is not of type 
WebApplicationContext: "
-                                                       + attr);
-               }
-               return (WebApplicationContext) attr;
-       }
  
-       public static WebApplicationContext getRequiredWebApplicationContext(
+     public static WebApplicationContext 
getRequiredWebApplicationContext(WebContext webcontext)
-                       WebContext wc) throws IllegalStateException {
-               WebApplicationContext wac = getWebApplicationContext(wc);
-               if (wac == null) {
-                       throw new IllegalStateException(
+         throws IllegalStateException
-                                       "No WebApplicationContext found: no 
ContextLoaderListener registered?");
-               }
-               return wac;
-       }
- 
+     {
+         WebApplicationContext webapplicationcontext = 
getWebApplicationContext(webcontext);
+         if(webapplicationcontext == null)
+             throw new IllegalStateException("No WebApplicationContext found: 
no ContextLoaderListener registered?");
+         else
+             return webapplicationcontext;
+     }
  }
- }}}
  
+ }}}
+ 
- == Spring Configuration ==
+ == Step 2: Spring Configuration ==
  Spring in servlet mode need two things, it needs the XML file for bean 
configuration and also a filter in web.xml. In web.xml, you will have to add 
this:
  {{{
  <context-param>
@@ -148, +143 @@

  </listener>
  }}}
  
- And let we try a simple XML file (name it under 
WEB-INF/applicationContext.xml).
+ And now let us try a simple XML file (place it under WEB-INF/ as 
applicationContext.xml).
  
  {{{
  <?xml version="1.0" encoding="UTF-8"?>
@@ -157, +152 @@

        "http://www.springframework.org/dtd/spring-beans.dtd";>
  
  <beans>
-       <bean id="person" class="id.co.nincec.dymension.page.Person">
+       <bean id="person" class="com.example.model.Person">
        <property name="name">
                <value>Nanda Firdausi</value>
        </property>
@@ -167, +162 @@

  
  It defines one object with one property.
  
- == See it works!! ==
+ == Step 3: Access Spring property from Tapestry page specification ==
  
- Now time to see whether our bean can be accessed from Tapestry page. First, 
let we create the page specification (Home.page).
+ Now time to see whether our bean can be accessed from a Tapestry page. First, 
let us create the page specification (Home.page).
  
  {{{
  <?xml version="1.0" encoding="UTF-8"?>
        
  <!DOCTYPE page-specification PUBLIC
-       "-//Apache Software Foundation//Tapestry Specification 3.1//EN"
+       "-//Apache Software Foundation//Tapestry Specification 4.0//EN"
-       "http://jakarta.apache.org/tapestry/dtd/Tapestry_3_1.dtd";>
+       "http://jakarta.apache.org/tapestry/dtd/Tapestry_4_0.dtd";>
        
  <page-specification class="org.apache.tapestry.html.BasePage">
+       <inject property="person" object="spring:person" />
-       <inject property="inuyasha"
-               object="spring:person" />
  </page-specification>
  }}}
  
- See, how easy to take Spring's bean managed into Tapestry page!! And so 
natural!!
  
  The page template is trivial, one super-simple-example is like this 
(Home.html).
  {{{
- <span jwcid="@Insert" value="ognl:inuyasha" /> 
+ <span jwcid="@Insert" value="ognl:person.name" /> 
  }}}
  
- And we finish!!!
  
- I wait for comments, suggestions, and any other things related to this simple 
tutorial.
+ Please make comments, suggestions, and any other things related to this 
tutorial.
  ----
  ''This information was originally written in an email to the Tapestry User's 
List on March 7, 2005 by Nanda Firdausi''
  
+ 
+ HowardLewisShip: This is pretty much overkill, since you can just acquire 
your AC and store it into the DefaultSpringBeanFactoryHolder service with no 
additional work.  I do like that you have a shutdown option, though.  I'm 
putting together a proper implementation for Tapestry @ JavaForge.
+ 
+ HowardLewisShip: I've put together a basic Spring integration module: 
[http://howardlewisship.com/tapestry-javaforge/tapestry-spring/ 
tapestry-spring]. The solution on this page is a little more flexible, however 
(at least for the moment).
+ 
+ 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();
+ }}}
+ 

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

Reply via email to