MongoDB , Angular.js and Vertx-Web -Rest Services

Madanasekaran.P

Reactive frameworks are becoming main-stream, because of “C10K” problem- explosion in the number of mobile clients and the need for better scalability and low latency. Have a look at figure-1 below. This is a typical layered architecture in Enterprise applications. We can replace synchronous Servlet based Application layer with Reactive frameworks like Node.js or Vertx or Async Servlet in the middle tier. Now there is a choice for Presentation and Database also. Mostly JavaScript-based frameworks/libraries are used in Presentation layer. In back-end, we can either use a Relational DB or MongoDB. We are not adopting a new programming paradigm and it is easy for a Java programmer to adopt these technologies.Spring5 is expected to become reactive. Project Reactor is another reactive framework from Spring Source. Quasar is a reactive framework which allows the programmer to write blocking synchronous code that will block only a fiber, a light-weight thread and not the OS thread. We may see them when enough material is made available on them. To use a full-fledged actor model –Erlang, or Akka, as we have seen our article on Erlang and Akka, a mental shift is required. That is a new paradigm and a new language Erlang/Scala. When a programmer uses the Quasar/Comsat implementations for Java APIs using “fiber” in place of thread, he can use the familiar synchronous code. This is similar to Async in C# and Scala, about which we have seen earlier. Comsat lets you write the familiar(fiber) blocking code for Java Web APIs and uses Quasar for invoking  call-back code and enjoy the scalability provided by asynchronous APIs. Quasar does not seem to have drawn much attention from the Java Programming community, though it is coded in Java and has Erlang- like actors and Go –like channels, implemented on top of fibers. It appears to be good alternative to Akka which is coded in Scala. For an ordinary Java programmer Vertx, which got the most innovative JAX award for Java technology, in 2014 is a good option, as it can easily replace existing technologies in the Enterprise stack. Vertx does not use existing Java Web and EE APIs and rather builds on Java NIO and Netty. It may become more popular, as it is backed by JBoss/RedHat.

Verticle behaves like a  controller:

Vertx implements Event-driven model of Node.js. But it uses actor- like Verticle as a deployment unit. That is, a Verticle is using messages as a means of communication to communicate with other Verticles and it is deployed as a single unit though it groups together many related events and event-handlers. This enables Vertx to utilize more than one Event-Loop as against the single Event loop in Node.js -multi-reactor as against reactor pattern and scale better. But the code in our present Verticle ( in the sample below) resembles more the controller, we have earlier seen in MVC frameworks, than an actor. To the Java users RequestMappings and their corresponding Actions are not new and they become routes and handlers in a Verticle. What is new is container-less deployment and absence of configuration files either in Xml or Java. The Verticle itself contains some configuration information. Even, container-less deployment has some similarity to the use of embedded Jetty/TomCat. What separates Vertx from traditional MVC frameworks are: 1)The scalability achieved through use of asynchronous APIs 2) the concurrency achieved through the facility to specify the number of instances to be deployed when you run a verticle. Like Express(from Node.js), Vertx-Web is just a module; one can easily use Express or Vertx-web in place of traditional Servlet-based frameworks for creating HTTP web applications or Rest Services  for their container-less deployment, scalability and the simple concurrency mentioned above. For soft real time applications Vertx is very scalable with its multi-reactor pattern, EventBus and Messages ; but it  does not have a full-fledged supervisory hierarchy as in Erlang or Akka for Error Recovery, though there is some support. You can give –ha (High Availability) option when you run a Verticle. When you run your verticles with high availability (HA) support, if a running a verticle dies abruptly, the verticle is migrated to another vertx instance in the same cluster.

Light-weight programming model and simpler deployment:   Vertx is very light-weight. Its size 830 KB and Vertx-web is 445 KB. It is easy to get going with practically no configuration. Like Node.js it provides methods to create and use HTTP server in a few lines within the application code. No need to deploy it on a preconfigured server. This simplified development model is an attraction of Vertx and Node.js, apart from their scalability. Their web modules Express and Vertx-web are fit for creating any type of web application - an HTTP/REST service, or a HTTP web application, or WEB-Socket / real-time server push app. Their size is very small when compared to Play, another reactive framework- whose size is more than 100 MBs- or the traditional MVC frameworks like Spring MVC or Struts. Yet they provide all the features you expect from an advanced web framework: for example cookies, session handling, pluggable auth, templating, websockets, support for SockJS, content negotiation.Vertx-3  packages the application and the dependencies/ environment as a jar, which can run be on any machine where Java is installed. The permanent TCP connection in Web-socket better suits the non-blocking event-driven programming model of these frameworks than the traditional Java servers, where some threads are permanently blocked waiting for some message in these connections that remain idle for most of the times. Hence the performance of Web-socket technology in the reactive frameworks is better than their counterparts in blocking JEE/Spring. This makes them more suitable for Soft Real-time apps where scalability and low latency are important.

