Core Java

Real-time Applications with AngularJS and Java – Part 1

1. Introduction

In 2015, is it still acceptable to develop web applications in which we have to hit F5 to actualize the page content? The answer is simple: Of course yes! But still, we can offer our users a better overall experience. I could ask myself: How comes Twitter or Facebook are able to notify me when I have new interactions or messages, but the software I use at my job is not? This is where the real-time applications get on stage.

This article is the first of a series of three in which I want to introduce you the basic concepts behind real-time applications in Java with simple examples.  In this first article, I will demonstrate how GMail, Facebook, Twitter and many other websites have implemented real-time notifications using the periodic refresh design pattern.

angularjs_small

AngularJS Programming Cookbook

In this ebook, we provide a compilation of AngularJS based examples that will help you kick-start your own web projects. We cover a wide range of topics, from Single Page Apps and Routing, to Data Binding and JSON Fetching. With our straightforward tutorials, you will be able to get your own projects up and running in minimum time. Download the cookbook by joining the Web Code Geeks Newsletter.

In this example, I will be showing you how real-time updates can be useful in a system where the users execute tasks that take time to run (import of CSV files into the system, copy of files from server to server, batch update in the database, etc.). AngularJS will be used in the front end to implement the Periodic Refresh pattern. Spring and Jackson will be used together to create a RESTful JSON Web Service answering the AJAX request made by Angular. If you do not know about AngularJS or Spring MVC, I would suggest you read tutorials before. Here is a screenshot of the end result:

Figure 1. Screenshot of the end result
Figure 1. Screenshot of the end result

2. The Periodic Refresh AJAX pattern

The Periodic Refresh pattern or polling is the simplest way of creating a real-time application. Basically, a JavaScript function periodically creates an XMLHttpRequest that is sent to the server. This request asks the server for updated information, then the view is actualized if necessary.

Figure 2. ClientServerBlank_PeriodicRefresh
Figure 2. ClientServerBlank_PeriodicRefresh

You can easily see this pattern in action in your Twitter feed. In any modern browser, hit F12, go to the Network tab and filter the requests so only XHR are displayed. Every 10 seconds or so, a new request is sent to the server asking for an update regarding new tweets. If there is any, a notification is displayed.

Figure 3. TwitterPeriodicRefresh
Figure 3. TwitterPeriodicRefresh

3. RESTful JSON Java Back-end

3.1. Maven dependencies

In order to create a simple REST web service that will accept and answer JSON objects, you have to include Spring MVC and Jackson. Your pom.xml file should contain the following dependencies:

pom.xml

 <dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-core</artifactId>
  <version>4.2.1.RELEASE</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-webmvc</artifactId>
  <version>4.2.1.RELEASE</version>
</dependency>
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.6.1</version>
</dependency>
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.1.0</version>
</dependency>

3.2. The Task object

Then, we want to create our Task object that will be used in the web service. This Task object has a duration in milliseconds and a status that can either be IDLE, RUNNING or SUCCESS.

Task.java

public class Task {
  private TaskStatus status = TaskStatus.IDLE;
  private long duration;

  // Getters and Setters...

  public void decrementDuration() {
    this.duration--;
  }

  public boolean isRunning() {
    return this.status.equals(TaskStatus.RUNNING);
  }
  
  public String getName() {
    return this.toString();
  }

  public void start() {
    this.status = TaskStatus.RUNNING;
  }
}

3.3. The TaskExecutor

Those Task objects, once instanciated, will be managed by a class called TaskExecutor. This class is a Spring Singleton that holds the tasks submitted by all users. Once it’s instanciated, it starts a thread that loops through the running tasks in the tasks pool and decrement their duration. When the duration gets to zero, the status is set to SUCCESS:

TaskExecutor.java

package com.javacodegeeks.examples.realtimeapp.part1.services;

import java.util.LinkedList;
import java.util.List;

import javax.annotation.PostConstruct;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import com.javacodegeeks.examples.realtimeapp.part1.domain.Task;
import com.javacodegeeks.examples.realtimeapp.part1.domain.TaskStatus;

@Component
@Scope("singleton")
public class TaskExecutor {
  private List pool = new LinkedList<>();
  
