QBit can do north of 100 million ping pong calls per second which is very fast, and it is also very easy to use. QBit enables you to build applications hassle free, can server up non-JSON resources, and allows you to bind objects to HTTP ports so that they can be called by REST and WebSocket clients. All this will be demonstrated in this simple TODO List example.
To demonstrate how easy it is to build a single page application with QBit, we will server up on http://localhost:9999/ui/index.html a simple TODO LIST app that will look as the following:
TODO List app with QBit |
With this app you will be able to add tasks to your todo list by typing them in the text box and hitting return on your keyboard, delete tasks by double clicking it, and draw a line through the task or change its status by checking the box next to it.
How to build it?
This app consists of four parts TodoObject.java, TodoService.java, TodoRestServer.java, and index.html. We will go over each one.
TodoObect.java is just a java object that holds the current time in milli seconds, as you will see later this object will be used to retrieve from it a unique id number for each todo item added, which will enable us to add, delete, and change the status of each task on the todo list.
package io.advantageous.qbit.example.todolistapp; /** * Created by rhightower on 2/10/15. */ public class TodoObject { //private final String todo; private final long time = System.currentTimeMillis(); // public TodoObject(String todo) { // this.todo = todo; // } }
TodoService.java has annotations to enable us to call it via (REST/HTTP/GET) and get back some JSON, in this case we will get a new TodoObject every time it is called.
package io.advantageous.qbit.example.todolistapp; import io.advantageous.qbit.annotation.*; /** * Created by rhightower on 2/10/15. */ @RequestMapping("/todoservice") public class TodoService { @RequestMapping("/todoo") public TodoObject list() { return new TodoObject(); } }
index.html holds the code for the todo list. It consists of html, css, and javascript.
Each time we add a new item to the todo list we call TodoService to get a TodoObject (remember TodoObect holds the current time in milli seconds), then parse it into a JSON, then assign the id variable to time. This id variable will be a unique id for each item added to the list.
Please note in this example to keep things simple, requests are synchronous, in a real scenario we should do asynchronous requests to prevent the executions from blocking and gumming up the performance of the app.
<script> .......... function httpGet(theUrl) { var xmlHttp = null; xmlHttp = new XMLHttpRequest(); xmlHttp.open( "GET", theUrl, false ); xmlHttp.send( null ); return xmlHttp.responseText; } ............... // getiing the id from TodoService var json = httpGet("/services/todoservice/todoo"); var date = JSON.parse(json); var id = date.time; ........... </script>
id variable will also be used for deleting an item and changing its status:
function removeItem() { //var listId = this.id.replace("li_", ""); document.getElementById(this.id).style.display = "none"; } function itemStatus() { var checkboxId = this.id.replace("idc_", ""); var itemContent = document.getElementById("ids_" + checkboxId); if (this.checked){ itemContent.className = "check"; }else { itemContent.className = ""; }
<style> body { background-color: #D8D8D8; } h1 { text-align: center; } ul { list-style-type: none; padding: 20px; margin: 0px; } li { background: #CCFF00; font-size: 30px; border: 2px solid #000; padding: 10px 20px; color: #000; cursor: cell; } li span { padding: 10px; cursor: cell; } .check { text-decoration: line-through; font-weight: bold; color:#000; } #enteritem { font-size: 30px; border: 2px solid #000; padding: 0; margin: 0; </style>
The interesting part of this example is the part where we server up this TODO List app on http://localhost:9999/ui/index.html; with QBit it is very easy:
-First create a QBit System Manager to manage the shutdown:
/* Create the system manager to manage the shutdown. */ QBitSystemManager systemManager = new QBitSystemManager();
-Create a Http server and set its port number to 9999
HttpServer httpServer = httpServerBuilder() .setPort(9999).build();
-Using java 8 lambda expression register the predicates, if the path entered in the browser matches the path of ~/index.html then read the resources of index.html and send it to the browser.
/* Register the Predicate using a Java 8 lambda expression. */ httpServer.setShouldContinueHttpRequest(httpRequest -> { /* If not the page uri we want to then just continue by returning true. */ if (!httpRequest.getUri().equals(HTML_PAGE)) { return true; } /* read the page from the file system or classpath. */ final String todoWebPage = resource(HTML_PAGE); /* Send the HTML file out to the browser. */ httpRequest.getReceiver().response(200, "text/html", todoWebPage); return false; });
-And finally start the service:
/* Start the service. */ final ServiceServer serviceServer = serviceServerBuilder().setSystemManager(systemManager) .setHttpServer(httpServer).build().initServices(new TodoService()).startServer();
That is it, you are done, now you can access this simple todo list app on http://localhost:9999/ui/index.html.
Full code Listing
You can also download/clone this example on github, here is the guide.
TodoObject.java Listing
package io.advantageous.qbit.example.todolistapp; /** * Created by rhightower on 2/10/15. */ public class TodoObject { //private final String todo; private final long time = System.currentTimeMillis(); // public TodoObject(String todo) { // this.todo = todo; // } }
TodoService.java Listing
package io.advantageous.qbit.example.todolistapp; import io.advantageous.qbit.annotation.*; /** * Created by rhightower on 2/10/15. */ @RequestMapping("/todoservice") public class TodoService { @RequestMapping("/todoo") public TodoObject list() { return new TodoObject(); } }
TodoRestServer.java Listing
package io.advantageous.qbit.example.todolistapp; import io.advantageous.qbit.http.server.HttpServer; import io.advantageous.qbit.server.ServiceServer; import io.advantageous.qbit.system.QBitSystemManager; import static io.advantageous.qbit.http.server.HttpServerBuilder.httpServerBuilder; import static io.advantageous.qbit.server.ServiceServerBuilder.serviceServerBuilder; import static io.advantageous.boon.Boon.resource; /** * Created by rhightower on 2/9/15. */ public class TodoRestServer { public static final String HTML_PAGE = "/ui/index.html"; public static void main(String... args) { /* Create the system manager to manage the shutdown. */ QBitSystemManager systemManager = new QBitSystemManager(); HttpServer httpServer = httpServerBuilder() .setPort(9999).build(); /* Register the Predicate using a Java 8 lambda expression. */ httpServer.setShouldContinueHttpRequest(httpRequest -> { /* If not the page uri we want to then just continue by returning true. */ if (!httpRequest.getUri().equals(HTML_PAGE)) { return true; } /* read the page from the file system or classpath. */ final String todoWebPage = resource(HTML_PAGE); /* Send the HTML file out to the browser. */ httpRequest.getReceiver().response(200, "text/html", todoWebPage); return false; }); /* Start the service. */ final ServiceServer serviceServer = serviceServerBuilder().setSystemManager(systemManager) .setHttpServer(httpServer).build().initServices(new TodoService()).startServer(); /* Wait for the service to shutdown. */ systemManager.waitForShutdown(); } }
index.html Listing
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title>TODO list example with Qbit</title> <style> body { background-color: #D8D8D8; } h1 { text-align: center; } ul { list-style-type: none; padding: 20px; margin: 0px; } li { background: #CCFF00; font-size: 30px; border: 2px solid #000; padding: 10px 20px; color: #000; cursor: cell; } li span { padding: 10px; cursor: cell; } .check { text-decoration: line-through; font-weight: bold; color:#000; } /*<!--#add {--> <!--width: 10em; height: 3em; border:solid 2px #000;--> <!--}--> */ #enteritem { font-size: 30px; border: 2px solid #000; padding: 0; margin: 0; </style> </head> <body> <p><h1>TODO LIST APP EXAMPLE WITH QBIT</h1></p> <p><label for="enteritem"><h3>Enter your item: </h3></label> <input type="text" id="enteritem" name="enteritem"/></p> <!--<button id="add">NEW ITEM</button>--> <ul id="todolist"></ul> <p id="demo"></p> <br> <br> <br> <p>**To add an item type in the box and hit enter</p> <p>**to delete an item double click it</p> <p>**To check off an item, check the box</p> <script> function httpGet(theUrl) { var xmlHttp = null; xmlHttp = new XMLHttpRequest(); xmlHttp.open( "GET", theUrl, false ); xmlHttp.send( null ); return xmlHttp.responseText; } //submit text box var enterItem = document.getElementById("enteritem"); enterItem.focus(); enterItem.onkeyup = function(event) { // 13 represents the enter key. if (event.which == 13) { //var enterItem = event.which; var itemContent = enterItem.value; //var itemContent = event.which; if (!itemContent || itemContent == "" || itemContent == " " || itemContent == " ") { return false; } addNewItem(document.getElementById("todolist"), itemContent); enterItem.focus(); enterItem.select(); } } function removeItem() { //var listId = this.id.replace("li_", ""); document.getElementById(this.id).style.display = "none"; } function addNewItem(list, itemContent) { // getiing the id from TodoService var json = httpGet("/services/todoservice/todoo"); var date = JSON.parse(json); var id = date.time; var listItem = document.createElement("li"); listItem.id = "li_" + id; var checkBox = document.createElement("input"); checkBox.type = "checkBox"; checkBox.id = "idc_" + id; var span = document.createElement("span"); span.id = "ids_" + id; checkBox.onclick = itemStatus; span.innerText = itemContent; listItem.ondblclick = removeItem; listItem.appendChild(checkBox); listItem.appendChild(span); //listItem.textContent = itemContent; list.appendChild(listItem); } function itemStatus() { var checkboxId = this.id.replace("idc_", ""); var itemContent = document.getElementById("ids_" + checkboxId); if (this.checked){ itemContent.className = "check"; }else { itemContent.className = ""; } } </script> </body> </html>
Summary
If we were to compare this app to a MVC environment we can safely say that TodoObject is similar to a Model (M), TodoService is similar to the controller (C), and TodoRestServer is similar to the View (V).
After going through this example I think we have made it very clear that QBit is very easy to use to server up single page applications, server up non-JSON resources, and allows you to bind objects to HTTP ports so that they can be called by REST and WebSocket clients.
What is QBit again?
QBit is a reactive programming lib for building microservices - JSON, HTTP, WebSocket, and REST. It is similar to many other projects like Akka, Spring Reactor, etc. QBit is just a library not a platform. QBit has libraries to put a service behind a queue. You can use QBit queues directly or you can create a service. QBit services can be exposed by WebSocket, HTTP, HTTP pipeline, and other types of remoting. A service in QBit is a Java class whose methods are executed behind service queues. QBit implements apartment model threading and is similar to the Actor model or a better description would be Active Objects. QBit does not use a disruptor. It uses regular Java Queues. QBit can do north of 100 million ping pong calls per second which is an amazing speed (seen as high as 200M). QBit uses reactive programming to build elastic REST, and WebSockets based cloud friendly, web services. SOA evolved for mobile and cloud.
QBit lingo
QBit is a reactive programming lib for building microservices - JSON, HTTP, WebSocket, and REST. It is written in Java but I might one day write a version in Rust or Go or C# (but that would require a large payday).
Service POJO (plain old Java object) behind a queue that can receive method calls via proxy calls or events (May have one thread managing events, method calls, and responses or two one for method calls and events and the other for responses so response handlers do not block service. One is faster unless responses block). Services can use Spring MVC style REST annotations to expose themselves to the outside world via REST and WebSocket.
ServiceBundle Many POJOs behind one response queue and many receive queues. There may be one thread for all responses or not. They also can be one receive queue.
Queue A thread managing a queue. It supports batching. It has events for empty, reachedLimit, startedBatch, idle. You can listen to these events from services that sit behind a queue. You don't have to use Services. You can use Queue's direct.
ServiceServer ServiceBundle that is exposed to REST and WebSocket communication
EventBus EventBus is a way to send a lot of messages to services that may be loosely coupled
ClientProxy Way to invoke service through async interface, service can be inproc (same process) or remoted over WebSocket.
Non-blocking QBit is a non-blocking lib. You use CallBacks via Java 8 Lambdas. You can also send event messages and get replies. Messaging is built into the system so you can easily coordinate complex tasks.
Speed There is a lot of room for improvement with Speed. But already QBit is VERY fast. 200M+ TPS inproc ping pong, 10M-20M+ TPS event bus, 500K TPS RPC calls over WebSocket/JSON, etc. More work needs to be done to improve speed, but now it is fast enough where I am working more with usability.
References and reading materials:
1. Java Microservices Architecture
2. Microservices by Martin Fowler and James Lewis
3. Microservices Architecture by Chris Richardson
4. Micro services – Java, the Unix Way by James Lewis
5. Microservices, or How I Learned To Stop Making Monoliths and Love Conway’s Law by Cliff Moon
6. Micro service architecure by Fred George
7. Microservices are not a free lunch by Benjamin Wootton
8. Microservice Service Discovery with Consul
9. Antifragility and Microservices by Russ Miles
10. The Unix Philosophy
11. Conway’s Law
12. Reactive Microservices
13. Amazon Architecture
14. Migrating to microservices by Adrian Cockroft
15. Microservices with Spring Boot
16. Microservices for the Grumpy Neckbeard
17. Microservices definition on Wikipedia
18. Microservices and DevOps by Adrian Cockcroft
19. Building and Deploying Microservices - Bart Blommaerts
20. Microservices on the JVM - Alexander Heusingfeld
21. Microservices Shaun Abrams
22. High Speed Microservices