123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135 |
- ---
- title: Using Server Initiated Events
- order: 30
- layout: page
- ---
-
- [[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 <<EnablingServerPush#, Enabling server push>> or <<UsingPolling#, Using polling>>.
|