I want to share the same set of data to multiple clients. I need to use Push to automatically update their view on screen.
I have read the Question and Answer, Minimal example of Push in Vaadin 7 app (“@Push”). Now I need a more robust realistic example. For one thing, I know having a never-ending Thread is not a good idea in a Servlet environment.
And I don't want each user having their own Thread, each hitting the database on their own. Seems more logical to have one thread alone checking for fresh data in the database. When found, that thread should publish the fresh data to all the users’ UI/Layouts waiting for updates.
Fully-Working Example
Below you will find the code for several classes. Together they make a fully working example of a Vaadin 7.3.8 app using the new built-in Push features to publish a single set of data simultaneously to any number of users. We simulate checking the database for fresh data by randomly generating a set of data values.
When you run this example app, a window appears displaying the current time along with a button. The time updates once per second for a hundred times.
This time-updating is not the true example. The time-updater serves two other purposes:
To see the true intended example of this app, click/tap the "Open data window" button. A second window opens to show three text fields. Each field contains a randomly-generated value which we pretend came from a database query.
Doing this is a bit of work, requiring several pieces. Let's go over those pieces.
Push
In the current version of Vaadin 7.3.8, there is no need for plugins or add-ons to enable Push technology. Even the Push-related .jar file is bundled with Vaadin.
See the Book Of Vaadin for details. But really all you need to do is add the
@Push
annotation to your subclass of UI.Use recent versions of your Servlet container and web server. Push is relatively new, and implementations are evolving, especially for the WebSocket variety. For example, if using Tomcat be sure to use the latest updates to Tomcat 7 or 8.
Periodically Checking For Fresh Data
We must have some way to repeatedly query the database for fresh data.
A never-ending Thread is not the best way to do that in a Servlet environment, as the Thread will not end when the web app is undeployed nor when the Servlet contain shutsdown. The Thread will continue to run in the JVM, wasting resources, causing a memory leak and other problems.
Web App Startup/Shutdown Hooks
Ideally we want to be informed when the web app starts up (deployed) and when the web app shuts down (or undeployed). When so informed, we could launch or interrupt that database-querying thread. Fortunately, there is such a hook provided as part of every Servlet container. The Servlet spec requires a container support the
ServletContextListener
interface.We can write a class that implements this interface. When our web app (our Vaadin app) is deployed, our listener class’
contextInitialized
is called. When undeployed, thecontextDestroyed
method is called.Executor Service
From this hook we could start up a Thread. But there is a better way. Java comes equipped with the
ScheduledExecutorService
. This class has a pool of Threads at its disposal, to avoid the overhead of instantiating and starting threads. You can assign one or more tasks (Runnable) to the executor, to be run periodically.Web App Listener
Here is our web app listener class, using the Lambda syntax available in Java 8.
DataPublisher
In that code you’ll see the DataPublisher instance is called periodically, asking it to check for fresh data, and if found deliver to all the interested Vaadin layouts or widgets.
Accessing Database
That DataPublisher class uses a DataProvider class to access the database. In our case, instead of actually accessing a database we simply generate random data values.
Packaging Data
The DataProvider packages fresh data for delivery to other objects. We define a DataEvent class to be that package. Alternatively, if you need to deliver multiple sets of data or objects rather than a single, then place a Collection in your version of DataHolder. Package up whatever makes sense for the layout or widget that wants to display this fresh data.
Distributing Data
Having packaged up fresh data into a DataEvent, the DataProvider hands that off to the DataPublisher. So the next step is getting that data to the interested Vaadin layouts or widgets for presentation to the user. But how do we know which layouts/widgets are interested in this data? And how do we deliver this data to them?
One possible way is the Observer Pattern. We see this pattern in Java Swing as well as Vaadin, such as a
ClickListener
for aButton
in Vaadin. This pattern means the observer and observed know about each other. And it means more work in defining and implementing interfaces.Event Bus
In our case, we do not need the producer of the data (DataPublisher) and the consumers (the Vaadin layouts/widgets) to know about each other. All the widgets want is the data, without any need for further interaction with the producer. So we can use a different approach, an event bus. In an event bus some objects publish an "event" object when something interesting occurs. Other objects register their interest in being notified when an event object is posted to the bus. When posted, the bus publishes that event to all the registered subscribers by calling a certain method and passing the event. In our case, the DataEvent object will be passed.
But which method on the registered subscribing objects will be invoked? Through the magic of Java’s annotation, reflection, and introspection technologies, any method can be tagged as the one to be called. Merely tag the desired method with an annotation, then let the bus find that method at runtime when publishing an event.
No need to build any of this event bus yourself. In the Java world, we have a choice of event bus implementations.
Google Guava EventBus
The most well known is probably the Google Guava EventBus. Google Guava is a bunch of various utility projects developed in-house at Google and then open-sourced for others to use. The EventBus package is one of those projects. We could use Guava EventBus. Indeed I did originally build this example using this library. But Guava EventBus has one limitation: It holds strong references.
Weak References
When objects register their interest in being notified, any event bus must keep a list of those subscriptions by holding a reference to the registering object. Ideally this should be a weak reference, meaning that should the subscribing object reach the end of its usefulness and become a candidate for garbage collection, that object may do so. If the event bus holds a strong reference, the object cannot proceed to garbage collection. A weak reference tells the JVM that we do not really care about the object, we care a little but not enough to insist the object be retained. With a weak reference, the event bus checks for a null reference before attempting to notify the subscriber of a new event. If null, the event bus can drop that slot in its object-tracking collection.
You might think that as a workaround for the problem of holding strong references you could have your registered Vaadin widgets override the
detach
method. You would be informed when that Vaadin widget is no longer is use, then your method would deregister from the event bus. If the subscribing object is taken out of the event bus, then no more strong reference and no more problem. But just as the Java Object methodfinalize
is not always called, so too is the Vaadindetach
method not always called. See the posting on this thread by Vaadin expert Henri Sara for details. Relying ondetach
could result in memory leaks and other problems.MBassador Event Bus
See my blog post for a discussion of various Java implementations of event bus libraries. Of those I chose MBassador for use in this example app. Its raison d’être is the use of weak references.
UI Classes
Between Threads
To actually update the values of the Vaadin layouts & widgets, there is one big catch. Those widgets run in their own user-interface-handling thread (the main Servlet thread for this user). Meanwhile, your database-checking and data-publishing and event-bus-dispatching are all happening on a background thread managed by the executor service. Never access or update Vaadin widgets from a separate thread! This rule is absolutely critical. To make it even trickier, doing so might actually work during development. But you will be in a world of hurt if you do so in production.
So how do we get the data from the background threads to be communicated into the widgets running in the main Servlet thread? The UI class offers a method just for this purpose:
access
. You pass a Runnable to theaccess
method, and Vaadin schedules that Runnable to be executed on the main user-interface thread. Easy-peasy.Remaining Classes
To wrap up this example app, here are the remaining classes. The "MyUI" class replaces that file of the same name in a default project created by the new Maven archetype for Vaadin 7.3.7.
"DataUI" and "DataLayout" complete the 7 .java files in this example Vaadin app.
…and…