Belongs to the following category: ULC5.2,
Purpose
Pushing data from the server to the client is often a needed requirement for ULC applications. One way how to achieve this, is by using a
ULCPollingTimer where the client polls the server for modified data and/or for third-party events in certain time intervals. This contribution demonstrates a generic reusable event-driven approach for pushing data from the server to the client, using a
ULCPollingTimer underneath.
As its primary goal, this contribution achieves to dispatch events triggered from within another thread than the ULC thread to listeners being called from within the ULC thread.
Please be aware that asynchronous polling will keep your GUI responsive, but inconsistencies may arise between the client-side and the server-side under certain circumstances. This lies in the nature of asynchronous server/client communication.
Synchronous polling can affect the responsiveness of your GUI (wait cursor during server round-trip), but you will always have a consistent state between the client-side and the server-side.
Resources
How to use
At the heart of event posting and event dispatching is the thread-safe
EventDispatcher. In most situations, it is sufficient to have one instance per sesssion and, for example, it can be kept in ULC's
ApplicationContext.
EventDispatcher eventDispatcher = new EventDispatcher();
ApplicationContext.setAttribute("eventDispatcher", eventDispatcher);Next, we have to register a
GenericEventListener with the
EventDispatcher and specify what events from what objects we want to listen to. In the example below, we register a listener with a
Store instance from the Mail API. We also specify that we want to be notified about connection events. In the
eventFired method, we can then access and modify the ULC components.
Store mailStore;
…
eventDispatcher.addListener(mailStore, ConnectionEvent.class, new GenericEventListener() { // eventFired must be called from the ULC thread public void eventFired(EventObject event) { ConnectionEvent connectionEvent = (ConnectionEvent) event;
Store sourceStore = (Store) connectionEvent.getSource(); switch(connectionEvent.getType()) {
case ConnectionEvent.OPENED:
handleOpened(event);
break;
case ConnectionEvent.DISCONNECTED:
handleDisconnected(event);
break;
case ConnectionEvent.CLOSED:
handleClosed(event);
break;
}
}
…
});How do events related to business objects get posted to the
EventDispatcher? We have to register a listener with the business object and forward the received events to the
EventDispatcher. Typically, these events are triggered in another thread than the ULC thread. In the example below, we listen to
ConnectionEvents on a
Store instance and forward these events to the specified
EventDispatcher.
mailStore.addConnectionListener(new ConnectionListenerProxy(eventDispatcher));public class ConnectionListenerProxy implements ConnectionListener {
private EventDispatcher fEventDispatcher; public ConnectionListenerProxy(EventDispatcher eventDispatcher) {
fEventDispatcher = eventDispatcher;
} // these methods will be called from the Mail thread public void opened(ConnectionEvent connectionEvent) {
fEventDispatcher.postEvent(connectionEvent);
} public void disconnected(ConnectionEvent connectionEvent) {
fEventDispatcher.postEvent(connectionEvent);
} public void closed(ConnectionEvent connectionEvent) {
fEventDispatcher.postEvent(connectionEvent);
}
}The actual push behaviour is achieved through an
EventDispatchingPoller instance. It will cause the associated
EventDispatcher instance to dispatch the currently posted events. Since the
EventDispatchingPoller decorates a
ULCPollingTimer and since the polling timer will be triggered from within the ULC thread, the
eventFired methods of the registered
GenericEventListeners will be called from within the ULC thread, too.
EventDispatchingPoller poller = new EventDispatchingPoller(eventDispatcher, 1000, 0, true, IUlcEventConstants.ASYNCHRONOUS_MODE);
poller.start();
In the mail example shown, we have managed to dispatch mail events triggered from within the Mail thread to listeners being called from within the ULC thread.
How it is implemented
The section above has uncovered most of the implementation details.
Compatibility
The described functionality has been developed and tested using JDK 1.3.1_10, JDK 1.4.2_04 and ULC 5.2 on Windows XP.
Author
etienne