-
Notifications
You must be signed in to change notification settings - Fork 140
[Detailed Tutorial] Building a single page; Todo List Application with QBit
##overview
QBit enables you to build applications hassle free, it can server up non-JSON resources. The QBit lib allows you to bind objects to HTTP ports so that they can be called by REST and WebSocket clients. This will be demonstrated in this example.
This wiki will walk you through the process of building a Todo List application with QBit.
You will build a Todo List application with QBit, you be able to access the application at the following address:
http://localhost:9999/ui/index.html
The app has a text box that will let you add todo items after typing it in and hitting ENTER, after the item is added you can delete it simply by double clicking it, or you can change its status (draw a line though it) simply by checking a box. here is a picture of the app in action:
In order to complete this example successfully you will need the following installed on your machine:
- Gradle; if you need help installing it, visit Installing Gradle.
- Your favorite IDE or text editor (we recommend [Intellig IDEA ] (https://www.jetbrains.com/idea/) latest version).
- [JDK ] (http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html) 1.8 or later.
- Build and install QBit on your machine click [Building QBit ] (https://github.com/advantageous/qbit/wiki/%5BQuick-Start%5D-Building-QBit-the-microservice-lib-for-Java) for instrutions.
Now that your machine is all ready let's get started:
- [Download ] (https://github.com/fadihub/todo-list-app/archive/master.zip) and unzip the source repository for this guide, or clone it using Git:
https://github.com/fadihub/todo-list-app.git
Once this is done you can test the service, let's first explain the process:
src/main/java/io.advantageous.qbit.example.todolistapp/TodoObject.java
package io.advantageous.qbit.example.todolistapp;
/**
* Created by rhightower on 2/10/15.
*/
public class TodoObject {
private final long time = System.currentTimeMillis();
}
This TodoObject
will only hold a variable time
that holds the current time in milli seconds, as you will see later this variable will be used as a unique id element for the todo items listed in the app.
src/main/java/io.advantageous.qbit.example.todolistapp/TodoService.java
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();
}
}
This TodoService
will be called by the html file (as you will see later) to return a TodoObject
that holds the time which is used as an id for the items that will be listed.
src/main/java/io.advantageous.qbit.example.todolistapp/TodoService.java
<!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;
}
#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>
<ul id="todolist"></ul>
<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>
//This function will enable you to call TodoService
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 ASCII dec number for the ENTER key.
if (event.which == 13) {
var itemContent = enterItem.value;
if (!itemContent || itemContent == "" || itemContent == " " || itemContent == " ") {
return false;
}
addNewItem(document.getElementById("todolist"), itemContent);
enterItem.focus();
enterItem.select();
}
}
//to delete a listed item from the todo list
function removeItem() {
document.getElementById(this.id).style.display = "none";
}
// function to add a todo item
function addNewItem(list, itemContent) {
// Calls TodoService to retrieve an object then retrieves the id number for the item listed
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);
list.appendChild(listItem);
}
//changes the status of the item listed by drawing a line through it when the box is checked
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>
The index.html
holds some css to format the todo list app and make it somewhat pretty here is the css part:
<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>
Also it holds some html to show the texts like the title of the app "TODO LIST APP EXAMPLE WITH QBIT",the text box is where you enter your item that you want to be listed, and the list is where the added items are listed. very simple really here is the html part:
<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>
<ul id="todolist"></ul>
<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>
Also it holds some javascript this is where it calls TodoServices
to get a TodoObject
then it parses it into a JSON since the object holds the current time in milli seconds like we mentioned before, current time can be retrieved and stored in a variable id
. Every todo item added by the user will have a unique id
current time in milli seconds. This unique id
will enable us to delete and change the status of a todo item.
To distinguish the parts we explained here they will be commented on the code. Here is the javascript part of the index.html
:
<script>
//This function will enable you to call TodoService
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 ASCII dec number for the ENTER key.
if (event.which == 13) {
var itemContent = enterItem.value;
if (!itemContent || itemContent == "" || itemContent == " " || itemContent == " ") {
return false;
}
addNewItem(document.getElementById("todolist"), itemContent);
enterItem.focus();
enterItem.select();
}
}
//to delete a listed item from the todo list
function removeItem() {
document.getElementById(this.id).style.display = "none";
}
// function to add a todo item
function addNewItem(list, itemContent) {
// Calls TodoService to retrieve an object then retrieves the id number for the item listed
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);
list.appendChild(listItem);
}
//changes the status of the item listed by drawing a line through it when the box is checked
function itemStatus() {
var checkboxId = this.id.replace("idc_", "");
var itemContent = document.getElementById("ids_" + checkboxId);
if (this.checked){
itemContent.className = "check";
}else {
itemContent.className = "";
}
}
</script>
src/main/java/io.advantageous.qbit.example.todolistapp/TodoRestServer.java
package io.advantageous.qbit.example.todolistapp;
import io.advantageous.qbit.http.server.HttpServer;
import io.advantageous.qbit.server.ServiceEndpointServer
ServiceEndpointServer
ServiceEndpointServer;
import io.advantageous.qbit.system.QBitSystemManager;
import static io.advantageous.qbit.http.server.HttpServerBuilder.httpServerBuilder;
import static io.advantageous.qbit.server.EndpointServerBuilder.endpointServerBuilder;
import static org.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.getResponse().response(200, "text/html", todoWebPage);
return false;
});
/* Start the service. */
final ServiceEndpointServer
ServiceEndpointServer
ServiceEndpointServer serviceServer = endpointServerBuilder().setSystemManager(systemManager)
.setHttpServer(httpServer).build().initServices(new TodoService()).startServer();
/* Wait for the service to shutdown. */
systemManager.waitForShutdown();
}
}
Here we will show how to use a ServiceEndpointServer
ServiceEndpointServer
ServiceEndpointServer to host The REST and WebSocket and still deliver up a single page app. Instead of having the EndpointServerBuilder create an HttpServer, we will create one for it, and pass that to the builder. We create the httpserver
and set its port to 9999, then the predicates are set using Lambda 8 java, With the Predicate callback, you can specify if you want the request to be handled by the consumer or not. This means all we have to do is create a Predicate that handles the request and then return false so the consumer which is wired into the EndpointServerBuilder is never called. Then we load the resource "/ui/index.html". And we deliver that up to the browser. All other requests we let go through.
At the end we just start the service and wait for the service to shutdown:
/* Start the service. */
final ServiceEndpointServer
ServiceEndpointServer
ServiceEndpointServer serviceServer = endpointServerBuilder().setSystemManager(systemManager)
.setHttpServer(httpServer).build().initServices(new TodoService()).startServer();
/* Wait for the service to shutdown. */
systemManager.waitForShutdown();
systemManager
is an instance of QBitSystemManager
/* Create the system manager to manage the shutdown. */
QBitSystemManager systemManager = new QBitSystemManager();
So when you run TodoRestServer
you will be able to access the application at http://localhost:9999/ui/index.html
##Test The Service
Using your terminal cd todo-list-app
then gradle clean build
then gradle run
then open up your favorite browser and visit this address http://localhost:9999/ui/index.html, now you should have access to a working todo list applications that looks like this:
##Summary
You have just built and tested a Todo List Application with QBit, as you can see by going over this example we have demonstrated that QBit can server up non-JSON resources and that QBit lib allows you to bind objects to HTTP ports so that they can be called by REST and WebSocket clients. see you in the next tutorial!
QBit is a queuing library for microservices. 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 also supports calling services via REST, and WebSocket. QBit is microservices in the pure Web sense: JSON, HTTP, WebSocket, etc. QBit uses micro batching to push messages through the pipe (queue, IO, etc.) faster to reduce thread hand-off.
QBit is a Java microservice lib supporting REST, JSON and WebSocket. It is written in Java but we could 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. In QBit, you have sender queues and receivers queues. They are separated to support micro-batching.
ServiceEndpointServer ServiceEndpointServer ServiceEndpointServer 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 ClientProxy is a 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. QBit takes an object-oriented approach to service development so services look like normal Java services that you already write, but the services live behind a queue/thread. This is not a new concept. Microsoft did this with DCOM/COM and called it active objects. Akka does it with actors and called them strongly typed Actors. The important concepts is that you get the speed of reactive and actor style messaging but you develop in a natural OOP approach. QBit is not the first. QBit is not the only.
Speed QBit is VERY fast. There is a of course a lot of room for improvement. But already 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 we are focusing more on usability. The JSON support uses Boon by default which is up to 4x faster than other JSON parsers for the REST/JSON, WebSocket/JSON use case.
QBit Website What is Microservices Architecture?
QBit Java Micorservices lib tutorials
The Java microservice lib. QBit is a reactive programming lib for building microservices - JSON, HTTP, WebSocket, and REST. QBit uses reactive programming to build elastic REST, and WebSockets based cloud friendly, web services. SOA evolved for mobile and cloud. ServiceDiscovery, Health, reactive StatService, events, Java idiomatic reactive programming for Microservices.
Reactive Programming, Java Microservices, Rick Hightower
Java Microservices Architecture
[Microservice Service Discovery with Consul] (http://www.mammatustech.com/Microservice-Service-Discovery-with-Consul)
Microservices Service Discovery Tutorial with Consul
[Reactive Microservices] (http://www.mammatustech.com/reactive-microservices)
[High Speed Microservices] (http://www.mammatustech.com/high-speed-microservices)
Reactive Microservices Tutorial, using the Reactor
QBit is mentioned in the Restlet blog
All code is written using JetBrains Idea - the best IDE ever!
Kafka training, Kafka consulting, Cassandra training, Cassandra consulting, Spark training, Spark consulting
Tutorials
- QBit tutorials
- Microservices Intro
- Microservice KPI Monitoring
- Microservice Batteries Included
- RESTful APIs
- QBit and Reakt Promises
- Resourceful REST
- Microservices Reactor
- Working with JSON maps and lists
__
Docs
Getting Started
- First REST Microservice
- REST Microservice Part 2
- ServiceQueue
- ServiceBundle
- ServiceEndpointServer
- REST with URI Params
- Simple Single Page App
Basics
- What is QBit?
- Detailed Overview of QBit
- High level overview
- Low-level HTTP and WebSocket
- Low level WebSocket
- HttpClient
- HTTP Request filter
- HTTP Proxy
- Queues and flushing
- Local Proxies
- ServiceQueue remote and local
- ManagedServiceBuilder, consul, StatsD, Swagger support
- Working with Service Pools
- Callback Builders
- Error Handling
- Health System
- Stats System
- Reactor callback coordination
- Early Service Examples
Concepts
REST
Callbacks and Reactor
Event Bus
Advanced
Integration
- Using QBit in Vert.x
- Reactor-Integrating with Cassandra
- Using QBit with Spring Boot
- SolrJ and service pools
- Swagger support
- MDC Support
- Reactive Streams
- Mesos, Docker, Heroku
- DNS SRV
QBit case studies
QBit 2 Roadmap
-- Related Projects
- QBit Reactive Microservices
- Reakt Reactive Java
- Reakt Guava Bridge
- QBit Extensions
- Reactive Microservices
Kafka training, Kafka consulting, Cassandra training, Cassandra consulting, Spark training, Spark consulting