-
Notifications
You must be signed in to change notification settings - Fork 140
ServiceEndpointServer
The ServiceEndpointServer
essentially exposes a ServiceBundle
to WebSocket and REST remote calls. This document is using the Todo example from the discussion of ServiceQueue
and the ServiceBundle
.
In fact, you can use ServiceEndpointServer
very similar to the way we used ServiceBundle
.
import io.advantageous.qbit.server.EndpointServerBuilder;
import io.advantageous.qbit.server.ServiceEndpointServer;
import static io.advantageous.qbit.server.EndpointServerBuilder.endpointServerBuilder;
...
/* Create the serviceBundleBuilder. */
final EndpointServerBuilder endpointServerBuilder =
endpointServerBuilder();
endpointServerBuilder.addService(auditorAddress,
new AuditorImpl());
/* Create the service endpoint server. */
serviceEndpointServer = endpointServerBuilder.build();
We use a EndpointServerBuilder
to build a serviceEndpointServer
. You can add services to the builder or you can add them directly to the serviceEndpointServer
.
Note you can use
EndpointServerBuilder
but most examples will use theManagedServiceBuilder
which has the benefit of wiring the services it creates into the microservice health check system and the microservice statistics/monitoring/distributed MDC logging systems that QBit provides.
The serviceEndpointServer
has a serviceBundle
.
/* Create a service client proxy for the auditor. */
auditor = serviceEndpointServer.serviceBundle()
.createLocalProxy(Auditor.class, auditorAddress);
/* Create a todo manager and pass the
client proxy of the auditor to it. */
final TodoManagerImpl todoManager =
new TodoManagerImpl(auditor);
// Add the todoManager to the serviceBundle.
serviceEndpointServer.serviceBundle()
.addServiceObject(todoAddress, todoManager);
/* Create a client proxy to communicate
with the service actor. */
client = serviceEndpointServer.serviceBundle()
.createLocalProxy(TodoManagerClient.class,
todoAddress);
Note if we wanted to hide access to the auditor, we could put the
auditor
in anotherserviceQueue
orserviceBundle
that was not accessible to WebSocket or REST.
We can use the proxy client just like we did before. We can create a local microservice actor proxy client. The only real difference is that auto flush is built into serviceEndpointServer
and not serviceBundle
.
/* A list of promises for things we want to do all at once. */
final List<Promise<Boolean>> promises = new ArrayList<>(3);
final CountDownLatch latch = new CountDownLatch(1);
final AtomicBoolean success = new AtomicBoolean();
/** Add a todoItem to the client add method */
final Todo todo = new Todo("write", "Write tutorial", timer.time());
final Promise<Boolean> promise
= client.add(todo);
promises.add(promise);
/** Add two more. */
promises.add(client.add(new Todo("callMom", "Call Mom", timer.time())));
promises.add(client.add(new Todo("callSis", "Call Sister", timer.time())));
/** Now async wait for them all to come back. */
Promises.all(promises).then(done -> {
success.set(true);
latch.countDown();
}).catchError(e -> {
success.set(false);
latch.countDown();
});
/** Invoke the promises. */
promises.forEach(Promise::invoke);
/** They are all going to come back async. */
latch.await();
assertTrue(success.get());
Ok. Up until this point, nothing is really different than before. The TodoManagerImpl
is now accessible via REST and WebSocket.
import io.advantageous.qbit.client.Client;
import io.advantageous.qbit.client.ClientBuilder;
...
//REMOVE THIS Create a client proxy to communicate with the service actor.
//REMOVE client = serviceEndpointServer.serviceBundle()
//REMOVE .createLocalProxy(TodoManagerClient.class, todoAddress);
/* Start the service endpoint server
and wait until it starts. */
serviceEndpointServer.startServerAndWait();
/* Create the WebSocket Client Builder. */
final ClientBuilder clientBuilder = ClientBuilder.clientBuilder();
/** Build the webSocketClient. */
webSocketClient = clientBuilder.setHost("localhost")
.setPort(8080)
.build();
/* Create a REMOTE client proxy to communicate with the service actor. */
client = webSocketClient.createProxy(TodoManagerClient.class, todoAddress);
/* Start the remote client. */
webSocketClient.start();
...
@After
public void tearDown() throws Exception{
Thread.sleep(100);
serviceEndpointServer.stop(); //stop the server
webSocketClient.stop(); //stop the client
}
The client like the service endpoint server also auto-flushes. You can use the remote client (remote microservice client proxy) just like before (when we showed the local microservice client proxy).
/* A list of promises for things we want to do all at once. */
final List<Promise<Boolean>> promises = new ArrayList<>(3);
final CountDownLatch latch = new CountDownLatch(1);
final AtomicBoolean success = new AtomicBoolean();
/** Add a todoItem to the client add method */
final Todo todo = new Todo("write", "Write tutorial", timer.time());
final Promise<Boolean> promise
= client.add(todo);
promises.add(promise);
/** Add two more. */
promises.add(client.add(new Todo("callMom", "Call Mom", timer.time())));
promises.add(client.add(new Todo("callSis", "Call Sister", timer.time())));
/** Now async wait for them all to come back. */
Promises.all(promises).then(done -> {
success.set(true);
latch.countDown();
}).catchError(e -> {
success.set(false);
latch.countDown();
});
/** Invoke the promises. */
promises.forEach(Promise::invoke);
/** They are all going to come back async. */
latch.await();
assertTrue(success.get());
To expose the TodoManagerImpl to REST, we will define a main method to start the server. Then we will add @RequestMapping
, @POST
, @PUT
, @DELETE/@RequestParam
, and @GET
.
package com.mammatustech.todo;
...
import io.advantageous.qbit.annotation.*;
import io.advantageous.qbit.annotation.http.DELETE;
import io.advantageous.qbit.annotation.http.GET;
import io.advantageous.qbit.annotation.http.PUT;
import io.advantageous.qbit.reactive.Callback;
...
@RequestMapping("/todo-service")
public class TodoManagerImpl {
private final Map<String, Todo> todoMap = new TreeMap<>();
private final Auditor auditor;
public TodoManagerImpl(final Auditor auditor) {
this.auditor = auditor;
}
@GET("/todo/count")
public int size() {
return todoMap.size();
}
@PUT("/todo/")
public void add(final Callback<Boolean> callback, final Todo todo) {
todoMap.put(todo.getId(), todo);
auditor.audit("add", "added new todo");
callback.resolve(true);
}
@DELETE("/todo/")
public void remove(final Callback<Boolean> callback,
@RequestParam("id") final String id) {
final Todo removed = todoMap.remove(id);
auditor.audit("add", "removed new todo");
callback.resolve(removed != null);
}
@GET("/todo/")
public void list(final Callback<List<Todo>> callback) {
auditor.audit("list", "auditor added");
callback.accept(new ArrayList<>(todoMap.values()));
}
...
}
The main method just creates the microservices and starts the server.
package com.mammatustech.todo;
import io.advantageous.qbit.server.EndpointServerBuilder;
import io.advantageous.qbit.server.ServiceEndpointServer;
import static io.advantageous.qbit.server.EndpointServerBuilder.endpointServerBuilder;
public class TodoServiceMain {
public static void main(final String... args) {
/** Object address to the auditorService service actor. */
final String auditorAddress = "auditorService";
/* Create the serviceBundleBuilder. */
final EndpointServerBuilder endpointServerBuilder =
endpointServerBuilder();
endpointServerBuilder.setPort(8080).setUri("/");
endpointServerBuilder.addService(auditorAddress,
new AuditorImpl());
/* Create the service server. */
final ServiceEndpointServer serviceEndpointServer =
endpointServerBuilder.build();
/* Create a service client proxy for the auditor. */
final Auditor auditor = serviceEndpointServer
.serviceBundle()
.createLocalProxy(Auditor.class, auditorAddress);
/* Create a todo manager and pass
the client proxy of the auditor to it. */
final TodoManagerImpl todoManager =
new TodoManagerImpl(auditor);
// Add the todoManager to the serviceBundle.
serviceEndpointServer.addService(todoManager);
/* Start the service endpoint server
and wait until it starts. */
serviceEndpointServer.startServerAndWait();
System.out.println("Started");
}
}
No RESTful microservice is proven to be RESTful without some curl script.
echo "Todo item list before "
curl http://localhost:8080/todo-service/todo/
echo
echo "Count of Todo items "
curl http://localhost:8080/todo-service/todo/count
echo
echo "PUT a TODO item"
curl -X PUT http://localhost:8080/todo-service/todo/ \
-H 'Content-Type: application/json' \
-d '{"name":"wash-car", "description":"Take the car to the car wash", "createTime":1463950095000}'
echo
echo "Todo item list after add "
curl http://localhost:8080/todo-service/todo/
echo
echo "Count of Todo items after add "
curl http://localhost:8080/todo-service/todo/count
echo
echo "Remove a TODO item"
curl -X DELETE http://localhost:8080/todo-service/todo/?id=wash-car::1463950095000
echo
echo "Todo item list after add "
curl http://localhost:8080/todo-service/todo/
echo
echo "Count of Todo items after add "
curl http://localhost:8080/todo-service/todo/count
echo
$ ./curl-test.sh
Todo item list before
[]
Count of Todo items
0
PUT a TODO item
true
Todo item list after add
[{"name":"wash-car","description":"Take the car to the car wash","createTime":1463950095000,"id":"wash-car::1463950095000"}]
Count of Todo items after add
1
Remove a TODO item
true
Todo item list after add
[]
Count of Todo items after add
0
For completeness, here is the build file.
group 'qbit-ex'
version '1.0-SNAPSHOT'
apply plugin: 'java'
apply plugin: 'application'
mainClassName = "com.mammatustech.todo.TodoServiceMain"
compileJava {
sourceCompatibility = 1.8
}
repositories {
mavenCentral()
mavenLocal()
}
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.11'
compile 'io.advantageous.qbit:qbit-vertx:1.9.1'
compile 'io.advantageous.qbit:qbit-admin:1.9.1'
compile 'io.advantageous.reakt:reakt:2.8.15'
}
##Conclusion
A ServiceEndpointServer
exposes a ServiceBundle
as a remote accessible microservice whose methods can be invoked over WebSocket and HTTP/REST. Remote proxies can be created with QBit Client/ClientBuilder
. The ServiceEndpointServer and the Client are both auto flushing (interval duration of flush is configurable from their respective builders).
To learn more about QBit and REST see Restful QBit tutorial and Resourceful RESTful Microservices tutorial.
To learn about the ManagedServiceBuilder please read QBit Batteries included which covers health, stats and microservice monitoring. The QBit batteries included also covers using QBit with Swagger. QBit can generate swagger JSON from all of its services which you can then use to generate clients for other platforms.
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