ZK - Open Source Ajax Java FrameworkZK - Open Source Ajax Java Framework

Using Spring IOC with ZK

newguy2010
2 Sep 2010 09:08:15 GMT
2 Sep 2010 09:08:15 GMT

I've read some tutorials (small talks) on how to use Spring Inversion of Control mechanism with ZK. However after a couple of days of trying I still can't get it work.

In my maven project webapp folder I have spring-config.xml, web.xml and zk.xml.
In spring-config.xml I specified the bean name, such as:

<bean id="example1" scope="session" class="example.com.ExampleService"></bean>
<bean id="someController" scope="prototype" class="example.com.ControllerClass">
   <constructor-arg ref="example1"/>
</bean>



In the web.xml file
<context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>classpath: spring-*.xml</param-value>
</context-param>


I've put ContextLoaderListener and RequestContextListener in web.xml file.

In index.zul,
<?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver"?>
<window id="window" apply="${someController}">
 <button id="test" />
</window>


In my controller class
I have event methods that correspond to the button.The class extends GenericForwardComposer.
ExampleService is a private field of the controller class, as well as the buttons.
The constructor of the controller class has a parameter ExampleService with the name example1.
I was expecting when I click test it should do something but it doesn't, seems the button is not getting the event. What's wrong with my configuration?

If I don't use Spring it works OK. The event fires correctly. But when I use Spring looks like spring beans and the components inside the page are messed together. Any suggestions to make them work together? Thank you.

vergereau
3 Sep 2010 04:32:47 GMT
3 Sep 2010 04:32:47 GMT

Hello NewGuy,
:)

Have you add listner for spring in the web.xml ?


Web.xml :

...
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/spring-config.xml</param-value>
  </context-param>

  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

  <listener>
    <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
  </listener>
...


Regards, V

newguy2010
3 Sep 2010 05:50:48 GMT
3 Sep 2010 05:50:48 GMT

Yes I've put that on.

terrytornadoTop Contributor
3 Sep 2010 08:14:18 GMT
3 Sep 2010 08:14:18 GMT

Try to do it without constructor args


public class ControllerClass.java {


private Button btn;
private ExampleService sample1; // + getter/setter

. . .
}


	<bean id="articleMainCtrl" class="de.forsthaus.webui.article.ArticleMainCtrl" scope="prototype">
		<property name="articleService" ref="articleService" />
	</bean>


	<bean name="articleService" 	class="de.forsthaus.soolaar.backend.service.impl.ArticleServiceImpl">
		<property name="articleDAO" ref="articleDAO" />
	</bean>

	<!-- Articles / Artikelstamm -->
	<bean id="articleDAO" class="de.forsthaus.soolaar.backend.dao.impl.ArticleDAOImpl" />

vergereau
3 Sep 2010 09:20:58 GMT
3 Sep 2010 09:20:58 GMT

Plop,

It's seems to me for session scope you should add one more line in zk.xml if you have not done it.

<listener>
		<description>ThreadLocal varaibles synchronizer</description>
		<listener-class>org.zkoss.zkplus.util.ThreadLocalListener</listener-class>
	</listener>

	<preference>
		<name>ThreadLocal</name>
		<value>	org.springframework.web.context.request.RequestContextHolder=requestAttributesHolder,inheritableRequestAttributesHolder;
		    	</value>
		
	</preference>





see http://www.zkoss.org/javadoc/3.0.3/zkplus/org/zkoss/zkplus/util/ThreadLocalListener.html

newguy2010
8 Sep 2010 18:54:51 GMT
8 Sep 2010 18:54:51 GMT

None of the above works. Any other suggestions?

vergereau
9 Sep 2010 00:25:32 GMT
9 Sep 2010 00:25:32 GMT

Hy NewGuy2010,

1/ Can you Make a short sample (conf file + java file + zul file) in order to test it.
2/ Which version of zk and Spring did you use ?

newguy2010
9 Sep 2010 01:12:10 GMT
9 Sep 2010 01:12:10 GMT

I've resort to use the SpringUtil class but still doesn't work.

A simple example:

Here is my code for EventController

package au.com.zkproject.controller;

import java.util.ArrayList;
import java.util.Arrays;

import org.apache.commons.lang.StringUtils;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.util.GenericForwardComposer;
import org.zkoss.zkplus.spring.SpringUtil;
import org.zkoss.zul.Button;
import org.zkoss.zul.Combobox;
import org.zkoss.zul.Radiogroup;

import au.com.zkproject.service.ConnectionService;
import au.com.zkproject.service.ModelService;

public class EventController extends GenericForwardComposer {
  
 
  private Combobox cbServer; // database server
  private Radiogroup rgDbType;
  
  private transient ConnectionService connectionService;
  private transient ModelService modelService;
  
  public ConnectionService getConnectionService() {
    if (connectionService == null) {
      connectionService = (ConnectionService)SpringUtil.getBean("connectionService");
      setConnectionService(connectionService);
    }
    return connectionService;
  }
  
  public void setConnectionService(ConnectionService connectionService) {
    this.connectionService = connectionService;
  }
  
  public ModelService getModelService() {
    if (modelService == null) {
      modelService = (ModelService)SpringUtil.getBean("modelService");
      setModelService(modelService);
    }
    return modelService;
  }
  
  public void setModelService(ModelService modelService) {
    this.modelService = modelService;
  }
  