Technogies used in the sample : In the earlier articles, we saw the use of Vertx-web in creating a HTTP RESTful self-contained service. In a number of articles we have used Angular.js Clients for REST services from different platforms -JEE, ASP Net Web API, Node.js and Vertx-web. Being a SPA, it is suitable to be used as the client for such services. Now we will add to the above app, MongoDB to store and retrieve data for our REST service. In functionality our app will resemble a traditional rest service but it can be easily created and deployed wherever you want and will scale better. MongoDB is a great match for persisting data in a Node.js or a Vert.x application, as it natively handles JSON (BSON) documents. It is the most popular NoSQL database and has drivers for many languages. Its official Java driver has both synchronous and asynchronous APIs. But the advantage of “vertx-mongodb-client” module, which we are going to use, is that it supports all the languages that Vert.x supports while the official Mongo async driver supports Java only. We will see the features of mongo-client below:

Features of mongo-client

  • Completely non-blocking
  • Supports direct serialization to/from Vert.x JSON
  • Supports a majority of the configuration options from the MongoDB Java Driver

 

MongoClient is asynchronous and non-blocking .To a call, it returns immediately and releases the Event-loop thread. When the result arrives the handler is invoked by the same event-loop thread. This model avoids the synchronization pitfalls. As our code is only called by a single thread, there is no need to synchronize anything. 

By deploying multiple instances of your verticle, you can scale your application. If you want each verticle instance to share the same pool and say no to multiple pools, use a command like this:
MongoClient client = MongoClient.createShared(vertx, config);

The first call to MongoClient.createShared will actually create the pool, and the specified config will be used.

Sample : The functionality provided resembles a “traditional  Rest service”; but the technology is entirely different; except that it uses  Java and JVM  there is no another resemblance. Vertx does not implement any JCP standard or use any JEE compliant server or web server ; there is no need for any configuration file  in XML or in Java . The Java file can be run on the fly without any pre-compilation by vertx run time.
We are using Maven to distribute our app as a jar and “to do things in a way most Java developers would expect”. We will use the generated “pom” and modified as mentioned in the earlier article. Now we will add the dependency for mongo and Maven will download it. The full “pom” file is given below:

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

  <groupId>io.vertx</groupId> <artifactId>AngWebMongo</artifactId> <version>1.0-SNAPSHOT</version>

  <dependencyManagement> <dependencies> <dependency> <groupId>io.vertx</groupId> <artifactId>vertx-dependencies</artifactId> <version>3.1.0</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>

  <dependencies> <dependency> <groupId>io.vertx</groupId> <artifactId>vertx-core</artifactId> </dependency> <dependency> <groupId>io.vertx</groupId> <artifactId>vertx-web</artifactId>

     <dependency>       <groupId>io.vertx</groupId>       <artifactId>vertx-mongo-client</artifactId>  /* now added */      </dependency>   </dependencies>
  <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.3</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId>
<version>2.3</version> <executions> <execution> <phase>package</phase>
<goals> <goal>shade</goal> </goals> <configuration> <transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<manifestEntries> <Main-Class>io.vertx.core.Starter</Main-Class> <Main-Verticle>io.vertx.angwebmongo.Main</Main-Verticle> </manifestEntries> </transformer> <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/services/io.vertx.core.spi.VerticleFactory</resource> </transformer> </transformers>
<artifactSet></artifactSet> <outputFile>${project.build.directory}/AngWebMongo-${project.version}-fat.jar</outputFile>
</configuration> </execution> </executions> </plugin> </plugins> </build>

</project>

It is repeated that it is mostly generated code which was slightly modified, as detailed in the earlier article “Angular.js + Vertx web Rest Services”. The dependency now added is given in red.

Data/Model

