The Name Of My Page"

From Documentation
Line 1: Line 1:
 
{{Template:Smalltalk_Author|
 
{{Template:Smalltalk_Author|
|author=Vincent Feng, Engineer, Getech Technology Corporation
+
|author=Matthieu Duchemin, Engineer, Potix Corporation
|date=March 7, 2016
+
|date=January 2016
 +
|version=ZK 8.0
 
}}
 
}}
  
=Foreword=
+
ZK Framework offer lots of features to simplify the creation of a Java based web application. As some of these features are not always known, we sometime come across suboptimal implementation. Usually, it only take a few simple steps to make them simpler and easier. Those aren't necessarily broken or damaging, but they can have positive effects without much changes or efforts.
I work as a software developer in an instrument company where we distribute and provide value-added services on solutions provided by Agilent, HP, Philips, etc. In this article I would like to share with you how I created a real-time system to both retrieve information from a remote embedded system and update the UI with ZK Server Push. I hope these tips will be useful references for those who have a similar requirement.
+
You will find here a few common mistakes in ZK, and solutions to avoid them.
  
=Functional Requirements=
+
=ZK Do's and Don'ts Part 1=
  
The system needs to listen to Http requests sent from the remote Embedded System, and update the information on ZK UI immediately, so that users can always get the latest update of the remote Embedded System.
+
==Calling components directly when using a model==
 +
ZK offers default ListModel<ref>http://books.zkoss.org/wiki/ZK_Developer's_Reference/MVC/Model/List_Model</ref> implementations such as ListModelList. They provide an easy way to separate the view from the model. By providing a template or a renderer to control the appearance, and a model to handle the data.
 +
While delegating control to the model, it feel sometime "easier" to act directly on a component. One would use grid.getRows().appendChild(..) to add a new row, or use listbox.setSelectedIndex() to set the selection state of a Listbox.
 +
If the components content is directly controlled by the application, this may be correct. However, if the content is controlled by a model, the model itself should perform these actions.
 +
<br/>
 +
;Do:
 +
*Use ListModels instead of basic collections when assigning a model to a component.
 +
**List – ListModelList <ref>https://www.zkoss.org/javadoc/latest/zk/org/zkoss/zul/ListModelList.html</ref>
 +
**Set – ListModelSet <ref>https://www.zkoss.org/javadoc/latest/zk/org/zkoss/zul/ListModelSet.html</ref>
 +
**Map - ListModelMap <ref>https://www.zkoss.org/javadoc/latest/zk/org/zkoss/zul/ListModelMap.html</ref>
 +
**Object[] or Enum – ListModelArray <ref>https://www.zkoss.org/javadoc/latest/zk/org/zkoss/zul/ListModelArray.html</ref>
 +
*Use ListModel methods to apply changes to the model.
 +
<br/>
 +
;Don’t:
 +
*Use component methods to alter the view when using a model.
 +
*Mix model and manual entries in the same component.
  
=I. System Structure=
+
==Understanding ZK scopes==
 +
Scopes in ZK define the range affected by and action. For example, when creating an event queue, we need to define the scope of listeners affected by its events.
 +
The basic scopes are DESKTOP, SESSION and APPLICATION. <ref>http://books.zkoss.org/wiki/ZK_Developer's_Reference/Event_Handling/Event_Queues#More_About_Scopes</ref>
 +
APPLICATION is very straightforward: it will affect every listeners on the whole application.
 +
SESSION represent the browser session. Assuming that the client uses cookies, it will match each tab in the browser.
 +
DESKTOP roughly represents a unique browser tab. In specific cases, like Iframe, a tab can contain more than one desktop.
 +
When using events, choosing the right scope can lead to increased performances, reduced network activity and reduced memory consumption. It’s also work remembering that using an event queue with any scope except Desktop will automatically activate server push.
 +
<br/>
 +
;Do:
 +
*Always use the smallest possible scope.
 +
*Be careful when using session scope, as it will affect every desktops in the session.
 +
*Be extra careful when using application scope, as it will affect any desktops in the application.
 +
<br/>
 +
;Don’t:
 +
*Use a scope broader than desktop unless you are sure that you need it.
 +
