From: Erik Lumme Date: Mon, 11 Sep 2017 12:06:32 +0000 (+0300) Subject: Migrate UsingServerInitiatedEvents X-Git-Tag: 8.2.0.alpha2~64^2~71 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=refs%2Freviewable%2Fpr9959%2Fr3;p=vaadin-framework.git Migrate UsingServerInitiatedEvents --- diff --git a/documentation/articles/UsingServerInitiatedEvents.asciidoc b/documentation/articles/UsingServerInitiatedEvents.asciidoc new file mode 100644 index 0000000000..26221e9ac2 --- /dev/null +++ b/documentation/articles/UsingServerInitiatedEvents.asciidoc @@ -0,0 +1,130 @@ +[[using-server-initiated-events]] +Using server-initiated events +----------------------------- + +The traditional way of communicating with the server is always client +initiated. Whenever the user interacts with the application so a server +visit is needed, the browser connects to the server, sends a request and +waits for the response. The response is handled when received by the +browser and the UI is updated accordingly. For basic applications this +is all that is needed but there are also many cases when you want the +server to be able to initiate events: updating the progress of a long +running application, notifying you of changes in the back end, providing +interaction between users and so on. + +Starting from Vaadin 7.1 you have a couple of ways you can implement +server initiated events without requiring any external add-ons: polling +and push. Polling is based on the client actively polling the server, +asking “are there any news for me?” whereas push is based on keeping a +connection constantly open to the server, allowing the server to, +whenever it likes, send something to the client. Which you want to use +is dependent on your use case. If you have events which occur seldom but +you want to deliver them immediately to the user, then push might serve +you better. If you want to avoid constant server connections and only +need to check now and then if something has happened, polling may work +out well for you. For any use case you should consider the two options +and which one will better suit your needs. + +An important part to consider when using server initiated events is +locking. Vaadin is built around the fact that only one thread can access +any VaadinSession instance at any time. This is to prevent +inconsistencies from occuring and needs to be taken into account when +using background threads to update a UI (which lives inside a +VaadinSession). To do proper locking when you are updating the UI you +use the UI.access method: + +[source,java] +.... +theUI.access(new Runnable() { + @Override + public void run() { + theUI.setContent(new Label("This is the real content")); + } +}); +.... + +The access method ensure your update is safe to do (you have exclusive +access to the `VaadinSession`), it ensures that threadlocals work also +inside the `run()`` method (e.g. `UI.getCurrent()``) and finally it deals with +some typical deadlock situations. To be able to do all this it does not +guarantee that the `Runnable` is executed immediately - on the contrary +it will be run as soon as it is safe to run it without causing deadlocks +by locking multiple `VaadinSessions` at once. + +A typical use case is the one-shot background operation which does some +heavy lifting, updates the `UI` based on the result (which is then +fetched by the browser by polling or pushed to the browser) and then +goes away. This can be implemented as a `Runnable`, e.g. + +[source,java] +.... +class AntCounter implements Runnable { + @Override + public void run() { + // Do some heavy work + final int result = calculateNumberOfAntsInTheWorld(); + + // Wrap UI updates in access to properly deal with locking + theUI.access(new Runnable() { + @Override + public void run() { + theUI.setContent(new Label("The result is " + result)); + } + }); + } +} +.... + +The Runnable is typically run in a background thread using e.g. an +`ExecutorService`. + +The other typical case is a long running background task which checks +for some event and, in case that events happens, alerts the user. The +event can originate from another user, from a change in the database or +from somewhere else. Similarly to before, this can be implemented as a +`Runnable`: + +[source,java] +.... +class AntTracker implements Runnable { + @Override + public void run() { + // Do some initial work + int antPopulation = calculateNumberOfAntsInTheWorld(); + + while (true) { + // Loop forever and ever + final int antPopulationNow = calculateNumberOfAntsInTheWorld(); + if (antPopulationNow != antPopulation) { + antPopulation = antPopulationNow; + // Wrap UI updates in access to properly deal with locking + theUI.access(new Runnable() { + @Override + public void run() { + new Notification("Ant population is now " + + antPopulationNow, Type.TRAY_NOTIFICATION) + .show(theUI.getPage()); + } + }); + } + // Wait for a while before calculating again + try { + Thread.sleep(5000); + } catch (InterruptedException e) { + return; + } + } + } + + private int calculateNumberOfAntsInTheWorld() { + return (int) (new Date().getTime()/1500); + } +} +.... + +The same thing can of course be implemented without the `while(true)`` loop +by using for instance a `ScheduledExecutorService` instead to make the +executor service handle the iteration and interval (e.g. `Executors.newScheduledThreadPool(1).scheduleAtFixedRate(...)`). + +For more information on how to enable push or polling in your +application, see link:EnablingServerPush.asciidoc[Enabling server push] or link:UsingPolling.asciidoc[Using polling]. diff --git a/documentation/articles/contents.asciidoc b/documentation/articles/contents.asciidoc index d2e77bad83..462e6df4fc 100644 --- a/documentation/articles/contents.asciidoc +++ b/documentation/articles/contents.asciidoc @@ -36,3 +36,4 @@ are great, too. - link:AccessingWebPageAndBrowserInformation.asciidoc[Accessing web page and browser information] - link:GeneratingDynamicResourcesBasedOnURIOrParameters.asciidoc[Generating dynamic resources based on URI or parameters] - link:OptimizingTheWidgetSet.asciidoc[Optimizing the widget set] +- link:UsingServerInitiatedEvents.asciidoc[Using server-initiated events]