You know Java has no native support for JSON. You have to rely on open source libraries such as Jackson for conversion. Vertx is basically a polyglot framework. So it prefers JSON, which can be used in any language, when data has to be passed between its different components. Vertx comes with some Convenience classes built on top of Jackson - JSON and JsonObject classes. Passing our Java objects to the methods in those classes we can get JSON and vice-versa. As MongoDB stores documents as BSON(binary SON) and Mongo-client accepts and returns data as JSON, this should work well. The necessary changes are made in the domain class/POJO “Book”, as our code has to send JSON to Mongo-client, which it directly serializes. A few more constructors and methods to convert the java object “Book” to JSON and vice-versa have been added. The code for the same is given below:

Book.java

package io.vertx.sample.ang;

import io.vertx.core.json.JsonObject;

public class Book {   // does not implement serializable as the
mongo-client serializes automatically 1)
private String id;  // id changed from Integer to String

private String title;
private String author; public Book(String title, String author) { this.id = ""; this.title = title; this.author = author; }

  public Book(JsonObject json) {  // a constructor taking JSONObject as argument this.title = json.getString("title"); this.author = json.getString("author"); this.id=json.getString("_id"); }
public Book(){   // another constructor added now this.id=""; }
public Book(String id, String title, String auhor){ this.id=id; this.title= title; this.author = author; }
// method added for conversion of Book Java object into JSON to be sent to mongo-client public JsonObject toJson() {     JsonObject json = new JsonObject() .put("title", title) .put("author", author); if (id != null && !id.isEmpty()) { json.put("_id", id); }
return json; }

  public String getTitle() { return title; }

  public String getAuthor() { return author; }

  public String getId() { return id; }

  public void setTitle(String title) { this.title = title; }

  public void setAuthor(String author) { this.author = author;

  }
//method not only sets id but also returns a Book object
public Book setId(String id){ this.id =id; return this; } }

  1. Destructive database operations like Write or Update requires to be serialized and Entity classes (in Hibernate or JPA) will implement Serializable. As mongo-client takes care of serialization, our data class does not implement it.

MyVerticle.java

As mentioned above, a Verticle behaves like a controller in Servlet-based traditional MVC frameworks like Spring MVC; but as mentioned above, in Vertx no implementation for any JCP specification or server or configuration file is used. Vertx is built on NIO and Netty and not on Servlet and hence Concurrency and performance distinguish it. Remember the following before going to the actual code. The methods from Java classes in both Vertx-core and Vertx-web modules are used. From core 1) AbstractVerticle class is extended.Its start() method is overidden and all our code is put in it .Within our code, the following methods in the core-classes are chained to create and start the server and enable it to handle various types of  Requests.

1)CreateHttpServer() – no argument
2) requestHandler() – argument, the accept () method which takes a Router object from vertx-web
3) listen()that takes port number and starts the server.

In Struts or Spring MVC requests are mappped to “various actions” in the Controller .Here requests/routes  are mapped to handlers in the Verticle. Routes and handlers from vertx-web are used for the purpose. Routes and their  handlers are attached to Router object and the Router is passed to the accept() method in Vertx-core.Have a look at the figure below: 

Apart from the above, the following methods from mongoClient are also invoked to interact with MongoDB : 1) createShared 2) insert 3) find. We will see about them in the course of this article. If you want, you can put this code in a separate DAO/Repository file.
The code for “MyVerticle.java” is given below. If you compare it to the earlier code, you can see now an asynchronous version of start() is used, as we are using mongo-client which is asynchronous. You can see the use of Future here. Vertx, in addition to callbacks, uses Futures also for asynchronous Programming.

MyVerticle.java

package io.vertx.sample.ang;

import io.vertx.core.AbstractVerticle; import io.vertx.core.Future; import io.vertx.core.http.HttpServerResponse; import io.vertx.core.json.Json; import io.vertx.core.json.JsonObject; import io.vertx.ext.web.Router; import io.vertx.ext.web.RoutingContext; import io.vertx.ext.web.handler.BodyHandler; import io.vertx.ext.web.handler.StaticHandler;
import io.vertx.ext.mongo.MongoClient;

import java.util.LinkedHashMap; import java.util.Map; import java.util.List; import java.util.stream.Collectors;

public class MyVerticle extends AbstractVerticle {

// Collection Name in MongoDB public static final String COLLECTION = "books";