*Choose session or application if you do not want server push to be activated.
  
The system is mainly developed by Java EE, Spring, and ZK. I use Servlet in Java EE, accompanied by Observable Pattern to trigger ZK Server Push to change ZUL. The main classes and ZUL are named below:
+
==Component belong to another desktop==
      <br><b>Java EE Servlet 3.0 class:</b><br>
+
Saving a reference to a component can be a powerful way to keep track of changes, but there is one pitfall to avoid. ZK components are bound to a desktop, and cannot be passed around to another desktop or session.
Basically, AlarmsReceive.java is responsible for receiving Http requests from the Embedded System, and triggering ZK Server Push with Observable Pattern.
+
Choosing where to save or send the component reference is critical, as accessing it outside of its original desktop would cause exceptions in the best case, and corrupted views in the worst. To avoid this, always use desktop scope when passing around components, and only send values when serving a whole session or application.
<br><b>Spring Service Component class:</b><br>
+
<br/>
AlarmNotifyObservable.java inherits the class of java.util.Observable, delivers the information between Java EE and ZK, and notifies changes or updates of Observer object messages implemented in the system.
+
;Do:
<br><b>ZK Composer and ZUL:</b><br>
+
*Keep references of business objects, values between desktops if needed.
NetworkMapComposer.java particularly inherits ZK’s SelectorComposer, and implements java.util.Observer. It listens to the events sent by Java EE through Observer, draws and updates UI.
+
*Use event queues for live data. Use session or application parameters for static data.
NetworkMap.ZUL focuses on integrating NetworkMapComposer and finalizing UI.
+
<br/>
 +
;Don’t:
 +
*Keep a reference to a view object such as a component as a session or application parameter.
 +
*Send a reference to a view object in an event queue with a scope is broader than desktop.
  
 +
==Choosing @init, @load, @save, or @bind==
 +
Using the MVVM data-binding annotations to wire a view model and a view, you may use these four annotations.
 +
*@init will load the value in the view once, but will not update it.<ref>http://books.zkoss.org/zk-mvvm-book/8.0/syntax/databindinginit.html</ref>
 +
*@load will load the value in the view, then updated it when the view model notify a change.<ref>http://books.zkoss.org/zk-mvvm-book/8.0/syntax/load.html</ref>
 +
*@save will not load anything in the view, but will save the values from the view into the view model when updated.<ref>http://books.zkoss.org/zk-mvvm-book/8.0/syntax/save.html</ref>
 +
*@bind is basically @save plus @load. Values will be updated from and to the view model when necessary.<ref>http://books.zkoss.org/zk-mvvm-book/8.0/syntax/bind.html</ref>
 +
By expensiveness, they are ranked as follow: @init < @load | @save < @bind.
 +
<br/>
 +
;Do:
 +
*Choose the least expensive option for each binding.
 +
<br/>
 +
;Don’t:
 +
*Bind a value using @save or @bind on components whose value cannot be set by the user, such as label, etc.
 +
*Bind a value using @load or @bind on components whose value is never set on server side.
 +
*Use @load when @init is sufficient.
  
=II. Code Illustration=
+
==Notifying the whole ListModel on change==
 +
Speaking of models and data-binding, ListModels will automatically update the view after many actions, such as adding or deleting an element. This makes adding new entries in a complex control such as a grid very easy.
 +
However, it’s not always best to refresh the whole model after making a small update on one of its items. ListModels can actually update individual items, which can save a lot of resources.
 +
<br/>
 +
;Do:
 +
*Bind a ListModel to a component using @init, unless you need to replace the whole model by a new object.
 +
*Use the ListModelList.notifyChange(…) method to update a single entry, or set the entry again to trigger a refresh instead of notifying the whole model.
 +
<br/>
 +
;Don’t:
 +
*Use @NotifyChange(“*”),  or BindUtils.postNotifyChange(…, …, …, "*"); unless there is no better option.
 +
*Use @NotifyChange(“myListModel”) or BindUtils.postNotifyChange(…, …, …, "myListModel"); to update a single row.
  
