-
Notifications
You must be signed in to change notification settings - Fork 140
[Z Blog] Qbit servlet support also a preview of using jetty and the QBit microservice lib together
I have a prototype that uses Jetty to prove out that qbit and Servlets is working for REST support.
Simple Service
package io.advantageous.qbit.servlet.integrationproto;
import io.advantageous.qbit.annotation.RequestMapping;
import io.advantageous.qbit.http.HttpServer;
import io.advantageous.qbit.server.ServiceEndpointServer
ServiceEndpointServer
ServiceEndpointServer;
import static io.advantageous.qbit.server.EndpointServerBuilder.endpointServerBuilder;
/**
* Created by rhightower on 2/12/15.
*/
public class MyServiceModule {
@RequestMapping("/ping")
public static class PingService {
@RequestMapping("/ping")
public String ping() {
return "ok";
}
}
public static ServiceEndpointServer
ServiceEndpointServer
ServiceEndpointServer configureApp(final HttpServer server) {
return endpointServerBuilder().setHttpServer(server)
.build().initServices(new PingService()).startServer();
}
}
The above by design has nothing to do with Jetty or Servlets.
Then to bind it into a Servlet engine for testing, I use Jetty because Jetty is easy to use and embed.
package io.advantageous.qbit.servlet.integrationproto;
import io.advantageous.qbit.http.HttpServer;
import io.advantageous.qbit.server.ServiceEndpointServer
ServiceEndpointServer
ServiceEndpointServer;
import io.advantageous.qbit.servlet.QBitHttpServlet;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import javax.servlet.ServletConfig;
/**
* Created by rhightower on 2/12/15.
*/
public class QBitPlusJettyPrototype {
public static class MyQBitServlet extends QBitHttpServlet {
public static final String QBIT_SERVICE_SERVER_SERVER = "QBit.ServiceEndpointServer
ServiceEndpointServer
ServiceEndpointServer.server";
private ServletConfig config;
@Override
protected void wireHttpServer(final HttpServer httpServer, final ServletConfig config) {
final ServiceEndpointServer
ServiceEndpointServer
ServiceEndpointServer server = MyServiceModule.configureApp(httpServer);
config.getServletContext().setAttribute(QBIT_SERVICE_SERVER_SERVER, server);
this.config = config;
}
@Override
protected void stop() {
final ServiceEndpointServer
ServiceEndpointServer
ServiceEndpointServer server =
(ServiceEndpointServer
ServiceEndpointServer
ServiceEndpointServer)
config.getServletContext().getAttribute(QBIT_SERVICE_SERVER_SERVER);
server.stop();
}
}
public static void main(String... args) throws Exception {
Server server = new Server(8080);
ServletContextHandler servletContextHandler = new ServletContextHandler(server,
"*", true, false);
servletContextHandler.addServlet(MyQBitServlet.class, "/services/*");
server.start();
server.join();
}
}
We just start up Jetty. Tell Jetty that it is a Servlet container. We create a servlet that extends QBitHttpServlet (that is the cross platform way to use QBit in any container, yes.. you could use QBit in Tomcat or Undertow or... God Forbid Websphere or WebLogic).
The support classes for QBit / Servlet support are:
- QBitHttpServlet template design pattern to hook into Servlet lifecycle
- QBitServletUtil utility to convert from HttpServletRequest to QBit HttpRequest
- HttpServletParamMultiMap adapter to a multi-map from a servlet request
- HttpServletHeaderMultiMap ditto but for headers (painful but lightweight)
- ServletHttpServer lightweight HttpServer (this could be in core, it is wafer thin)
I want to put this in qbit-core. It has no ties to Servlets at all.
package io.advantageous.qbit.servlet;
import io.advantageous.qbit.http.HttpRequest;
import io.advantageous.qbit.http.HttpServer;
import io.advantageous.qbit.http.WebSocketMessage;
import java.util.concurrent.*;
import java.util.function.Consumer;
import java.util.function.Predicate;
/**
* Created by rhightower on 2/12/15.
*/
public class ServletHttpServer implements HttpServer {
private Consumer<WebSocketMessage> webSocketMessageConsumer = webSocketMessage -> {
};
private Consumer<WebSocketMessage> webSocketCloseMessageConsumer = webSocketMessage -> {
};
private Consumer<HttpRequest> httpRequestConsumer = request -> {
};
private Consumer<Void> requestIdleConsumer = aVoid -> {};
private Consumer<Void> webSocketIdleConsumer = aVoid -> {};
private Predicate<HttpRequest> shouldContinueHttpRequest = request -> true;
private ScheduledFuture<?> future;
@Override
public void setShouldContinueHttpRequest(Predicate<HttpRequest> predicate) {
this.shouldContinueHttpRequest = predicate;
}
public void handleRequest(final HttpRequest request) {
if (shouldContinueHttpRequest.test(request)) {
httpRequestConsumer.accept(request);
}
}
@Override
public void setWebSocketMessageConsumer(final Consumer<WebSocketMessage> webSocketMessageConsumer) {
this.webSocketMessageConsumer = webSocketMessageConsumer;
}
@Override
public void setWebSocketCloseConsumer(Consumer<WebSocketMessage> webSocketCloseMessageConsumer) {
this.webSocketCloseMessageConsumer = webSocketCloseMessageConsumer;
}
@Override
public void setHttpRequestConsumer(Consumer<HttpRequest> httpRequestConsumer) {
this.httpRequestConsumer = httpRequestConsumer;
}
@Override
public void setHttpRequestsIdleConsumer(Consumer<Void> idleConsumer) {
this.requestIdleConsumer = idleConsumer;
}
@Override
public void setWebSocketIdleConsume(Consumer<Void> idleConsumer) {
this.webSocketIdleConsumer = idleConsumer;
}
private ScheduledExecutorService monitor;
@Override
public void start() {
monitor = Executors.newScheduledThreadPool(1,
runnable -> {
Thread thread = new Thread(runnable);
thread.setName("ServletHttpServer Flush Thread" );
return thread;
}
);
/** This wants to be configurable. */
future = monitor.scheduleAtFixedRate(() -> {
try {
requestIdleConsumer.accept(null);
webSocketIdleConsumer.accept(null);
} catch (Exception ex) {
ex.printStackTrace();
//logger.error("blah blah Manager::Problem running queue manager", ex); //TODO log this
}
}, 50, 50, TimeUnit.MILLISECONDS);
}
@Override
public void stop() {
if (future!=null) {
future.cancel(true);
}
if (monitor!=null) {
monitor.shutdown();
}
}
}
A Servlet so someone using Servlets can easily use QBit.
package io.advantageous.qbit.servlet;
import io.advantageous.qbit.http.HttpRequest;
import io.advantageous.qbit.http.HttpServer;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import static io.advantageous.qbit.servlet.QBitServletUtil.convertRequest;
/**
* Created by rhightower on 2/12/15.
*/
@WebServlet(asyncSupported = true)
public abstract class QBitHttpServlet extends HttpServlet {
private final ServletHttpServer httpServer = new ServletHttpServer();
@Override
public void destroy() {
httpServer.stop();
stop();
}
protected abstract void stop();
@Override
public void init(ServletConfig config) throws ServletException {
httpServer.start();
wireHttpServer(httpServer, config);
}
protected abstract void wireHttpServer(final HttpServer httpServer, ServletConfig config);
@Override
protected void service(final HttpServletRequest request, final HttpServletResponse response)
throws ServletException, IOException {
final HttpRequest httpRequest = convertRequest(request.startAsync());
httpServer.handleRequest(httpRequest);
}
}
Now the meat. This does all the work and glue. This glues the Servlet world to the QBit world.
package io.advantageous.qbit.servlet;
import io.advantageous.qbit.http.HttpRequest;
import io.advantageous.qbit.http.HttpRequestBuilder;
import io.advantageous.qbit.util.MultiMap;
import org.boon.IO;
import javax.servlet.AsyncContext;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import static io.advantageous.qbit.http.HttpRequestBuilder.httpRequestBuilder;
/**
* Created by rhightower on 2/12/15.
*/
public class QBitServletUtil {
public static HttpRequest convertRequest(final AsyncContext asyncContext) {
final HttpServletRequest request = (HttpServletRequest) asyncContext.getRequest();
final HttpServletResponse response = (HttpServletResponse) asyncContext.getResponse();
final MultiMap<String, String> headers = new HttpServletHeaderMultiMap(request);
final MultiMap<String, String> params = new HttpServletParamMultiMap(request);
final HttpRequestBuilder httpRequestBuilder =
httpRequestBuilder().setParams(params)
.setHeaders(headers).setUri(request.getRequestURI())
.setMethod(request.getMethod());
setRequestBodyIfNeeded(request, httpRequestBuilder);
setupRequestHandler(asyncContext, response, httpRequestBuilder);
return httpRequestBuilder.build();
}
private static void setupRequestHandler(AsyncContext asyncContext, HttpServletResponse response, HttpRequestBuilder httpRequestBuilder) {
httpRequestBuilder.setTextResponse((code, contentType, body) -> {
response.setHeader("Content-Type", contentType);
try {
final ServletOutputStream outputStream = response.getOutputStream();
IO.write(outputStream, body);
outputStream.close();
asyncContext.complete();
} catch (IOException e) {
throw new IllegalStateException(e);
}
});
}
private static void setRequestBodyIfNeeded(HttpServletRequest request, HttpRequestBuilder httpRequestBuilder) {
if (request.getMethod().equals("POST") || request.getMethod().equals("PUT")) {
final String body = readBody(request);
if (body!=null) {
httpRequestBuilder.setBody(body);
}
}
}
private static String readBody(HttpServletRequest request) {
try {
final ServletInputStream inputStream = request.getInputStream();
final String body = IO.read(inputStream, StandardCharsets.UTF_8);
return body;
} catch (IOException e) {
throw new IllegalStateException(e);
}
}
}
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