  @PostConstruct
  public void initialize() {
    Runnable taskPoolConsumer = () -> {
      while (true) {
        try {
          this.pool.stream()
              .filter(task -> task.isRunning() && task.getDuration() > 0)
              .forEach(task -> task.decrementDuration());
          
          this.pool.stream()
            .filter(task -> task.isRunning() && task.getDuration() == 0)
            .forEach(task -> task.setStatus(TaskStatus.SUCCESS));

          Thread.sleep(1000);
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
    };
    
    new Thread(taskPoolConsumer).start();
  }
  
  public void startAllTasks() throws InterruptedException {
    this.pool.stream().forEach(task -> task.start());  
  }

  public List getPool() {
    return this.pool;
  }

  public void addTask(Task taskToAdd) {
    this.pool.add(taskToAdd);
  }

}

3.4 The Web Service

To create the web service, we will be using the @RestController annotation from Spring. This web service will be mapped to "/api/task" and will answer POST and GET requests.

TaskService.java

@RestController
@RequestMapping("/api/task")
public class TaskService {
  @Autowired
  private TaskExecutor taskExecutor;
  
  @RequestMapping(method = RequestMethod.GET)
  public List getTasks() {
    return this.taskExecutor.getPool();
  }
  
  @RequestMapping(method = RequestMethod.POST)
  public void addTask(@RequestBody Task taskToAdd) {
    this.taskExecutor.addTask(taskToAdd);
  }
  
  public void startIdleTasks() throws InterruptedException {
    this.taskExecutor.startAllTasks();
  }
  
}

3.5 The ManagedBean to start the tasks

Finally, we have a managed bean of JSF to execute the code behind the last button.

TaskController.java

@ManagedBean(name = "taskController", eager=true)
@Component
@RequestScoped
public class TaskController {
  @Autowired
  private TaskService taskService;
  
  public void startTasks(ActionEvent event) throws InterruptedException {
    this.taskService.startIdleTasks();
  }
  
}

4. Front-end implementation with AngularJS

First, you want to create your module, then your controller. In the end result screenshot above, our controller will manage the first three buttons (Add Task, Refresh Tasks and Activate Auto Refresh). The last button is a JSF button managed by a backing bean.

index.xhtml

var part1 = angular.module("part1", []);
part1.controller("RealtimeCtrl", function($scope, $http, $timeout) {
  $scope.tasks = [];
  
  $scope.addTask = function() {
    $http.post("api/task", $scope.task);
  }
  
  $scope.getTasks = function() {
    $http.get("api/task")
      .success(function(data) {
        $scope.tasks = data;
      });
  }
  
  $scope.activateRealtime = function() {
    $scope.getTasks();
    $timeout($scope.activateRealtime, 1000);
  }
  
});

I used Angular’s dependency injection to get the $scope, $http and $timeout services. In the Angular scope, I initially set the list of tasks to an empty array which will be replaced by the tasks array returned by the web service. Now, we have our three functions. The first one is addTask() which simply creates an Ajax POST request to the server with the task object from Angular’s scope in the request data. The second function above is getTasks() which creates an Ajax GET request to the server. The server will return an array of JSON objects corresponding to the tasks registered on the server. The last but not the least function is the implementation of the real-time feel, that is a recursive function with a pause of a second that simply retrieves the tasks using the controller’s function getTask(). This is the complete index.xhtml code:

index.xhtml

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"  
    xmlns:h="http://java.sun.com/jsf/html"  
    xmlns:f="http://java.sun.com/jsf/core">
    
  <h:head>
    <title>Real-time applications - Part 1 - Java Code Geeks</title>
    <link rel="stylesheet" href="https://examples.javacodegeeks.com/wp-content/litespeed/localres/aHR0cHM6Ly9tYXhjZG4uYm9vdHN0cmFwY2RuLmNvbS8=bootstrap/3.3.5/css/bootstrap.min.css"/>
    <script src="https://examples.javacodegeeks.com/wp-content/litespeed/localres/aHR0cHM6Ly9jZG5qcy5jbG91ZGZsYXJlLmNvbS8=ajax/libs/angular.js/1.4.5/angular.min.js"></script>
    
    <script>
      var part1 = angular.module("part1", []);
      part1.controller("RealtimeCtrl", function($scope, $http, $timeout) {
        $scope.tasks = [];
        
        $scope.addTask = function() {
          $http.post("api/task", $scope.task);
        }
        
        $scope.getTasks = function() {
          $http.get("api/task")
            .success(function(data) {
              $scope.tasks = data;
            });
        }
        
        $scope.activateRealtime = function() {
          $scope.getTasks();
          $timeout($scope.activateRealtime, 1000);
        }
        
      });
      
    </script>
  </h:head>
    
  <h:body>
    <div ng-app="part1" ng-controller="RealtimeCtrl" class="container">
      <h1>Real-time application <SMALL>part 1</SMALL></h1>
      <h2>Add task</h2>
      <h:form>
        <label for="durationField">Duration (in seconds):</label>
        <input type="number" id="durationField" class="form-control" ng-model="task.duration"/>
        <button type="button" ng-click="addTask()" class="btn btn-success">Add task</button>
        <button type="button" ng-click="getTasks()" class="btn btn-default">Refresh Tasks</button>
        <button type="button" ng-click="activateRealtime()" class="btn btn-default">Activate Auto Refresh</button>
        <h:commandButton actionListener="#{taskController.startTasks}" 
            styleClass="btn btn-default"
            value="Start Idle Tasks">
          <f:ajax execute="@form"/>
        </h:commandButton>
      </h:form>
      
      <h2>Listing</h2>
      <ul class="list-group">
        <li ng-repeat="curTask in tasks" class="list-group-item {{curTask.running ? 'active' : ''}}">
          {{curTask.name}} ({{curTask.status}})<span class="badge">{{curTask.duration}}</span>
        </li>
      </ul>
    </div>
  </h:body>    
</html>

5. What’s next?

Obviously, there are tons of different ways of implementing a real-time application with the Periodic Refresh pattern. I picked AngularJS along RESTful JSON Web service because AngularJS really simplifies the update of the UI without having to refresh the page.

In the next article, I will reuse the same application but I will show you how have a better feel of the real-time application. The part 2 will be on Long Polling and the part 3 on the spanking new HTML 5 WebSocket.

6. Download the Eclipse project

This was an example of how to integrate AngularJS and Spring MVC to create an application that is updated automatically using the Periodic Refresh design pattern.

Download
You can download the full source code of this example here: Real-time part 1

Sylvain Cloutier

Sylvain has been programming in Java for the past 5 years, mainly in the aerospace industry, as a lead developer of complex web based aircraft wiring systems. He is also one of the organizers of the Java User Group of Quebec City and currently works as a Java developer consultant at CGI.
Subscribe
Notify of
guest

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

2 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Yusuf Indah
Yusuf Indah
3 years ago

Fantastic, I never knew one could combine angularjs and java in eclipse, though I have not run it but I will try
Indah Yusuf

Hassan
Hassan
2 years ago

bro thnaks

Back to top button