  private MongoClient mongo;

public static void main(String[] args) { Vertx vertx = Vertx.vertx(); vertx.deployVerticle(new Main());  // the verticle is deployed in main() }

/** an asynchronous start(). This method is called when the verticle is deployed. It creates a
HTTP server and registers a simple request handler.  The `listen` method passes a lambda,
checking the port binding result. When the HTTP server has been bound on the
port, it calls the `complete` method to inform that the starting has
completed. Else it reports the error. */
@Override public void start(Future<Void> fut) {

// shared pool discussed above mongo = MongoClient.createShared(vertx, config());

    // Create a router object passing vertx and attach handlers for different routes/requests Router router = Router.router(vertx);

    // Bind "/" to our hello message. Just to show that our application is working
router.route("/").handler(routingContext -> { HttpServerResponse response = routingContext.response(); response .putHeader("content-type", "text/html") .end("<h1>Hello from my first Vert.x 3 application</h1>"); });

    router.route("/assets/*").handler(StaticHandler.create("assets"));
    router.get("/api/books").handler(this::getAll); router.route("/api/books*").handler(BodyHandler.create()); router.post("/api/books").handler(this::addOne);

    // Create the HTTP server and pass the "accept" method to the request handler.
vertx .createHttpServer() .requestHandler(router::accept) .listen( // Retrieve the port from the configuration, // default to 8080.
config().getInteger("http.port", 8080), result -> { if (result.succeeded()) { fut.complete(); } else {
fut.fail(result.cause()); } } ); }
//handler for POST route private void addOne(RoutingContext routingContext) { // Read the request's content and create an instance of Book. final Book book = Json.decodeValue(routingContext.getBodyAsString(), Book.class);
// In mongoDB you have to insert only a JSON document to a Collection-here books
mongo.insert(COLLECTION, book.toJson(), r ->

    routingContext.response()
.setStatusCode(201) .putHeader("content-type", "application/json; charset=utf-8") .end(Json.encodePrettily(book.setId(r.result()))));    //--------1) }

//handler for GET route private void getAll(RoutingContext routingContext) { mongo.find(COLLECTION, new JsonObject(), results -> {   //--------2) List<JsonObject> objects = results.result();  //--------3) List<Book> books = objects.stream().map(Book::new).collect(Collectors.toList());  //----4) routingContext.response() .putHeader("content-type", "application/json; charset=utf-8") .end(Json.encodePrettily(books));  //----------5) }); }

}

