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.
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.
I. System Structure
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:
Java EE Servlet 3.0 class:
Basically, AlarmsReceive.java is responsible for receiving Http requests from the Embedded System, and triggering ZK Server Push with Observable Pattern.
Spring Service Component class:
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.
ZK Composer and ZUL:
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. NetworkMap.ZUL focuses on integrating NetworkMapComposer and finalizing UI.
II. Code Illustration
AlarmsReceive.java is Servlet 3.0.
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.
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.
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.
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.
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.
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.
Caused by: java.lang.IllegalStateException: Access denied: component, <Rect mA3Qz3#RTU-T114_1>, belongs to another desktop: [Desktop z_hch:/security/template/baseLayout.zul]
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.
This article is contributed by Vincent Feng for the community. Please feel free to leave him a comment below or create a discussion on ZK forum.
|Copyright © Potix Corporation. This article is licensed under GNU Free Documentation License.|