diff options
Diffstat (limited to 'documentation/advanced/advanced-push.asciidoc')
-rw-r--r-- | documentation/advanced/advanced-push.asciidoc | 417 |
1 files changed, 0 insertions, 417 deletions
diff --git a/documentation/advanced/advanced-push.asciidoc b/documentation/advanced/advanced-push.asciidoc deleted file mode 100644 index df9279c6bb..0000000000 --- a/documentation/advanced/advanced-push.asciidoc +++ /dev/null @@ -1,417 +0,0 @@ ---- -title: Server Push -order: 16 -layout: page ---- - -[[advanced.push]] -= Server Push - -When you need to update a UI from another UI, possibly of another user, or from -a background thread running in the server, you usually want to have the update -show immediately, not when the browser happens to make the next server request. -For this purpose, you can use __server push__ that sends the data to the browser -immediately. Push is based on a client-server connection, usually a WebSocket -connection, that the client establishes and the server can then use to send -updates to the client. - -The server-client communication is done by default with a WebSocket connection -if the browser and the server support it. If not, Vaadin will fall back to a -method supported by the browser. Vaadin Push uses a custom build of the -link:https://github.com/Atmosphere/atmosphere[Atmosphere framework] for -client-server communication. - -[[advanced.push.installation]] -== Installing the Push Support - -The server push support in Vaadin requires the separate Vaadin Push library. It -is included in the installation package as [filename]#vaadin-push.jar#. - -[[advanced.push.installation.ivy]] -=== Retrieving with Ivy - -With Ivy, you can get it with the following declaration in the -[filename]#ivy.xml#: - - -[source, xml] ----- -<dependency org="com.vaadin" name="vaadin-push" - rev="&vaadin.version;" conf="default->default"/> ----- - -In some servers, you may need to exlude a [literal]#++sl4j++# dependency as -follows: - - -[source, xml] ----- -<dependency org="com.vaadin" name="vaadin-push" - rev="&vaadin.version;" conf="default->default"> - <exclude org="org.slf4j" name="slf4j-api"/> -</dependency> ----- - -Pay note that the Atmosphere library is a bundle, so if you retrieve the -libraries with Ant, for example, you need to retrieve -[literal]#++type="jar,bundle"++#. - - -[[advanced.push.installation.maven]] -=== Retrieving with Maven - -In Maven, you can get the push library with the following dependency in the POM: - - -[source, xml] ----- -<dependency> - <groupId>com.vaadin</groupId> - <artifactId>vaadin-push</artifactId> - <version>${vaadin.version}</version> -</dependency> ----- - - - -[[advanced.push.enabling]] -== Enabling Push for a UI - -To enable server push, you need to define the push mode either in the deployment -descriptor or with the [classname]#@Push# annotation for the UI. - -[[advanced.push.enabling.pushmode]] -=== Push Modes - -You can use server push in two modes: [literal]#++automatic++# and -[literal]#++manual++#. The automatic mode pushes changes to the browser -automatically after access() finishes. With the manual mode, you can do the push -explicitly with [methodname]#push()#, which allows more flexibility. - - -[[advanced.push.enabling.pushmode]] -=== The [classname]#@Push# annotation - -You can enable server push for a UI with the [classname]#@Push# annotation as -follows. It defaults to automatic mode ( [parameter]#PushMode.AUTOMATIC#). - - -[source, java] ----- -@Push -public class PushyUI extends UI { ----- - -To enable manual mode, you need to give the [parameter]#PushMode.MANUAL# -parameter as follows: - - -[source, java] ----- -@Push(PushMode.MANUAL) -public class PushyUI extends UI { ----- - - -[[advanced.push.enabling.servlet]] -=== Servlet Configuration - -You can enable the server push and define the push mode also in the servlet -configuration with the [parameter]#pushmode# parameter for the servlet in the -[filename]#web.xml# deployment descriptor. If you use a Servlet 3.0 compatible -server, you also want to enable asynchronous processing with the -[literal]#++async-supported++# parameter. Note the use of Servlet 3.0 schema in -the deployment descriptor. - - -[subs="normal"] ----- -<?xml version="1.0" encoding="UTF-8"?> -<web-app - id="WebApp_ID" version="**3.0**" - xmlns="**http://java.sun.com/xml/ns/javaee**" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="**http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd**"> - <servlet> - <servlet-name>Pushy UI</servlet-name> - <servlet-class> - com.vaadin.server.VaadinServlet</servlet-class> - - <init-param> - <param-name>UI</param-name> - <param-value>**com.example.my.PushyUI**</param-value> - </init-param> - - <!-- Enable server push --> - <init-param> - <param-name>pushmode</param-name> - <param-value>**automatic**</param-value> - </init-param> - <async-supported>**true**</async-supported> - </servlet> -</web-app> ----- - -[[advanced.push.running]] -== Accessing UI from Another Thread - -Making changes to a [classname]#UI# object from another thread and pushing them -to the browser requires locking the user session when accessing the UI. -Otherwise, the UI update done from another thread could conflict with a regular -event-driven update and cause either data corruption or deadlocks. Because of -this, you may only access an UI using the [methodname]#access()# method, which -locks the session to prevent conflicts. It takes a [interfacename]#Runnable# -which it executes as its parameter. - -For example: - - -[source, java] ----- -ui.access(new Runnable() { - @Override - public void run() { - series.add(new DataSeriesItem(x, y)); - } -}); ----- - -In Java 8, where a parameterless lambda expression creates a runnable, you could -simply write: - - -[source, java] ----- -ui.access(() -> - series.add(new DataSeriesItem(x, y))); ----- - -If the push mode is [literal]#++manual++#, you need to push the pending UI -changes to the browser explicitly with the [methodname]#push()# method. - - -[source, java] ----- -ui.access(new Runnable() { - @Override - public void run() { - series.add(new DataSeriesItem(x, y)); - ui.push(); - } -}); ----- - -Below is a complete example of a case where we make UI changes from another -thread. - - -[source, java] ----- -public class PushyUI extends UI { - Chart chart = new Chart(ChartType.AREASPLINE); - DataSeries series = new DataSeries(); - - @Override - protected void init(VaadinRequest request) { - chart.setSizeFull(); - setContent(chart); - - // Prepare the data display - Configuration conf = chart.getConfiguration(); - conf.setTitle("Hot New Data"); - conf.setSeries(series); - - // Start the data feed thread - new FeederThread().start(); - } - - class FeederThread extends Thread { - int count = 0; - - @Override - public void run() { - try { - // Update the data for a while - while (count < 100) { - Thread.sleep(1000); - - access(new Runnable() { - @Override - public void run() { - double y = Math.random(); - series.add( - new DataSeriesItem(count++, y), - true, count > 10); - } - }); - } - - // Inform that we have stopped running - access(new Runnable() { - @Override - public void run() { - setContent(new Label("Done!")); - } - }); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } -} ----- -See the http://demo.vaadin.com/book-examples-vaadin7/book#advanced.push.simple[on-line example, window="_blank"]. - -When sharing data between UIs or user sessions, you need to consider the -message-passing mechanism more carefully, as explained next. - - -[[advanced.push.pusharound]] -== Broadcasting to Other Users - -Broadcasting messages to be pushed to UIs in other user sessions requires having -some sort of message-passing mechanism that sends the messages to all UIs that -register as recipients. As processing server requests for different UIs is done -concurrently in different threads of the application server, locking the threads -properly is very important to avoid deadlock situations. - -[[advanced.push.pusharound.broadcaster]] -=== The Broadcaster - -The standard pattern for sending messages to other users is to use a -__broadcaster__ singleton that registers the UIs and broadcasts messages to them -safely. To avoid deadlocks, it is recommended that the messages should be sent -through a message queue in a separate thread. Using a Java -[classname]#ExecutorService# running in a single thread is usually the easiest -and safest way. - - -[source, java] ----- -public class Broadcaster implements Serializable { - static ExecutorService executorService = - Executors.newSingleThreadExecutor(); - - public interface BroadcastListener { - void receiveBroadcast(String message); - } - - private static LinkedList<BroadcastListener> listeners = - new LinkedList<BroadcastListener>(); - - public static synchronized void register( - BroadcastListener listener) { - listeners.add(listener); - } - - public static synchronized void unregister( - BroadcastListener listener) { - listeners.remove(listener); - } - - public static synchronized void broadcast( - final String message) { - for (final BroadcastListener listener: listeners) - executorService.execute(new Runnable() { - @Override - public void run() { - listener.receiveBroadcast(message); - } - }); - } -} ----- -See the http://demo.vaadin.com/book-examples-vaadin7/book#advanced.push.pusharound[on-line example, window="_blank"]. - -In Java 8, you could use lambda expressions for the listeners instead of the -interface, and a parameterless expression to create the runnable: - - -[source, java] ----- -for (final Consumer<String> listener: listeners) - executorService.execute(() -> - listener.accept(message)); ----- -See the http://demo.vaadin.com/book-examples-vaadin7/book#advanced.push.pusharound[on-line example, window="_blank"]. - - -[[advanced.push.pusharound.receiving]] -=== Receiving Broadcasts - -The receivers need to implement the receiver interface and register to the -broadcaster to receive the broadcasts. A listener should be unregistered when -the UI expires. When updating the UI in a receiver, it should be done safely as -described earlier, by executing the update through the [methodname]#access()# -method of the UI. - - -[source, java] ----- -@Push -public class PushAroundUI extends UI - implements Broadcaster.BroadcastListener { - - VerticalLayout messages = new VerticalLayout(); - - @Override - protected void init(VaadinRequest request) { - ... build the UI ... - - // Register to receive broadcasts - Broadcaster.register(this); - } - - // Must also unregister when the UI expires - @Override - public void detach() { - Broadcaster.unregister(this); - super.detach(); - } - - @Override - public void receiveBroadcast(final String message) { - // Must lock the session to execute logic safely - access(new Runnable() { - @Override - public void run() { - // Show it somehow - messages.addComponent(new Label(message)); - } - }); - } -} ----- -See the http://demo.vaadin.com/book-examples-vaadin7/book#advanced.push.pusharound[on-line example, window="_blank"]. - - -[[advanced.push.pusharound.sending]] -=== Sending Broadcasts - -To send broadcasts with a broadcaster singleton, such as the one described -above, you would only need to call the [methodname]#broadcast()# method as -follows. - - -[source, java] ----- -final TextField input = new TextField(); -sendBar.addComponent(input); - -Button send = new Button("Send"); -send.addClickListener(new ClickListener() { - @Override - public void buttonClick(ClickEvent event) { - // Broadcast the message - Broadcaster.broadcast(input.getValue()); - - input.setValue(""); - } -}); ----- -See the http://demo.vaadin.com/book-examples-vaadin7/book#advanced.push.pusharound[on-line example, window="_blank"]. - - - - - |