  public void onFocus$cbServer(Event evt) {
    final String dbType = rgDbType.getSelectedItem().getLabel();
    if (!StringUtils.isEmpty(dbType)) {
      ListModel model = getModelService().getServerListModel(dbType);
      cbServer.setModel(model);
    }
  }
}

and my index.zul file:

<?page id="mainPage" title="Database tool alpha"?>
<zk>
<window id="connectWindow" title="Welcome to Database Tool Alpha!!"
border="normal" width="100%" apply="au.com.zkproject.controller.EventController">
<hbox pack="end">
<label value="Please enter parameters to connect to a database"/>
<vbox width="360px">
<hbox>
<label value="Choose a driver:"/>
<radiogroup id="rgDbType">
      <radio id="rdMSSQL" label="Microsoft SQL Server" checked="true"/>
      <radio id="rdOracle" label="Oracle" />
</radiogroup>
</hbox>
<hbox>
<label value="Database Server:" />
<combobox id="cbServer" cols="20" buttonVisible="false" autodrop="true"/>
</hbox>
</vbox>
</hbox>
</window>
</zk>

newguy2010
9 Sep 2010 01:12:57 GMT
9 Sep 2010 01:12:57 GMT

web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
  <display-name>DatabaseTool</display-name>
  <listener>
  	<description>
  	Used to cleanup when a session is destroyed</description>
  	<display-name>ZK Session cleaner</display-name>
  	<listener-class>org.zkoss.zk.ui.http.HttpSessionListener</listener-class>
  </listener>
  <!-- INI SPRING -->
  <!--
    - Location of the XML file that defines the root application context.
    - Applied by ContextLoaderServlet.
  -->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:spring-*.xml</param-value>
  </context-param>

  <!--
    - Loads the root application context of this web app at startup,
    - by default from "/WEB-INF/applicationContext.xml".
    - Note that you need to fall back to Spring's ContextLoaderServlet for
    - J2EE servers that do not follow the Servlet 2.4 initialization order.
    -
    - Use WebApplicationContextUtils.getWebApplicationContext(servletContext)
    - to access it anywhere in the web application, outside of the framework.
    -
    - The root context is the parent of all servlet-specific contexts.
    - This means that its beans are automatically available in these child contexts,
    - both for getBean(name) calls and (external) bean references.
  -->
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  
  <listener>
        <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
  </listener>
    <!-- END SPRING -->
  <servlet>
  	<description>
  	The ZK loader for ZUML pages</description>
  	<servlet-name>zkLoader</servlet-name>
  	<servlet-class>org.zkoss.zk.ui.http.DHtmlLayoutServlet</servlet-class>
  	<init-param>
  		<param-name>update-uri</param-name>
  		<param-value>/zkau</param-value>
  	</init-param>
  	<load-on-startup>2</load-on-startup>
  </servlet>
  <servlet>
  	<description>
  	The asynchronous update engine for ZK</description>
  	<servlet-name>auEngine</servlet-name>
  	<servlet-class>org.zkoss.zk.au.http.DHtmlUpdateServlet</servlet-class>
  </servlet>
  <servlet-mapping>
  	<servlet-name>zkLoader</servlet-name>
  	<url-pattern>*.zul</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
  	<servlet-name>zkLoader</servlet-name>
  	<url-pattern>*.zhtml</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
  	<servlet-name>auEngine</servlet-name>
  	<url-pattern>/zkau/*</url-pattern>
  </servlet-mapping>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
    <welcome-file>index.zul</welcome-file>
  </welcome-file-list>
</web-app>

spring-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xmlns:context="http://www.springframework.org/schema/context"
     xmlns:aop="http://www.springframework.org/schema/aop"
     xsi:schemaLocation="http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
         http://www.springframework.org/schema/context
         http://www.springframework.org/schema/context/spring-context-3.0.xsd
         http://www.springframework.org/schema/aop
         http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
  <!-- services -->
  <bean id="connectionService" scope="session" class="au.com.zkproject.impl.ConnectionServiceImpl" >
  </bean>
  
  <bean id="modelService" scope="session" class="au.com.zkproject.impl.ModelServiceImpl">
  </bean> 

  <!-- controllers -->
</beans>  

newguy2010
9 Sep 2010 01:15:25 GMT
9 Sep 2010 01:15:25 GMT

I am using zk 5.0.4 and Springframework 3.0.2, maven 2 and maven-jetty-plugin as the web server.
Whenever I try to focus on the cbServer combox it throws a NullPointerException, which means the service bean is not created or it cannot locate the bean.

vergereau
9 Sep 2010 03:04:23 GMT
9 Sep 2010 03:04:23 GMT

Can you give us the stack trace ?

I think you should process this way :

1- Test a basic zul.file to display an inject bean (a basic one just to display a string).

zul file

<?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver"?>
<zk>
<label value="${beanTest.textVal} />
</zk>


2. According to this test if bean it's display then we can see what's wrong in you example and try to use a best approach ( ex: First of all I think you should put the event on radiobox and not on the combobox focus, Use databinding for your model , ...)

newguy2010
9 Sep 2010 18:42:58 GMT
9 Sep 2010 18:42:58 GMT

Thanks vergereau. That test doesn't work so I guess it couldn't resolve the bean.
The radiogroup used to be a textbox so what I wanted is to get the model after I enter something in the textbox but avoid leaving a blank textbox. The event was previously coded for the old design and I forgot to modify the codes after I changed my design.