From a1b265c318dbda4a213cec930785b81e4c0f7d2b Mon Sep 17 00:00:00 2001
From: elmot <elmot@vaadin.com>
Date: Fri, 25 Sep 2015 16:40:44 +0300
Subject: Framework documentation IN

Change-Id: I767477c1fc3745f9e1f58075fe30c9ac8da63581
---
 documentation/advanced/advanced-push.asciidoc | 417 ++++++++++++++++++++++++++
 1 file changed, 417 insertions(+)
 create mode 100644 documentation/advanced/advanced-push.asciidoc

(limited to 'documentation/advanced/advanced-push.asciidoc')

diff --git a/documentation/advanced/advanced-push.asciidoc b/documentation/advanced/advanced-push.asciidoc
new file mode 100644
index 0000000000..df9279c6bb
--- /dev/null
+++ b/documentation/advanced/advanced-push.asciidoc
@@ -0,0 +1,417 @@
+---
+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"]
+----
+&lt;?xml version="1.0" encoding="UTF-8"?&gt;
+&lt;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**"&gt;
+  &lt;servlet&gt;
+    &lt;servlet-name&gt;Pushy UI&lt;/servlet-name&gt;
+    &lt;servlet-class&gt;
+        com.vaadin.server.VaadinServlet&lt;/servlet-class&gt;
+
+    &lt;init-param&gt;
+        &lt;param-name&gt;UI&lt;/param-name&gt;
+        &lt;param-value&gt;**com.example.my.PushyUI**&lt;/param-value&gt;
+    &lt;/init-param&gt;
+
+    &lt;!-- Enable server push --&gt;
+    &lt;init-param&gt;
+      &lt;param-name&gt;pushmode&lt;/param-name&gt;
+      &lt;param-value&gt;**automatic**&lt;/param-value&gt;
+    &lt;/init-param&gt;
+    &lt;async-supported&gt;**true**&lt;/async-supported&gt;
+  &lt;/servlet&gt;
+&lt;/web-app&gt;
+----
+
+[[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"].
+
+
+
+
+
-- 
cgit v1.2.3