<b>AlarmsReceive.java is Servlet 3.0.</b>
+
= References =
<br>[[File:Import.png‎]]
+
<references/>
<br><br>I use Java EE annotation @Webservlet with a parameter name that is the same as the servlet’s. urlPatterns serve as the web link to invoke the URL of the Servlet and loadOnStartup, which then triggers the order of the Servlet; the smaller the number, the earlier it starts.
 
<br><br>
 
Next, I declare class variable alarmsNotifyObservable and override init method, so that when starting the Servlet, AslarmsRecevie.java can retrieve AlarmsNotifyObservable objects from Spring web context. Then in Service method, alarmsNotifyObservable receives and handles the information sent from Embedded System, calls the method of sendNotification(data) from AlarmNotifyObservable.java, and triggers Observable Pattern to notify the inherited Observer object.
 
<br><br><br>[[File:Private..png‎]]
 
<br><br>AlarmNotifyObservable.java is the Bean of Spring framework.
 
Using @Service in Spring framework to initiate AlarmNotifyObservable.java is to ensure that the whole system has only one Observable. AlarmNotifyObservable inherits the Observable of Java Util, to save those listeners and sends messages when the listeners are triggered. setChanged() means status change, while notifyObserver() represents the method of sending messages.
 
<br><br>
 
[[File:Service.png‎]]<br><br>
 
