How to Integrate ZK with Seam

From Documentation
How to Integrate ZK with Seam


Stop.png This documentation is for an older version of ZK. For the latest one, please click here.


In this session, we show you how to config for integration, then we demonstrate two examples "Using bean context and navigation rule of Seam" and "Using bean context of Seam only".

Configuration

To integrate ZK with seam, you must download and install ZK (reference to ZK Tutorial ). After that, append following configuration on web.xml,zk.xml, navigation.xml and pages.xml in WEB-INF folder

  • web.xml : register two filters to initiate Seam's context when zk loading and ui update.
  <filter>
	  <filter-name>Seam Context Filter</filter-name>
	  <filter-class>org.jboss.seam.web.ContextFilter</filter-class>
  </filter>
  <filter-mapping>
	  <filter-name>Seam Context Filter</filter-name>
	  <servlet-name>zkLoader</servlet-name>
  </filter-mapping> 
  filter-mapping>
	  <filter-name>Seam Context Filter</filter-name>
	  <servlet-name>auEngine</servlet-name>
  </filter-mapping>
  <filter>
	  <filter-name>ZK FacesContext Filter</filter-name>
	  <filter-class>org.zkoss.seam.HttpFacesContextFilter</filter-class>
	  <init-param>
		  <param-name>update-uri</param-name>
		  <param-value>/zkau</param-value>
	  </init-param>
  </filter>
  <filter-mapping>
	  <filter-name>ZK FacesContext Filter</filter-name>
	  <servlet-name>zkLoader</servlet-name>
  </filter-mapping> 
  <filter-mapping>
	  <filter-name>ZK FacesContext Filter</filter-name>
	  <servlet-name>auEngine</servlet-name>
  </filter-mapping>


  • zk.xml : add Thread Local Synchronizer to synchronize context of Seam.
  <listener>
	  <description>ThreadLocal Variables Synchronizer</description>
	  <listener-class>org.zkoss.zkplus.util.ThreadLocalListener</listener-class>
  </listener>
  <preference>
   <name>ThreadLocal</name>
	  <value>
		org.jboss.seam.contexts.Contexts=applicationContext,methodContext,
			eventContext,pageContext,sessionContext,conversationContext,businessProcessContext;
		javax.faces.context.FacesContext=_currentInstance;
	  </value>
  </preference>


  • navigation.xml : add navigation rule (for first integration example only)
  <navigation-rule>
	  <from-view-id>/part2/*</from-view-id>
	  <navigation-case>
		  <from-outcome>fans</from-outcome>
		  <to-view-id>/part2/fans.zul</to-view-id>
		  <redirect/>
	  </navigation-case>
	  <navigation-case>
		  <from-outcome>hello</from-outcome>
		  <to-view-id>/part2/hello.zul</to-view-id>
		  <redirect/>
	  </navigation-case>
  </navigation-rule>


  • pages.xml : add Param for person.zul page initiation (for first integration example only)
  <page view-id="/part2/person.zul">
	  <param name="pid" value="#{manager.pid}" converterId="javax.faces.Long"/>
  </page>


Using bean context and navigation rule of Seam

In Part 2, we replace the UI layer from JSF to ZK. There are 3 zul pages which reuse Seam's context beans and page navigation rule by some utility class. All functions are same as "Say Hello" example in Seam.

  • part2/hello.zul
  <?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit" ?>
  <?variable-resolver class="org.zkoss.seam.DelegatingVariableResolver"?>
  <zk >
  <window title="DataModel, Validation and Restful Page Demo" border="normal" 
	width="400px">
	<zscript>import org.zkoss.seam.*</zscript>
	<grid>
	  <rows>
		<row>Your Name: 
		<textbox onBindingSave="ValidationUtil.validate(event)"
		value="@{bind(value=person.name,save-when='btn.onClick')}"/>
		</row>
		....
	  </rows>
	</grid>
	<button label="Say Hello" id="btn" onClick="doSayHello()"
	 onBindingValidate="ValidationUtil.afterValidate(event)"/>
	<button label="See Fans" href="fans.zul"/>
	
	<zscript>
	  void doSayHello(){
		NavigationUtil.navigate(manager.sayHello());
	  }
	</zscript>
  </window>
  </zk>

1. Add <?variable-resolver class="org.zkoss.seam.DelegatingVariableResolver"?> to obtain variable from Seam's context. Such as variable "person" will be obtained from Seam's context.

2. Add onBindingSave = "ValidationUtil.validate(event)" in component to handle validation and add onBindingValidate = "ValidationUtil.afterValidate(event)" in trigger button to handle the logic after validation.

3. Call manager.sayHello() to insert data. "manager" is obtain by resolver from Seam's context, too.

4. Use NavigationUtil.navigate(pageid:String) to process navigation rules of JSF.


  • part2/fans.zul
  <?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit" ?>
  <?variable-resolver class="org.zkoss.seam.DelegatingVariableResolver"?>
  <zk >
  <window title="The ZK and Seam Fans" border="normal" 
	width="600px">
	<zscript>import org.zkoss.seam.*;import org.jboss.seam.*;</zscript>
	The following persons have said "hello" to ZK and Seam:
	<grid model="@{bind(fans)}" id="g1" >
	  ....
	  <rows>  
		<row self="@{bind(each='rperson')}" value="@{bind(rperson)}">
		  <label value="@{bind(rperson.name)}"/>
		  ....
		  <button label="edit" onClick="doEdit(self.parent.value)"/>
		  <button label="delete" onClick="doDelete()" />
		</row>
	  </rows>
	</grid>
	<separator/>
	<button label="Goto Hello" onClick="gotoHello()"/>
	<zscript>
	  void gotoHello(){
		NavigationUtil.navigate("hello");
	  }
	  void doDelete(){
		if(DataModelUtil.select("fans","selectedFan",self.parent.value)){
		  NavigationUtil.navigate(manager.delete());
		  g1.model = fans;
		}else{
		  alert("some thing wrong!!");
		}
	  }
	  void doEdit(selected){
		selectedFan = selected;
		Executions.getCurrent().sendRedirect("person.zul?pid="+selectedFan.id);
	  }
	</zscript>
  </window>
  </zk>

1. Bind model of grid by variable "fans" from Seam's context.

2. Use DataModelUtil.select(dataModel:String,dataModelSelection:String,selected:Object) to inject selected person into Seam's context. After that, We call manager.delete() to delete selected person.

3. Update the model of grid(g1) since a new model is created after deletion.


  • part2/person.zul
  <?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit" ?>
  <?variable-resolver class="org.zkoss.seam.DelegatingVariableResolver"?>
  <zk >
  <window title="Edit " border="normal" 
	width="400px">
	<zscript>import org.zkoss.seam.*</zscript>
	<textbox visible="false" value="@{bind(value=person.id,save-when='btn.onClick')}"/>
	<grid>
	  <rows>
		<row>Your Name: 
		<textbox onBindingSave="ValidationUtil.validate(event)"
		value="@{bind(value=person.name,save-when='btn.onClick',converter='org.zkoss.seam.Validator')}"/>
		</row>
		....
	  </rows>
	</grid>
	<button label="Save" id="btn" onClick="doUpdate()"
		onBindingValidate="ValidationUtil.afterValidate(event)"/>
	<zscript>
	  void doUpdate(){
		  NavigationUtil.navigate(manager.update());
	  }
	</zscript>
  </window>
  </zk>

1. Because we assign a page initial action of Seam in pages.xml, so when a request to "/part2/person.zul" with request parameter "pid" will cause event invoking manager.setPid(). After this action, we can get "person" variable which is prepared by manager.setPid() from Seam's context.

2. We must bind person.id to a hidden field(use <textbox visible="false"> to instead) to retrieve data(id) back.

3. When call to manager.update(), a variable "person" will be update into database.


Live Demo

ERROR: Width and Height not set


Using bean context of Seam only

In Part 3, we not only replace the UI layer but also eliminate the navigation rule. Without tied with the navigation rule we can put all CRUD operation in just one page.

  • part3/hello.zul
  <?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit" ?>
  <?variable-resolver class="org.zkoss.seam.DelegatingVariableResolver"?>
  <zk  >
  <hbox onCreate="refreshW1()">
  <zscript>import org.zkoss.seam.*;import org.jboss.seam.*;</zscript>
  <zscript>
	Person selectedPerson;
  </zscript>
  <window border="normal" width="300px" id="w1">
	<textbox visible="false" value="@{bind(value=person.id,save-when='triggerBtn.onClick'}"/>
	<grid>
	  <rows>
		<row>Your Name: 
		<textbox onBindingSave="ValidationUtil.validate(event)"
		value="@{bind(value=person.name,save-when='triggerBtn.onClick')}"/></row>
		....
	  </rows>
	</grid>
	<button label="Say Hello" id="btn" onClick="Events.sendEvent(new Event(Events.ON_CLICK,triggerBtn));doSayHello()" />
	<button label="Update" id="updateBtn" onClick="Events.sendEvent(new Event(Events.ON_CLICK,triggerBtn));doUpdate()" />
	<button label="Delete" id="deleteBtn" onClick="Events.sendEvent(new Event(Events.ON_CLICK,triggerBtn));doDelete()" />
	<button label="Cancel" id="cancelBtn" onClick="doClear()"/>
	<button visible="false" id="triggerBtn" onBindingValidate="ValidationUtil.afterValidate(event)"/>
  </window>
  <window title="The following persons have said 'hello' to Zk and Seam:" border="normal" width="550px" id="w2">
	<listbox id="g1" onSelect="listSelected(g1.selectedItem)"
	  model="@{bind(fans)}" selectedItem="@{bind(selectedPerson)}">
	  ....
	  <listitem self="@{bind(each='lperson')}">
		<listcell label="@{bind(lperson.name)}"/>
		....
	  </listitem>
	</listbox>
  </window>
  <zscript>
	void listSelected(li){
	  ContextUtil.updateToContext("person",selectedPerson);
	  binder.loadComponent(w1);
	  refreshW1();
	}
	void doSayHello(){
	  manager.sayHello();
	  binder.loadComponent(w2);
	  doClear();
	}
	void doUpdate(){
	  manager.update();
	  binder.loadComponent(w2);
	  doClear();
	}
	void doDelete(){
	  if(DataModelUtil.select("fans","selectedFan",person)){
		manager.delete();
		binder.loadComponent(w2);  
		doClear();
	  }else{
		alert("some thing wrong!!");
	  }
	}
	void doClear(){
	  ContextUtil.updateToContext("person",new Person());
	  selectedPerson = null;
	  binder.loadComponent(w1);
	  refreshW1();
	}
	void refreshW1(){
	  if(person.id==0){
		w1.getFellow("btn").setVisible(true);
		....
	  }else{
		w1.getFellow("btn").setVisible(false);
		....
	  }
	}
  </zscript>
  </hbox>
  </zk>


  1. We use a tirggerBtn to proxy save-when event to multiple buttons(btn, updateBtn and deleteBtn). And those buttons must send a onClick Event to tirggerBtn to notify Data Binding to process.
  2. When listSelected(), we put selectedPerson into to Seam's context by ContextUtil.updateToContext(name:String,bean:Object). After that, we can reload the window by Data Binding.
  3. When "Say Hello" button is clicked, Data Binding is triggered by the Events.sendEvent(new Event(Events.ON_CLICK,triggerBtn)) and will bind data into person which is obtained from Seam's context. After that, doSayHello() just call manager.sayHello() to insert data
  4. When "Update" button is clicked, Data Binding is triggered by the Events.sendEvent(new Event(Events.ON_CLICK,triggerBtn)) and will bind data into person which is obtained from Seam's context. After that, doUpdate() just call manager.update() to update data.
  5. When "Delete" button is clicked, Data Binding is triggered by the Events.sendEvent(new Event(Events.ON_CLICK,triggerBtn)) and will bind data into person which is obtained from Seam's context. After that, in doDelete() we use DataModelUtil.select(dataModel:String,dataModelSelection:String,selected:Object) to inject person into Seam's context for DataModelSelection, and then just call manager.delete() to delete data.
  6. When doClear(), we put a new Person() into to Seam's context by ContextUtil.updateToContext(name:String,bean:Object). After that, We can reload the window by Data Binding.


Live Demo

ERROR: Width and Height not set



Last Update : 2010/07/19

Copyright © Potix Corporation. This article is licensed under GNU Free Documentation License.