Vaadin

Vaadin Server Push Example

Server push is a technology when the server pushes data to the client without the client asking for that data just like the old intranet client/server architecture when the clients get updated by the server. This kind of communication was near to impossible in the web few years before, first the bandwidth, when the Internet begins was not enough for server push, several attempts before the HTML5 websocket like webcasting and comet have not been successfull enough and is with HTML5 that server push become widely used.

1. The tools

  • Java JDK 8
  • Latest Eclipse Mars
  • Vaadin 7.6.4
  • Tomcat Server 8

2. Introduction

Vaadin make very easy to use server push, you only need to use the @Push annotation and Vaadin is using server push. In this example I am going to show you how to handle the server push to send content to the client. I am using here Labels as a containers to the data pushed from the server but you can use any container you want. In the first server push, the server is pushing the time every second and in the second one the server is pushing every 10 seconds.

3. Prerequisites

  • JDK installed
  • Eclipse Mars installed and working
  • Vaadin 7.6.4 plugin installed
  • Tomcat 8 installed and running

4. Set up the project

In the file menu choose File -> New -> Other:

01 New Project
01 New Project

Now from the list choose Vaadin 7 project:

02 Vaadin Project
02 Vaadin Project

Hit next and name your project then hit finish.

5. Coding the example

5.1 The quote generator class

I created a class that generates some random quotes from an array.

Quote array

private String[] quotes = new String[20];

Declared the array.

Generate quotes

	public String getQuote(){
		Random r = new Random();
		return quotes[r.nextInt(20)];
	}

Generate a random quote from the array.

5.2 Initial preparations

@Push annotation

@Push
@SuppressWarnings("serial")
@Theme("vaadinseverpushbeta")
public class VaadinseverpushbetaUI extends UI{

To use server push just add the annotation @Push to the UI class annotations. Adding @Push to a UI class configures the UI for automatic push.

Class Variables

	private QuoteGenerator qg;
	private VerticalLayout layout;
	private Label theTime;

The private QuoteGenerator qg; is used for the custom POJO Class created before to generate quotes. private VerticalLayout layout; the layout of our UI class and private Label theTime; to store the datetime pushed from the server.

5.3 First Thread

I am using Threads to make the server pushes.

First Thread

	class MyFirsthThread extends Thread {