NetworkMapComposer.java mainly inherits ZK’s SelectorComposer and implements java.util.Observer. In NetworkMapComposer, it listens to the messages sent by Observer and uses ZK Server PUSH to update the information on UI immediately, and obtains the session-scope EventQueue. 
 
  
<br><br>I use AlarmNotifyObservable to add myself into Observer pattern’s listening queue, and create an EventListener of Server Push. When Server Push changes the UI, (i.e. updateGis, initGis or openAlarmList) I use gisChangeEvent.subcribe (gisChangeEventEventListener) to subscribe to Server Push.<br><br>[[File:Gis.png‎]]
+
{{Template:CommentedSmalltalk_Footer_new|
 
 
NetworkMapComposer, which inherits java.util.Observer, implements update() method; this will influence updated items when Observer status is changed.
 
<br>[[File:Gis.png‎]]
 
 
 
=Challenges and Tips=
 
 
 
Note that if you are changing things like ZK UI components in ZK Server Push, it is not recommended that you send it through Server Push eventlistener, since during the sending process, server push will lock the sending object, and an error message will occur: Access denied: component. Therefore, those that will be changed should not be put into and sent by server push; instead, you should send values to indicate the changed UI content.
 
<br><br>
 
Complete example: <br>
 
Caused by: java.lang.IllegalStateException: Access denied: component, <Rect mA3Qz3#RTU-T114_1>, belongs to another desktop: [Desktop z_hch:/security/template/baseLayout.zul]
 
<br>
 
1. Every time you re-enter SelectorComposer, UI will be re-drawn and a new SelectorComposer will be created. However, since the previous SelectorComposer may or may not be recycled yet, it will be difficult to define the actual time the SelectorComposer is created. To avoid such cases, when implementing update() method in Observer pattern, I first define whether the desktop exists already or not. If the desktop does not exist, it means that SelectorComposer does not exist either, and I can safely delete the invalid SelectorComposer in the observer pattern queue.
 
<br>
 
 
 
 
 
This article is contributed by Vincent Feng for the community. Please feel free to leave him a comment below or create a discussion on [http://forum.zkoss.org/questions/ ZK forum].
 
 
 
{{Template:CommentedSmalltalk_Footer|
 
 
|name=Potix Corporation
 
|name=Potix Corporation
 
}}
 
}}

Revision as of 06:09, 17 March 2016

The Name Of My Page

Author
Matthieu Duchemin, Engineer, Potix Corporation
Date
January 2016
Version
ZK 8.0

ZK Framework offer lots of features to simplify the creation of a Java based web application. As some of these features are not always known, we sometime come across suboptimal implementation. Usually, it only take a few simple steps to make them simpler and easier. Those aren't necessarily broken or damaging, but they can have positive effects without much changes or efforts. You will find here a few common mistakes in ZK, and solutions to avoid them.

ZK Do's and Don'ts Part 1

Calling components directly when using a model

ZK offers default ListModel[1] implementations such as ListModelList. They provide an easy way to separate the view from the model. By providing a template or a renderer to control the appearance, and a model to handle the data. While delegating control to the model, it feel sometime "easier" to act directly on a component. One would use grid.getRows().appendChild(..) to add a new row, or use listbox.setSelectedIndex() to set the selection state of a Listbox. If the components content is directly controlled by the application, this may be correct. However, if the content is controlled by a model, the model itself should perform these actions.

Do
  • Use ListModels instead of basic collections when assigning a model to a component.
    • List – ListModelList [2]
    • Set – ListModelSet [3]
    • Map - ListModelMap [4]
    • Object[] or Enum – ListModelArray [5]
  • Use ListModel methods to apply changes to the model.


Don’t
  • Use component methods to alter the view when using a model.
  • Mix model and manual entries in the same component.

Understanding ZK scopes

Scopes in ZK define the range affected by and action. For example, when creating an event queue, we need to define the scope of listeners affected by its events. The basic scopes are DESKTOP, SESSION and APPLICATION. [6] APPLICATION is very straightforward: it will affect every listeners on the whole application. SESSION represent the browser session. Assuming that the client uses cookies, it will match each tab in the browser. DESKTOP roughly represents a unique browser tab. In specific cases, like Iframe, a tab can contain more than one desktop. When using events, choosing the right scope can lead to increased performances, reduced network activity and reduced memory consumption. It’s also work remembering that using an event queue with any scope except Desktop will automatically activate server push.

Do
  • Always use the smallest possible scope.
  • Be careful when using session scope, as it will affect every desktops in the session.
  • Be extra careful when using application scope, as it will affect any desktops in the application.


Don’t
  • Use a scope broader than desktop unless you are sure that you need it.
  • Choose session or application if you do not want server push to be activated.

Component belong to another desktop

Saving a reference to a component can be a powerful way to keep track of changes, but there is one pitfall to avoid. ZK components are bound to a desktop, and cannot be passed around to another desktop or session. Choosing where to save or send the component reference is critical, as accessing it outside of its original desktop would cause exceptions in the best case, and corrupted views in the worst. To avoid this, always use desktop scope when passing around components, and only send values when serving a whole session or application.

Do
  • Keep references of business objects, values between desktops if needed.
  • Use event queues for live data. Use session or application parameters for static data.


Don’t
  • Keep a reference to a view object such as a component as a session or application parameter.
  • Send a reference to a view object in an event queue with a scope is broader than desktop.

Choosing @init, @load, @save, or @bind

Using the MVVM data-binding annotations to wire a view model and a view, you may use these four annotations.

  • @init will load the value in the view once, but will not update it.[7]
  • @load will load the value in the view, then updated it when the view model notify a change.[8]
  • @save will not load anything in the view, but will save the values from the view into the view model when updated.[9]
  • @bind is basically @save plus @load. Values will be updated from and to the view model when necessary.[10]

By expensiveness, they are ranked as follow: @init < @load | @save < @bind.

Do
  • Choose the least expensive option for each binding.


Don’t
  • Bind a value using @save or @bind on components whose value cannot be set by the user, such as label, etc.
  • Bind a value using @load or @bind on components whose value is never set on server side.
  • Use @load when @init is sufficient.

Notifying the whole ListModel on change

Speaking of models and data-binding, ListModels will automatically update the view after many actions, such as adding or deleting an element. This makes adding new entries in a complex control such as a grid very easy. However, it’s not always best to refresh the whole model after making a small update on one of its items. ListModels can actually update individual items, which can save a lot of resources.

Do
  • Bind a ListModel to a component using @init, unless you need to replace the whole model by a new object.
  • Use the ListModelList.notifyChange(…) method to update a single entry, or set the entry again to trigger a refresh instead of notifying the whole model.


Don’t
  • Use @NotifyChange(“*”), or BindUtils.postNotifyChange(…, …, …, "*"); unless there is no better option.
  • Use @NotifyChange(“myListModel”) or BindUtils.postNotifyChange(…, …, …, "myListModel"); to update a single row.

References


Comments



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