  1. Though Book class has an Id property, the JSonObject inserted to with MongoClient  has no id field. Hence the id field generated by MongoDB will be returned to the result handler. The handler gets the AsyncResult <String> and passes it to the setId() in the Book class. This method accepts a String id and returns a Book object.
  2. See the use of “{}” when the body of the lambda contains more than one statement separated by “;”.
  3. The find() returns  AsyncResult of a List of JSONObject. From this list we can create our Book instances, and fill the HTTP response with this set.  
  4. To Json.encodePrettily(), we passing List of books. 

In Java-8 and in any Functional language Stream is a tool for internal iteration and other complex operations on collections using a functional approach. 

In Java8 or in Functional languages in general, Stream is a tool for internal iteration and for complex operations on collections using a functional approach. Clients that use an external iterator must advance the traversal and request the next element explicitly from the iterator. In contrast, the client hands an internal iterator,  an operation to perform, and the iterator applies that operation to every element in the collection. Languages with support for closures/lambdas (such as Scala and Ruby) usually provide support for looping over their collections using internal iterators , while other object-oriented languages (such as C++, Java, and C#) tend to use external iterators. Now as Java-8 has become a Functional language, internal iteration as been provided. Because this iterator implementation doesn't have to explicitly store and manage the state of the iteration the code can be easily parallelized.

Coming to our code, a stream is created out of the List of source-here JSONObject, using the stream() method and the pipeline set up. In the Pipeline the output of one method becomes the input for another. Had you used pipes in Unix, Linux or Scala you would know a number of method calls are chained in a pipeline. Here the output of stream() becomes the input for map(). Map takes one type of stream and returns another type of stream using the function passed to it. Here the map() is passed a method reference. Both stream () and map are lazy. ie Evaluation of data is postponed. The final result is collected using the collect() method. Collect(toList()) is an eager operation that generates a list from the values in a Stream. Many Stream functions are lazy; you need an eager operation such as collect at the end of a sequence of chained method calls.

Configuraion

Look at the size of the only configuration file we use; that too in JSON and for providing connection parameters to MongoDB. The file is given below:

Conf/my-appication-conf.json

{ "http.port": 8083, "db_name": "test", "connection_string": "mongodb://localhost:27017" }

Index.html

The code for index.html is given below. This is the same code used earlier.

resources/assets/index.html

<html ng-app="booksApp">

<head> <title>Vertx-Angular </title> <style> .item { padding: 10px; } </style> </head>

<body ng-controller="MainCtrl as mainCtrl"> <h1>Angular-vertx-App!</h1> <div ng-repeat="book in mainCtrl.items" class="item"> <div><span ng-bind="book.title"></span></div> <div><span ng-bind="book.author"></span></div>
</div>

  <div>
<form name="addForm" ng-submit="mainCtrl.add()"> <input type="text" placeholder="Title" ng-model="mainCtrl.newBook.title" required>
<input type="text" placeholder="Author" ng-model="mainCtrl.newBook.author" required>
<input type="submit" value="Add" ng-disabled="addForm.$invalid"> </form> </div>

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.11/angular.js">
</script> <script> angular.module('booksApp', []) .controller('MainCtrl', ['$http', function($http) { var self = this;
self.items = []; self.newBook = {}; var fetchBooks = function() { return $http.get('/api/books').then( function(response) { self.items = response.data; }, function(errResponse) { console.error('Error while fetching '); }); };

      fetchBooks();
      self.add = function() { $http.post('/api/books', self.newBook) .then(fetchBooks) .then(function(response) { self.newBook = {}; }); };

    }]);
</script> </body> </html>


Build and Run

Ensure that the MongoDB in your system is running. In the command prompt go to “MongoDB\bin” and execute
“mongod –dbpath E:data(where you created data folder)
When you get the message waiting for connections on port 27017,
You can build a fat.jar and run it as mentioned in the earlier article. The Browser will appear as shown below:


After inserting a record it may appear as under:

 

 

Conclusion

MongoDB is the leading “NoSQL” database and considered good for use as a primary data store for web applications. It stores data as BSON-binary JSON. Though there is no native support for JSON in Java, Vertx provides support through some convenience classes built upon “Jackson”, an open source library. Mongo-client directly serializes JSON. Mongo-client is a “non-blocking” module and fits well with the Vertx philosophy.  We saw how to use the vertx-mongo-client to access asynchronously data stored inside a mongo database as well as inserting this data. The Verticle is the deployment unit in Vertx. Vertx-web has renounced the synchronous Servlet model in favor of asynchronous event-driven model. Because of its container-less deployment, it could package the application and the dependencies as a jar which can be run on any machine where Java is installed (for this sample- and also MongoDB server is running). Maven is used to build and package in Vertx-3 with an intention “to do things in a way most Java developers would expect”. But no application server or web server is required and people like Eberhard Wolff have gone to the extent of pronouncing “Java application servers are dead!”. One may ask about the absence of EventBus and Messages in our rest service. These are features that distinguish Vertx from Node.js and are used only when more than one verticle communicate among themselves or we want to make our http app, a soft real time/server push application -see Server.java in angular_realtime in vertx-examples-master\web-examples. We will see a soft real time app later and in our present http rest service we have used only callbacks. These callbacks, container-less deployment and practically no configuration distinguish our Vertx app from traditional, say Spring MVC, Rest service. The programming model is the same, but no implementation of any JCP standard is used. Only asynchronous APIs built on top of NIO classes and Netty are used. Play also is similarly built on top of Netty; but it is a separate framework and it takes some efforts to integrate it with Akka and use Scala-the Typesafe  stack.

Critics call this use of callbacks as pyramid of doom or callback hell. Richard Warburton author of the book “Java8 Lambdas” observers If you write code with lots of callbacks, it becomes very hard to read, even with lambda expressions. The more operations you want to chain or compose, the worse this problem gets”. Chaining or composing is a feature of functional programming style that avoids intermediate/mutable variables to store the result of every function call, as the output of one function becomes input for another function in the pipeline. Callbacks are features of asynchronous programming. Within a function, the block of code to be executed later after some event-happens, has to be furnished somewhere. If not in callbacks, you have to furnish them in Futures. Futures are syntactic sugar for callbacks. There is another module “Vertx-sync” which allows you to work with asynchronous APIs, but using a direct synchronous style/imperative program style that you’re already familiar with. . Vertx-sync uses Quasar to provide the functionality. You can code using imperative synchronous fiber blocking APIs provided by the Quasar, but built on top of asynchronous call-backs. It is for the framework to invoke this asynchronous callback code and provide the required functionality. Fibers are very lightweight threads that do not correspond to underlying kernel threads. When they are blocked, they do not block a kernel thread. We will see more about it later.








}