Here is information about the package which allows to make asynchronous
method calls from server to clients by packing the method invocations into
notifications being sent to the clients.
Introduction
There are some projects (Sequencer, PMA) which should update their state
in the GUIs with time. The updates are not parameter updates, but another type of
information like "sequence has been suspended" or "data are produced by PMA module".
Such information is represented as a notification which is sent to all the clients.
Notifications should keep their sending order.
Hints on the implementation
In fact all the notifications contain method invocations which are called on
the client listeners. Each notification has the number which is used on the
client side to keep the right ordering. So, basically client listeners expect
a notification with the next number.
One special case is resetting the client listener counter when a new publisher
replaces an old one (due to the server restart or any other reason).
Another important note about the client side is that it is not always appropriate
to just start accepting notifications upon the listener is created. It could be
necessary to first process all the notification which were sent before the listener
creation or just get the information about which notification to wait for first.
Some examples of usage can be found in JUnit tests.
The server side: NotificationPublisher and AccumulatingNotificationPublisher
Publishers are created by a factory NotificationPublisherFactory
and are used to publish notifications:
ClientNotificationListener publisher = publisherFactory.newNotificationPublisher(
PAR_NAME, ClientNotificationListener.class);
In this example all the available notifications are represented by
ClientNotificationListener interface. So for a user notification sending is
hidden behind a method call of this interface:
publisher.onSomethingHappened("info");
AccumulatingNotificationPublisher should be used if the client listener should
always process the notifications starting from the very first one. This publisher
keeps all the sent notifications in the buffer so it is possible to obtain them
and return to the client which was created later. The buffer of sent notifications
is obtained via publisher's administrative interface (AccumulatingNotificationPublisher).
For all the publishers created via factory it is possible to obtain an
administrative interface implementation: NotificationPublisher
and/or AccumulatingNotificationPublisher. Those interfaces contain
useful administrative methods which are common for all the publishers of that type.
For example, AccumulatingNotificationPublisher
contains methods to manipulate the buffer of sent messages:
NotificationPublishers.getAccumulatingPublisherAdmin(testPublisher)
.getAccumulatedNotifications();
The client side: notification listeners
The registration and unregistration of client listeners is done via
NotificationService:
notificationService.registerNotificationListener(PAR_NAME, clientListener);
As for publishers listeners can be registered as normal listeners (example above), normal listeners
which need some additional information about the publisher before delivering the notifications to
a client and as accumulating listeners.
- normal listeners receives notifications from the first one which came (they don't know which
notification should come first and therefore can miss some notifications, what is not always important)
- normal listeners which need additional information serve the case when it is
important to inform listener which notification should come first (to not miss it)
- accumulating listeners processing notifications from the very first one, so
they need all the notification which were sent before the listener registration.
Additional information can be delivered to the listeners by an implementation of
NotificationPublisherInfoFetcher or AccumulatingPublisherInfoFetcher
interfaces:
AccumulatingPublisherInfoFetcher fetcher = ...;
notificationService.registerAccumulatingNotificationListener(PAR_NAME,
clientListener, fetcher);