        @Override
        public void run() {
            try {
                while (true) {
            		Thread.sleep(1000);

                    access(new Runnable() {
                        @Override
                        public void run() {
                    		theTime.setValue("Its now : " + Instant.now());
                        }
                    });
                }

            	} catch (InterruptedException e) {
            		e.printStackTrace();
            	}
        }
    }

This thread update the private Label theTime; every second as long as the webpage is running, the time is coming from the server using server push. Thread.sleep(1000);, sleep the thread for 1000 milliseconds = 1 second. access(new Runnable() locks the UI and provide exclusive access to the current runnable, All the UI operations must be inside an access block because the thread needs a lock to modify the UI, if you try to modify the UI outside an access block an exception is raised. theTime.setValue("Its now : " + Instant.now()); modify the content of the Label using server push.

5.4 Second Thread

Second Thread

	class MySecondThread2 extends Thread {
        int count = 0;

        @Override
        public void run() {
            try {
                while (count < 4) {
                    Thread.sleep(10000);

                    access(new Runnable() {
                        @Override
                        public void run() {
                        	layout.addComponent(new Label(qg.getQuote()));
                        	count++;
                        }
                    });
                }

                access(new Runnable() {
                    @Override
                    public void run() {
                        layout.addComponent(new Label("No more messages for you !"));
                    }
                });
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

This thread run four times every 10 seconds and every time it runs, adds a label with a random quote from the server using server push.int count = 0; its a counter to limit the number of times this thread runs. while (count < 4) {, the while checks the counter. Thread.sleep(10000); the thread sleep for 10 seconds, remember the parameter of the sleep is in miliseconds. access(new Runnable() { using the access block to lock the UI. layout.addComponent(new Label(qg.getQuote())); adds a new Label with a random quote every time it runs. count++; Update the counter. After the thread have added 4 labels it exits from the while and add a last label to show to the user that it finish layout.addComponent(new Label("No more messages for you !")); with no more messages.

5.5 The init method

Init Method

	@Override
	protected void init(VaadinRequest request) {
		qg = new QuoteGenerator();
		layout = new VerticalLayout();
		layout.setMargin(true);
		setContent(layout);
		theTime = new Label();
		theTime.setValue("Its now : " + Instant.now());
		layout.addComponent(theTime);
		new MyFirsthThread().start();
		new MySecondThread2().start();
	}

In the init method first create the random quote generator instance qg = new QuoteGenerator();. Then create the layout layout = new VerticalLayout();. Create the label to hold the time theTime = new Label();. Start the first thread new MyFirsthThread().start(); and start the second thread new MySecondThread2().start();.

6. The complete source code

QuoteGenerator.java

package com.example.vaadinserverpush;

import java.util.Random;

public class QuoteGenerator {
	private String[] quotes = new String[20];

	public QuoteGenerator (){
		quotes[0] = "A friend asks only for your time not your money.";
		quotes[1] = "Your high-minded principles spell success.";
		quotes[2] = "Enjoy the good luck a companion brings you.";
		quotes[3] = "Hidden in a valley beside an open stream- This will be the type of place where you will find your dream.";
		quotes[4] = "What ever you're goal is in life, embrace it visualize it, and for it will be yours.";
		quotes[5] = "You will become great if you believe in yourself.";
		quotes[6] = "Never give up. You're not a failure if you don't give up.";
		quotes[7] = "It is now, and in this world, that we must live.";
		quotes[8] = "Adversity is the parent of virtue.";
		quotes[9] = "A stranger, is a friend you have not spoken to yet.";
		quotes[10] = "A new voyage will fill your life with untold memories.";
		quotes[11] = "Its amazing how much good you can do if you dont care who gets the credit.";
		quotes[12] = "Stop wishing. Start doing.";
		quotes[13] = "Your fortune is as sweet as a cookie.";
		quotes[14] = "Don't pursue happiness - create it.";
		quotes[15] = "Everything happens for a reason.";
		quotes[16] = "Rivers need springs.";
		quotes[17] = "All progress occurs because people dare to be different.";
		quotes[18] = "It is not necessary to show others you have change; the change will be obvious.";
		quotes[19] = "Next full moon brings an enchanting evening.";
	}
	
	public String getQuote(){
		Random r = new Random();
		return quotes[r.nextInt(20)];
	}
}

VaadinserverpushUI.java

package com.example.vaadinserverpush;

import java.time.Instant;

import javax.servlet.annotation.WebServlet;

import com.vaadin.annotations.Push;
import com.vaadin.annotations.Theme;
import com.vaadin.annotations.VaadinServletConfiguration;
import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinServlet;
import com.vaadin.ui.Label;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;

@Push
@SuppressWarnings("serial")
@Theme("vaadinserverpush")
public class VaadinserverpushUI extends UI {

	@WebServlet(value = "/*", asyncSupported = true)
	@VaadinServletConfiguration(productionMode = false, ui = VaadinserverpushUI.class)
	public static class Servlet extends VaadinServlet {
	}

	private QuoteGenerator qg;
	private VerticalLayout layout;
	private Label theTime;
	
	@Override
	protected void init(VaadinRequest request) {
		qg = new QuoteGenerator();
		layout = new VerticalLayout();
		layout.setMargin(true);
		setContent(layout);
		theTime = new Label();
		theTime.setValue("Its now : " + Instant.now());
		layout.addComponent(theTime);
		new MyFirsthThread().start();
		new MySecondThread2().start();
	}

	class MyFirsthThread extends Thread {

	    @Override
	    public void run() {
	        try {
	            while (true) {
	        		Thread.sleep(1000);

	                access(new Runnable() {
	                    @Override
	                    public void run() {
	                		theTime.setValue("Its now : " + Instant.now());
	                    }
	                });
	            }

	        	} catch (InterruptedException e) {
	        		e.printStackTrace();
	        	}
	    }
	}

	class MySecondThread2 extends Thread {
	    int count = 0;

	    @Override
	    public void run() {
	        try {
	            while (count < 4) {
	                Thread.sleep(10000);

	                access(new Runnable() {
	                    @Override
	                    public void run() {
	                    	layout.addComponent(new Label(qg.getQuote()));
	                    	count++;
	                    }
	                });
	            }

	            access(new Runnable() {
	                @Override
	                public void run() {
	                    layout.addComponent(new Label("No more messages for you !"));
	                }
	            });
	        } catch (InterruptedException e) {
	            e.printStackTrace();
	        }
	    }
	}	
	
}

7. Running the example

Right click on the project folder and choose Run as -> Run on server choose Tomcat 8 server and hit finish.

8. Results

Open your application in a browser and fire Up the developer tools CTRL+SHIFT+i shortcut in most browsers, you should see something like the following image, go to the console tab:

04 Browser developer tools
04 Browser developer tools

Let’s run the application and examine the console output to see whats Vaadin doing under the hood.

05 Running the example
05 Running the example

After running the application for a while you get a lot of messages lets filter these messages to get only the server push messages.

First you get a update time message every second:

Time update

Mon Apr 04 15:47:05 GMT-430 2016 com.vaadin.client.communication.AtmospherePushConnection
INFO: Received push (websocket) message: for(;;);[{"syncId": 20, "clientId": 0, "changes" : [], "state":{"34":{"text":"Its now : 2016-04-04T20:17:05.428Z"}}, "types":{"34":"1"}, "hierarchy":{}, "rpc" : [], "meta" : {"async":true}, "resources" : {}, "timings":[115, 15]}] VaadinServerPush:1:5094
Mon Apr 04 15:47:05 GMT-430 2016 com.vaadin.client.communication.MessageHandler
Mon Apr 04 15:47:06 GMT-430 2016 com.vaadin.client.communication.AtmospherePushConnection
INFO: Received push (websocket) message: for(;;);[{"syncId": 21, "clientId": 0, "changes" : [], "state":{"34":{"text":"Its now : 2016-04-04T20:17:06.429Z"}}, "types":{"34":"1"}, "hierarchy":{}, "rpc" : [], "meta" : {"async":true}, "resources" : {}, "timings":[115, 15]}] VaadinServerPush:1:5094
Mon Apr 04 15:47:06 GMT-430 2016 com.vaadin.client.communication.MessageHandler

And every 10 seconds you should get a random message:

Random Message

Mon Apr 04 15:47:06 GMT-430 2016 com.vaadin.client.communication.AtmospherePushConnection
INFO: Received push (websocket) message: for(;;);[{"syncId": 22, "clientId": 0, "changes" : [], "state":{"33":{"childData":{"34":{"alignmentBitmask":5,"expandRatio":0},"35":{"alignmentBitmask":5,"expandRatio":0},"36":{"alignmentBitmask":5,"expandRatio":0}}},"36":{"text":"Your fortune is as sweet as a cookie.","width":"100.0%"}}, "types":{"33":"2","36":"1"}, "hierarchy":{"33":["34","35","36"]}, "rpc" : [], "meta" : {"async":true}, "resources" : {}, "timings":[115, 15]}] VaadinServerPush:1:5094
Mon Apr 04 15:47:06 GMT-430 2016 com.vaadin.client.communication.MessageHandler
Mon Apr 04 15:47:16 GMT-430 2016 com.vaadin.client.communication.AtmospherePushConnection
INFO: Received push (websocket) message: for(;;);[{"syncId": 33, "clientId": 0, "changes" : [], "state":{"33":{"childData":{"34":{"alignmentBitmask":5,"expandRatio":0},"35":{"alignmentBitmask":5,"expandRatio":0},"36":{"alignmentBitmask":5,"expandRatio":0},"37":{"alignmentBitmask":5,"expandRatio":0}}},"37":{"text":"A new voyage will fill your life with untold memories.","width":"100.0%"}}, "types":{"33":"2","37":"1"}, "hierarchy":{"33":["34","35","36","37"]}, "rpc" : [], "meta" : {"async":true}, "resources" : {}, "timings":[115, 15]}] VaadinServerPush:1:5094
Mon Apr 04 15:47:16 GMT-430 2016 com.vaadin.client.communication.MessageHandler
Mon Apr 04 15:47:26 GMT-430 2016 com.vaadin.client.communication.AtmospherePushConnection
INFO: Received push (websocket) message: for(;;);[{"syncId": 44, "clientId": 0, "changes" : [], "state":{"33":{"childData":{"34":{"alignmentBitmask":5,"expandRatio":0},"35":{"alignmentBitmask":5,"expandRatio":0},"36":{"alignmentBitmask":5,"expandRatio":0},"37":{"alignmentBitmask":5,"expandRatio":0},"38":{"alignmentBitmask":5,"expandRatio":0}}},"38":{"text":"A new voyage will fill your life with untold memories.","width":"100.0%"}}, "types":{"33":"2","38":"1"}, "hierarchy":{"33":["34","35","36","37","38"]}, "rpc" : [], "meta" : {"async":true}, "resources" : {}, "timings":[115, 15]}] VaadinServerPush:1:5094
Mon Apr 04 15:47:26 GMT-430 2016 com.vaadin.client.communication.MessageHandler
Mon Apr 04 15:47:26 GMT-430 2016 com.vaadin.client.communication.AtmospherePushConnection
INFO: Received push (websocket) message: for(;;);[{"syncId": 45, "clientId": 0, "changes" : [], "state":{"33":{"childData":{"34":{"alignmentBitmask":5,"expandRatio":0},"35":{"alignmentBitmask":5,"expandRatio":0},"36":{"alignmentBitmask":5,"expandRatio":0},"37":{"alignmentBitmask":5,"expandRatio":0},"38":{"alignmentBitmask":5,"expandRatio":0},"39":{"alignmentBitmask":5,"expandRatio":0}}},"39":{"text":"No more messages for you !","width":"100.0%"}}, "types":{"33":"2","39":"1"}, "hierarchy":{"33":["34","35","36","37","38","39"]}, "rpc" : [], "meta" : {"async":true}, "resources" : {}, "timings":[115, 15]}] VaadinServerPush:1:5094
Mon Apr 04 15:47:26 GMT-430 2016 com.vaadin.client.communication.MessageHandler

Let’s see this in detail. For every message you get:

com.vaadin.client.communication.AtmospherePushConnection Vaadin uses the Atmosphere framework to manage server push, Atmosphere is a framework that that include a mix of WebSocket, Comet and RESTful behavior.

Also you get: INFO: Received push (websocket) message: that is telling you that the webapplication is receiving server push messages.

Now we are sure that Vaadin is using server push to update our page.

9. Download the Source Code

This was an example of Vaadin Server Push.

Download
You can download the Eclipse project here: VaadinServerPush

Jesus Boadas

I'm a self taught programmer, I began programming back in 1991 using an IBM A10 mainframe with Pascal an Assembler IBM 360/70 emulator and Turbo C on a X86 PC, since that I work for the banking industry with emerging technologies like Fox Pro, Visual Fox Pro, Visual Basic, Visual C++, Borland C++, lately I moved out to the Airline industry, leading designing and programming in-house web applications with Flex, Actionscript, PHP, Python and Rails and in the last 7 years I focused all my work in Java, working on Linux servers using GlassFish, TomCat, Apache and MySql.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Mario
Mario
4 years ago

your solution will acumulate an “infinite” amount of threads over time. each page refresh/visit will start a new MyFirstThread instance and never stops it.

Back to top button