<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Recent changes to BaseHttpMicroServicesVerticle</title><link>https://sourceforge.net/p/garyproject00/wiki/BaseHttpMicroServicesVerticle/</link><description>Recent changes to BaseHttpMicroServicesVerticle</description><atom:link href="https://sourceforge.net/p/garyproject00/wiki/BaseHttpMicroServicesVerticle/feed" rel="self"/><language>en</language><lastBuildDate>Wed, 25 Apr 2018 02:03:43 -0000</lastBuildDate><atom:link href="https://sourceforge.net/p/garyproject00/wiki/BaseHttpMicroServicesVerticle/feed" rel="self" type="application/rss+xml"/><item><title>BaseHttpMicroServicesVerticle modified by Gary Cheng</title><link>https://sourceforge.net/p/garyproject00/wiki/BaseHttpMicroServicesVerticle/</link><description>&lt;div class="markdown_content"&gt;&lt;pre&gt;--- v10
+++ v11
@@ -5,8 +5,11 @@
 import io.vertx.core.Handler;
 import io.vertx.core.http.HttpMethod;
 import io.vertx.core.json.JsonObject;
+import io.vertx.reactivex.RxHelper;
 import io.vertx.reactivex.core.Future;
 import io.vertx.reactivex.core.buffer.Buffer;
+import io.vertx.reactivex.core.http.HttpServer;
+import io.vertx.reactivex.core.http.HttpServerRequest;
 import io.vertx.reactivex.ext.web.Router;
 import io.vertx.reactivex.ext.web.RoutingContext;
 import io.vertx.reactivex.ext.web.client.HttpRequest;
@@ -20,6 +23,7 @@
 import java.util.HashSet;
 import java.util.Set;

+import static com.ezshop.common.ConfigKeys.KEY_PORT;
 import static com.ezshop.common.ErrorCodes.SYSTEM_ERROR_CODE;
 import static com.ezshop.common.HttpResponseCodes.SC_INTERNAL_SERVER_ERROR;
 import static com.ezshop.common.HttpResponseCodes.SC_OK;
@@ -34,6 +38,28 @@
     private static final String KEY_ERROR = "error";
     private static final String KEY_ERROR_CODE = "errorCode";
     private static final String KEY_ERROR_MESSAGE = "errorMessage";
+
+    /**
+     * Create a HTTP server by given config and router
+     *
+     * @param config HTTP config
+     * @param router the router receives HTTP request
+     * @return
+     */
+    protected Single&amp;lt;HttpServer&amp;gt; createHttpServer(JsonObject config, Router router) {
+        int port = config.getInteger(KEY_PORT);
+        HttpServer server = vertx.createHttpServer();
+        server.requestStream()
+                .toFlowable()
+                .map(HttpServerRequest::pause)
+                .onBackpressureDrop(req -&amp;gt; req.response().setStatusCode(503).end())
+                .observeOn(RxHelper.scheduler(vertx.getDelegate()))
+                .subscribe(req -&amp;gt; {
+                    req.resume();
+                    router.accept(req);
+                });
+        return server.rxListen(port).doAfterSuccess(s -&amp;gt; logger.debug("http server started on port {}", port));
+    }

     /**
      * Enable CORS
&lt;/pre&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Gary Cheng</dc:creator><pubDate>Wed, 25 Apr 2018 02:03:43 -0000</pubDate><guid>https://sourceforge.net2d03083db3791b8e9be9ca0470e93fe05b37c4c5</guid></item><item><title>BaseHttpMicroServicesVerticle modified by Gary Cheng</title><link>https://sourceforge.net/p/garyproject00/wiki/BaseHttpMicroServicesVerticle/</link><description>&lt;div class="markdown_content"&gt;&lt;pre&gt;--- v9
+++ v10
@@ -4,6 +4,7 @@
 import io.reactivex.Single;
 import io.vertx.core.Handler;
 import io.vertx.core.http.HttpMethod;
+import io.vertx.core.json.JsonObject;
 import io.vertx.reactivex.core.Future;
 import io.vertx.reactivex.core.buffer.Buffer;
 import io.vertx.reactivex.ext.web.Router;
@@ -19,6 +20,10 @@
 import java.util.HashSet;
 import java.util.Set;

+import static com.ezshop.common.ErrorCodes.SYSTEM_ERROR_CODE;
+import static com.ezshop.common.HttpResponseCodes.SC_INTERNAL_SERVER_ERROR;
+import static com.ezshop.common.HttpResponseCodes.SC_OK;
+
 /**
  * The abstract verticle which work as HTTP server
  *
@@ -26,6 +31,9 @@
  */
 public abstract class BaseHttpMicroServicesVerticle extends BaseMicroServicesVerticle {
     private static final Logger logger = LoggerFactory.getLogger(BaseMicroServicesVerticle.class);
+    private static final String KEY_ERROR = "error";
+    private static final String KEY_ERROR_CODE = "errorCode";
+    private static final String KEY_ERROR_MESSAGE = "errorMessage";

     /**
      * Enable CORS
@@ -46,11 +54,50 @@
     }

     /**
+     * Write generic json object to HTTP response
+     *
+     * @param context
+     * @param jsonString the json context to be wrote to HTTP response
+     */
+    protected void restResponseHandler(RoutingContext context, String jsonString) {
+        if (!context.response().ended()) {
+            context.response().setStatusCode(SC_OK).putHeader("content-type", "application/json")
+                    .end(jsonString);
+        }
+    }
+
+    /**
+     * Generate Rest error response by given exception
+     *
+     * @param context
+     * @param throwable
+     */
+    protected void restErrorHandler(RoutingContext context, Throwable throwable) {
+        this.restErrorHandler(context, SC_INTERNAL_SERVER_ERROR, SYSTEM_ERROR_CODE, throwable.getMessage());
+    }
+
+    /**
+     * Generate Rest error response by given statusCode, errorCode and error message
+     *
+     * @param context
+     * @param statusCode   the HTTP response status code
+     * @param errorCode    the error code
+     * @param errorMessage the error message
+     */
+    protected void restErrorHandler(RoutingContext context, int statusCode, String errorCode, String errorMessage) {
+        if (!context.response().ended()) {
+            JsonObject json = new JsonObject().put(KEY_ERROR, new JsonObject().put(KEY_ERROR_CODE, errorCode).put(KEY_ERROR_MESSAGE, errorMessage));
+            context.response().setStatusCode(statusCode).putHeader("content-type", "application/json")
+                    .end(json.encodePrettily());
+        }
+    }
+
+    /**
      * Dispatch a HTTP request to a HttpEndPoint service
      *
-     * @param context Routing context
-     * @param serviceName the name of service
-     * @param uri the uri at HttpEndPoint service
+     * @param context      Routing context
+     * @param serviceName  the name of service
+     * @param uri          the uri at HttpEndPoint service
      * @param errorHandler the async error handler
      */
     protected void dispatchRequest(RoutingContext context, String serviceName, String uri, Handler errorHandler) {
@@ -60,7 +107,7 @@
                 .subscribe(v -&amp;gt; logger.debug("dispatch request completed"), errorHandler::handle);
     }

-    protected void dispatchRequestHandler(RoutingContext context, String serviceName, String uri, Future&amp;lt;Void&amp;gt; future) {
+    private void dispatchRequestHandler(RoutingContext context, String serviceName, String uri, Future&amp;lt;Void&amp;gt; future) {
         this.getWebEndPoint(serviceName)
                 .subscribe(webClient -&amp;gt; invokeDispatchHttpRequest(context, webClient, uri, future),
                         throwable -&amp;gt; future.fail("Service [" + serviceName + "] not published"));
&lt;/pre&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Gary Cheng</dc:creator><pubDate>Tue, 24 Apr 2018 20:15:40 -0000</pubDate><guid>https://sourceforge.netc6b37e67e30875ea9fe0662e0af3c34828eb781a</guid></item><item><title>BaseHttpMicroServicesVerticle modified by Gary Cheng</title><link>https://sourceforge.net/p/garyproject00/wiki/BaseHttpMicroServicesVerticle/</link><description>&lt;div class="markdown_content"&gt;&lt;pre&gt;--- v8
+++ v9
@@ -1,5 +1,5 @@
 ~~~
-package com.example.microservices.com;
+package com.ezshop.common;

 import io.reactivex.Single;
 import io.vertx.core.Handler;
@@ -45,22 +45,30 @@
         router.route().handler(corsHandler);
     }

-    protected void dispatchRequest(RoutingContext context, String serviceName, Handler errorHandler) {
-        logger.debug("Dispatch Http Request {} to service {}", context.request().uri(), serviceName);
+    /**
+     * Dispatch a HTTP request to a HttpEndPoint service
+     *
+     * @param context Routing context
+     * @param serviceName the name of service
+     * @param uri the uri at HttpEndPoint service
+     * @param errorHandler the async error handler
+     */
+    protected void dispatchRequest(RoutingContext context, String serviceName, String uri, Handler errorHandler) {
+        logger.debug("Dispatch Http Request {} to {} service", uri, serviceName);
         this.getCircuitBreaker(serviceName).&amp;lt;Void&amp;gt;rxExecuteCommand(
-                future -&amp;gt; this.dispatchRequestHandler(context, serviceName, future))
+                future -&amp;gt; this.dispatchRequestHandler(context, serviceName, uri, future))
                 .subscribe(v -&amp;gt; logger.debug("dispatch request completed"), errorHandler::handle);
     }

-    protected void dispatchRequestHandler(RoutingContext context, String serviceName, Future&amp;lt;Void&amp;gt; future) {
+    protected void dispatchRequestHandler(RoutingContext context, String serviceName, String uri, Future&amp;lt;Void&amp;gt; future) {
         this.getWebEndPoint(serviceName)
-                .subscribe(webClient -&amp;gt; invokeDispatchHttpRequest(context, webClient, future),
+                .subscribe(webClient -&amp;gt; invokeDispatchHttpRequest(context, webClient, uri, future),
                         throwable -&amp;gt; future.fail("Service [" + serviceName + "] not published"));
     }

-    private void invokeDispatchHttpRequest(RoutingContext context, WebClient webClient, Future&amp;lt;Void&amp;gt; future) {
-        logger.debug("invokeDispatchHttpRequest, uri:{}", context.request().uri());
-        HttpRequest&amp;lt;Buffer&amp;gt; httpRequest = webClient.request(context.request().method(), context.request().uri());
+    private void invokeDispatchHttpRequest(RoutingContext context, WebClient webClient, String uri, Future&amp;lt;Void&amp;gt; future) {
+        logger.debug("invokeDispatchHttpRequest, uri:{}", uri);
+        HttpRequest&amp;lt;Buffer&amp;gt; httpRequest = webClient.request(context.request().method(), uri);
         context.request().headers().getDelegate().forEach(header -&amp;gt; httpRequest.putHeader(header.getKey(), header.getValue()));
         if (context.user() != null) {
             httpRequest.putHeader("user-principal", context.user().principal().encode());
&lt;/pre&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Gary Cheng</dc:creator><pubDate>Tue, 24 Apr 2018 01:59:15 -0000</pubDate><guid>https://sourceforge.netb1d483e3ffe935c3d4fdc997132cfec3f2e58d07</guid></item><item><title>BaseHttpMicroServicesVerticle modified by Gary Cheng</title><link>https://sourceforge.net/p/garyproject00/wiki/BaseHttpMicroServicesVerticle/</link><description>&lt;div class="markdown_content"&gt;&lt;pre&gt;--- v7
+++ v8
@@ -2,245 +2,85 @@
 package com.example.microservices.com;

 import io.reactivex.Single;
-import io.vertx.circuitbreaker.CircuitBreakerOptions;
+import io.vertx.core.Handler;
 import io.vertx.core.http.HttpMethod;
-import io.vertx.core.json.JsonObject;
-import io.vertx.reactivex.circuitbreaker.CircuitBreaker;
-import io.vertx.reactivex.core.AbstractVerticle;
+import io.vertx.reactivex.core.Future;
 import io.vertx.reactivex.core.buffer.Buffer;
-import io.vertx.reactivex.core.http.HttpClient;
+import io.vertx.reactivex.ext.web.Router;
+import io.vertx.reactivex.ext.web.RoutingContext;
 import io.vertx.reactivex.ext.web.client.HttpRequest;
 import io.vertx.reactivex.ext.web.client.HttpResponse;
 import io.vertx.reactivex.ext.web.client.WebClient;
-import io.vertx.reactivex.servicediscovery.ServiceDiscovery;
-import io.vertx.reactivex.servicediscovery.types.HttpEndpoint;
-import io.vertx.servicediscovery.Record;
-import io.vertx.servicediscovery.ServiceDiscoveryOptions;
+import io.vertx.reactivex.ext.web.handler.CorsHandler;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;

-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;

 /**
- * The base verticle class which provided some common functions include service discovery
+ * The abstract verticle which work as HTTP server
  *
  * @author Gary Cheng
  */
-public abstract class BaseMicroServicesVerticle extends AbstractVerticle {
-    protected static final String KEY_SERVICE_NAME = "service.name";
-    protected static final String KEY_HOST = "host";
-    protected static final String KEY_PORT = "port";
-    protected static final String KEY_ROOT = "root";
-    protected static final String KEY_NAME = "name";
-
+public abstract class BaseHttpMicroServicesVerticle extends BaseMicroServicesVerticle {
     private static final Logger logger = LoggerFactory.getLogger(BaseMicroServicesVerticle.class);

-    protected ServiceDiscovery discovery;
-    private Record publishedRecord;
-    private Map&amp;lt;String, CircuitBreaker=""&amp;gt; circuitBreakerMap = new ConcurrentHashMap&amp;lt;&amp;gt;();
-    private Map&amp;lt;String, Object=""&amp;gt; serviceEndPointMap = new ConcurrentHashMap&amp;lt;&amp;gt;();
+    /**
+     * Enable CORS
+     *
+     * @param router
+     */
+    protected void enableCorsSupport(Router router) {
+        Set&amp;lt;String&amp;gt; allowedHeaders = new HashSet&amp;lt;&amp;gt;();
+        allowedHeaders.add("x-requested-with");
+        allowedHeaders.add("Access-Control-Allow-Origin");
+        allowedHeaders.add("origin");
+        allowedHeaders.add("Content-Type");
+        allowedHeaders.add("accept");

-    @Override
-    public void start() {
-        logger.debug("Starting verticle - {}", this.getClass().getName());
-        logger.debug("Config:{}", this.config().encodePrettily());
-        this.discovery = ServiceDiscovery.create(vertx, new ServiceDiscoveryOptions().setBackendConfiguration(this.getServiceDiscoveryConfig()));
+        CorsHandler corsHandler = CorsHandler.create("*").allowedHeaders(allowedHeaders);
+        Arrays.asList(HttpMethod.values()).stream().forEach(method -&amp;gt; corsHandler.allowedMethod(method));
+        router.route().handler(corsHandler);
     }

-    @Override
-    public void stop() {
-        logger.debug("Stopping verticle - {}", this.getClass().getName());
-        this.serviceEndPointMap.keySet().stream().forEach(serviceName -&amp;gt; this.closeCachedEndPoint(serviceName));
-        this.serviceEndPointMap.clear();
-        this.circuitBreakerMap.values().stream().forEach(circuitBreaker -&amp;gt; circuitBreaker.close());
-        this.circuitBreakerMap.clear();
-        this.unpublishRecord().subscribe(b -&amp;gt; discovery.close());
+    protected void dispatchRequest(RoutingContext context, String serviceName, Handler errorHandler) {
+        logger.debug("Dispatch Http Request {} to service {}", context.request().uri(), serviceName);
+        this.getCircuitBreaker(serviceName).&amp;lt;Void&amp;gt;rxExecuteCommand(
+                future -&amp;gt; this.dispatchRequestHandler(context, serviceName, future))
+                .subscribe(v -&amp;gt; logger.debug("dispatch request completed"), errorHandler::handle);
     }

-    /**
-     * Return Service discovery configure, the default implementation store them in verticle's config()
-     *
-     * @return Service discovery configure
-     */
-    protected JsonObject getServiceDiscoveryConfig() {
-        return this.config();
+    protected void dispatchRequestHandler(RoutingContext context, String serviceName, Future&amp;lt;Void&amp;gt; future) {
+        this.getWebEndPoint(serviceName)
+                .subscribe(webClient -&amp;gt; invokeDispatchHttpRequest(context, webClient, future),
+                        throwable -&amp;gt; future.fail("Service [" + serviceName + "] not published"));
     }

-    /**
-     * Return circuit breaker of service by service name
-     *
-     * @param serviceName the name of service
-     * @return circuit breaker of service
-     */
-    protected final CircuitBreaker getCircuitBreaker(String serviceName) {
-        logger.debug("Get CircuitBreaker of service {}", serviceName);
-        CircuitBreaker circuitBreaker = circuitBreakerMap.get(serviceName);
-        if (null == circuitBreaker) {
-            circuitBreaker = this.createCircuitBreaker(serviceName);
-            this.circuitBreakerMap.put(serviceName, circuitBreaker);
+    private void invokeDispatchHttpRequest(RoutingContext context, WebClient webClient, Future&amp;lt;Void&amp;gt; future) {
+        logger.debug("invokeDispatchHttpRequest, uri:{}", context.request().uri());
+        HttpRequest&amp;lt;Buffer&amp;gt; httpRequest = webClient.request(context.request().method(), context.request().uri());
+        context.request().headers().getDelegate().forEach(header -&amp;gt; httpRequest.putHeader(header.getKey(), header.getValue()));
+        if (context.user() != null) {
+            httpRequest.putHeader("user-principal", context.user().principal().encode());
         }
-        return circuitBreaker;
-    }
-
-    /**
-     * Create circuit breaker for service
-     *
-     * @param serviceName the name of service
-     * @return circuit breaker of service
-     */
-    protected CircuitBreaker createCircuitBreaker(String serviceName) {
-        logger.debug("Create CircuitBreaker for service {}", serviceName);
-        String circuitBreakerName = serviceName + "-" + "circuit-breaker";
-        CircuitBreakerOptions options = new CircuitBreakerOptions()
-                .setMaxFailures(5)
-                .setTimeout(5000)
-                .setResetTimeout(10000)
-                .setFallbackOnFailure(true);
-        return CircuitBreaker.create(circuitBreakerName, vertx, options)
-                .openHandler(v -&amp;gt; {
-                    logger.debug("{} opened", circuitBreakerName);
-                    this.closeCachedEndPoint(serviceName);
-                })
-                .halfOpenHandler(v -&amp;gt; logger.debug("{} half opened", circuitBreakerName))
-                .closeHandler(v -&amp;gt; logger.debug("{} closed", circuitBreakerName));
-    }
-
-    /**
-     * Return an async HttpClient by service name
-     *
-     * @param serviceName the name of service
-     * @return
-     */
-    protected final Single&amp;lt;HttpClient&amp;gt; getHttpEndPoint(String serviceName) {
-        logger.debug("Get HTTP client by service name[{}]", serviceName);
-        Object endPoint = this.serviceEndPointMap.get(serviceName);
-        if (null != endPoint &amp;amp;&amp;amp; endPoint instanceof HttpClient) {
-            return Single.just((HttpClient) endPoint);
+        Single&amp;lt;HttpResponse&amp;lt;Buffer&amp;gt;&amp;gt; result;
+        if (null != context.request().formAttributes() &amp;amp;&amp;amp; !context.request().formAttributes().isEmpty()) {
+            result = httpRequest.rxSendForm(context.request().formAttributes());
+        } else if (null != context.getBody()) {
+            result = httpRequest.rxSendBuffer(context.getBody());
         } else {
-            return HttpEndpoint.rxGetClient(discovery, new JsonObject().put(KEY_NAME, serviceName))
-                    .doOnSuccess(httpClient -&amp;gt; this.serviceEndPointMap.put(serviceName, httpClient));
+            result = httpRequest.rxSend();
         }
-    }
-
-    /**
-     * Return an async HttpClient by service name
-     *
-     * @param serviceName the name of service
-     * @return
-     */
-    protected final Single&amp;lt;WebClient&amp;gt; getWebEndPoint(String serviceName) {
-        logger.debug("Get Web client by service name[{}]", serviceName);
-        Object endPoint = this.serviceEndPointMap.get(serviceName);
-        if (null != endPoint &amp;amp;&amp;amp; endPoint instanceof WebClient) {
-            return Single.just((WebClient) endPoint);
-        } else {
-            logger.debug("Getting Web client from ServiceDiscovery...");
-            return HttpEndpoint.rxGetWebClient(discovery, new JsonObject().put(KEY_NAME, serviceName))
-                    .doOnSuccess(webClient -&amp;gt; this.serviceEndPointMap.put(serviceName, webClient));
-        }
-    }
-
-    /**
-     * Publish a HttpEndPoint service to ServiceDiscovery
-     *
-     * @param config the configure of HttpEndPoint
-     * @return
-     */
-    protected final Single&amp;lt;Record&amp;gt; publishHttpEndPoint(JsonObject config) {
-        String serviceName = config.getString(KEY_SERVICE_NAME);
-        String host = config.getString(KEY_HOST, "localhost");
-        Integer port = config.getInteger(KEY_PORT, 8080);
-        String root = config.getString(KEY_ROOT, "/");
-        return this.publishRecord(HttpEndpoint.createRecord(serviceName, host, port, root));
-    }
-
-    /**
-     * Publish a service record to ServiceDiscovery
-     *
-     * @param record record to publish
-     * @return
-     */
-    protected Single&amp;lt;Record&amp;gt; publishRecord(Record record) {
-        return this.unpublishRecord()
-                .flatMap(b -&amp;gt; discovery.rxPublish(record))
-                .doOnSuccess(r -&amp;gt; this.publishedRecord = r);
-    }
-
-    /**
-     * Invoke a restful service by service name
-     *
-     * @param serviceName the name of service
-     * @param method      HTTP method
-     * @param uri         uri of request
-     * @param body        body of request
-     * @return result as JsonObject
-     */
-    protected Single&amp;lt;JsonObject&amp;gt; invokeRestfulService(String serviceName, HttpMethod method, String uri, JsonObject body) {
-        logger.debug("invokeRestfulService, service name:{}, uri:{}", serviceName, uri);
-        return this.getCircuitBreaker(serviceName).rxExecuteCommand(future -&amp;gt; this.getWebEndPoint(serviceName).subscribe(
-                webClient -&amp;gt; {
-                    HttpRequest request = webClient.request(method, uri);
-                    Single&amp;lt;HttpResponse&amp;lt;Buffer&amp;gt;&amp;gt; result;
-                    if (null == body) {
-                        result = request.rxSend();
-                    } else {
-                        result = request.rxSendJsonObject(body);
-                    }
-                    result.map(HttpResponse::bodyAsJsonObject).subscribe(future::complete, future::fail);
-                },
-                throwable -&amp;gt; future.fail("Service [" + serviceName + "] not found"))
-        );
-    }
-
-    /**
-     * Invoke a restful service by given host and port
-     *
-     * @param method HTTP method
-     * @param port   port of EndPoint
-     * @param host   host of EndPoint
-     * @param uri    uri of request
-     * @param body   body of request
-     * @return
-     */
-    protected Single&amp;lt;JsonObject&amp;gt; invokeRestful(HttpMethod method, int port, String host, String uri, JsonObject body) {
-        logger.debug("invokeRestfulService, host:{}, port:{}, uri:{}", host, port, uri);
-        HttpRequest&amp;lt;Buffer&amp;gt; request = WebClient.create(vertx).request(method, port, host, uri);
-        Single&amp;lt;HttpResponse&amp;lt;Buffer&amp;gt;&amp;gt; result;
-        if (null == body) {
-            result = request.rxSend();
-        } else {
-            result = request.rxSendJsonObject(body);
-        }
-        return result.map(HttpResponse::bodyAsJsonObject);
-    }
-
-    private Single&amp;lt;Boolean&amp;gt; unpublishRecord() {
-        return Single.create(emitter -&amp;gt; {
-            if (null != this.publishedRecord) {
-                discovery.rxUnpublish(this.publishedRecord.getRegistration())
-                        .subscribe(() -&amp;gt; {
-                            logger.debug("Service {} unpublished", this.publishedRecord.getName());
-                            this.publishedRecord = null;
-                            emitter.onSuccess(true);
-                        }, emitter::onError);
-            } else {
-                emitter.onSuccess(true);
+        result.subscribe(response -&amp;gt; {
+            if (!context.response().ended()) {
+                context.response().setStatusCode(response.statusCode());
+                response.headers().getDelegate().forEach(header -&amp;gt; context.response().putHeader(header.getKey(), header.getValue()));
+                context.response().end(response.body());
             }
-        });
-    }
-
-    private void closeCachedEndPoint(String serviceName) {
-        Object endPoint = this.serviceEndPointMap.get(serviceName);
-        if (null != endPoint) {
-            logger.debug("Close cached EndPoint for service {}", serviceName);
-            if (endPoint instanceof WebClient) {
-                ((WebClient) endPoint).close();
-            } else if (endPoint instanceof HttpClient) {
-                ((HttpClient) endPoint).close();
-            }
-            this.serviceEndPointMap.remove(serviceName);
-        }
+            future.complete();
+        }, future::fail);
     }
 }
 ~~~
&lt;/pre&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Gary Cheng</dc:creator><pubDate>Wed, 18 Apr 2018 01:46:57 -0000</pubDate><guid>https://sourceforge.net81317cfefc424eec83a0f039b4110569b030c14e</guid></item><item><title>BaseHttpMicroServicesVerticle modified by Gary Cheng</title><link>https://sourceforge.net/p/garyproject00/wiki/BaseHttpMicroServicesVerticle/</link><description>&lt;div class="markdown_content"&gt;&lt;pre&gt;--- v6
+++ v7
@@ -1,87 +1,246 @@
 ~~~
-package com.example.common;
+package com.example.microservices.com;

 import io.reactivex.Single;
-import io.vertx.core.Handler;
+import io.vertx.circuitbreaker.CircuitBreakerOptions;
 import io.vertx.core.http.HttpMethod;
-import io.vertx.reactivex.core.Future;
+import io.vertx.core.json.JsonObject;
+import io.vertx.reactivex.circuitbreaker.CircuitBreaker;
+import io.vertx.reactivex.core.AbstractVerticle;
 import io.vertx.reactivex.core.buffer.Buffer;
-import io.vertx.reactivex.ext.web.Router;
-import io.vertx.reactivex.ext.web.RoutingContext;
+import io.vertx.reactivex.core.http.HttpClient;
 import io.vertx.reactivex.ext.web.client.HttpRequest;
 import io.vertx.reactivex.ext.web.client.HttpResponse;
 import io.vertx.reactivex.ext.web.client.WebClient;
-import io.vertx.reactivex.ext.web.handler.CorsHandler;
+import io.vertx.reactivex.servicediscovery.ServiceDiscovery;
+import io.vertx.reactivex.servicediscovery.types.HttpEndpoint;
+import io.vertx.servicediscovery.Record;
+import io.vertx.servicediscovery.ServiceDiscoveryOptions;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;

-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Set;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;

 /**
- * The abstract verticle which work as HTTP server
+ * The base verticle class which provided some common functions include service discovery
  *
  * @author Gary Cheng
  */
-public abstract class BaseHttpMicroServicesVerticle extends BaseMicroServicesVerticle {
+public abstract class BaseMicroServicesVerticle extends AbstractVerticle {
+    protected static final String KEY_SERVICE_NAME = "service.name";
+    protected static final String KEY_HOST = "host";
+    protected static final String KEY_PORT = "port";
+    protected static final String KEY_ROOT = "root";
+    protected static final String KEY_NAME = "name";
+
     private static final Logger logger = LoggerFactory.getLogger(BaseMicroServicesVerticle.class);

-    /**
-     * Enable CORS
-     *
-     * @param router
-     */
-    protected void enableCorsSupport(Router router) {
-        Set&amp;lt;String&amp;gt; allowedHeaders = new HashSet&amp;lt;&amp;gt;();
-        allowedHeaders.add("x-requested-with");
-        allowedHeaders.add("Access-Control-Allow-Origin");
-        allowedHeaders.add("origin");
-        allowedHeaders.add("Content-Type");
-        allowedHeaders.add("accept");
-
-        CorsHandler corsHandler = CorsHandler.create("*").allowedHeaders(allowedHeaders);
-        Arrays.asList(HttpMethod.values()).stream().forEach(method -&amp;gt; corsHandler.allowedMethod(method));
-        router.route().handler(corsHandler);
-    }
-
-    protected void dispatchRequest(RoutingContext context, String serviceName, Handler errorHandler) {
-        logger.debug("Dispatch Http Request {} to service {}", context.request().uri(), serviceName);
-        this.getCircuitBreaker(serviceName).&amp;lt;Void&amp;gt;rxExecuteCommand(
-                future -&amp;gt; this.dispatchRequestHandler(context, serviceName, future))
-                .subscribe(v -&amp;gt; logger.debug("dispatch request completed"), errorHandler::handle);
-    }
-
-    protected void dispatchRequestHandler(RoutingContext context, String serviceName, Future&amp;lt;Void&amp;gt; future) {
-        this.getWebEndPoint(serviceName)
-                .subscribe(webClient -&amp;gt; invokeDispatchHttpRequest(context, webClient, future),
-                        throwable -&amp;gt; future.fail("Service [" + serviceName + "] not published"));
-    }
-
-    private void invokeDispatchHttpRequest(RoutingContext context, WebClient webClient, Future&amp;lt;Void&amp;gt; future) {
-        logger.debug("invokeDispatchHttpRequest, uri:{}", context.request().uri());
-        HttpRequest&amp;lt;Buffer&amp;gt; httpRequest = webClient.request(context.request().method(), context.request().uri());
-        context.request().headers().getDelegate().forEach(header -&amp;gt; httpRequest.putHeader(header.getKey(), header.getValue()));
-        if (context.user() != null) {
-            httpRequest.putHeader("user-principal", context.user().principal().encode());
-        }
+    protected ServiceDiscovery discovery;
+    private Record publishedRecord;
+    private Map&amp;lt;String, CircuitBreaker=""&amp;gt; circuitBreakerMap = new ConcurrentHashMap&amp;lt;&amp;gt;();
+    private Map&amp;lt;String, Object=""&amp;gt; serviceEndPointMap = new ConcurrentHashMap&amp;lt;&amp;gt;();
+
+    @Override
+    public void start() {
+        logger.debug("Starting verticle - {}", this.getClass().getName());
+        logger.debug("Config:{}", this.config().encodePrettily());
+        this.discovery = ServiceDiscovery.create(vertx, new ServiceDiscoveryOptions().setBackendConfiguration(this.getServiceDiscoveryConfig()));
+    }
+
+    @Override
+    public void stop() {
+        logger.debug("Stopping verticle - {}", this.getClass().getName());
+        this.serviceEndPointMap.keySet().stream().forEach(serviceName -&amp;gt; this.closeCachedEndPoint(serviceName));
+        this.serviceEndPointMap.clear();
+        this.circuitBreakerMap.values().stream().forEach(circuitBreaker -&amp;gt; circuitBreaker.close());
+        this.circuitBreakerMap.clear();
+        this.unpublishRecord().subscribe(b -&amp;gt; discovery.close());
+    }
+
+    /**
+     * Return Service discovery configure, the default implementation store them in verticle's config()
+     *
+     * @return Service discovery configure
+     */
+    protected JsonObject getServiceDiscoveryConfig() {
+        return this.config();
+    }
+
+    /**
+     * Return circuit breaker of service by service name
+     *
+     * @param serviceName the name of service
+     * @return circuit breaker of service
+     */
+    protected final CircuitBreaker getCircuitBreaker(String serviceName) {
+        logger.debug("Get CircuitBreaker of service {}", serviceName);
+        CircuitBreaker circuitBreaker = circuitBreakerMap.get(serviceName);
+        if (null == circuitBreaker) {
+            circuitBreaker = this.createCircuitBreaker(serviceName);
+            this.circuitBreakerMap.put(serviceName, circuitBreaker);
+        }
+        return circuitBreaker;
+    }
+
+    /**
+     * Create circuit breaker for service
+     *
+     * @param serviceName the name of service
+     * @return circuit breaker of service
+     */
+    protected CircuitBreaker createCircuitBreaker(String serviceName) {
+        logger.debug("Create CircuitBreaker for service {}", serviceName);
+        String circuitBreakerName = serviceName + "-" + "circuit-breaker";
+        CircuitBreakerOptions options = new CircuitBreakerOptions()
+                .setMaxFailures(5)
+                .setTimeout(5000)
+                .setResetTimeout(10000)
+                .setFallbackOnFailure(true);
+        return CircuitBreaker.create(circuitBreakerName, vertx, options)
+                .openHandler(v -&amp;gt; {
+                    logger.debug("{} opened", circuitBreakerName);
+                    this.closeCachedEndPoint(serviceName);
+                })
+                .halfOpenHandler(v -&amp;gt; logger.debug("{} half opened", circuitBreakerName))
+                .closeHandler(v -&amp;gt; logger.debug("{} closed", circuitBreakerName));
+    }
+
+    /**
+     * Return an async HttpClient by service name
+     *
+     * @param serviceName the name of service
+     * @return
+     */
+    protected final Single&amp;lt;HttpClient&amp;gt; getHttpEndPoint(String serviceName) {
+        logger.debug("Get HTTP client by service name[{}]", serviceName);
+        Object endPoint = this.serviceEndPointMap.get(serviceName);
+        if (null != endPoint &amp;amp;&amp;amp; endPoint instanceof HttpClient) {
+            return Single.just((HttpClient) endPoint);
+        } else {
+            return HttpEndpoint.rxGetClient(discovery, new JsonObject().put(KEY_NAME, serviceName))
+                    .doOnSuccess(httpClient -&amp;gt; this.serviceEndPointMap.put(serviceName, httpClient));
+        }
+    }
+
+    /**
+     * Return an async HttpClient by service name
+     *
+     * @param serviceName the name of service
+     * @return
+     */
+    protected final Single&amp;lt;WebClient&amp;gt; getWebEndPoint(String serviceName) {
+        logger.debug("Get Web client by service name[{}]", serviceName);
+        Object endPoint = this.serviceEndPointMap.get(serviceName);
+        if (null != endPoint &amp;amp;&amp;amp; endPoint instanceof WebClient) {
+            return Single.just((WebClient) endPoint);
+        } else {
+            logger.debug("Getting Web client from ServiceDiscovery...");
+            return HttpEndpoint.rxGetWebClient(discovery, new JsonObject().put(KEY_NAME, serviceName))
+                    .doOnSuccess(webClient -&amp;gt; this.serviceEndPointMap.put(serviceName, webClient));
+        }
+    }
+
+    /**
+     * Publish a HttpEndPoint service to ServiceDiscovery
+     *
+     * @param config the configure of HttpEndPoint
+     * @return
+     */
+    protected final Single&amp;lt;Record&amp;gt; publishHttpEndPoint(JsonObject config) {
+        String serviceName = config.getString(KEY_SERVICE_NAME);
+        String host = config.getString(KEY_HOST, "localhost");
+        Integer port = config.getInteger(KEY_PORT, 8080);
+        String root = config.getString(KEY_ROOT, "/");
+        return this.publishRecord(HttpEndpoint.createRecord(serviceName, host, port, root));
+    }
+
+    /**
+     * Publish a service record to ServiceDiscovery
+     *
+     * @param record record to publish
+     * @return
+     */
+    protected Single&amp;lt;Record&amp;gt; publishRecord(Record record) {
+        return this.unpublishRecord()
+                .flatMap(b -&amp;gt; discovery.rxPublish(record))
+                .doOnSuccess(r -&amp;gt; this.publishedRecord = r);
+    }
+
+    /**
+     * Invoke a restful service by service name
+     *
+     * @param serviceName the name of service
+     * @param method      HTTP method
+     * @param uri         uri of request
+     * @param body        body of request
+     * @return result as JsonObject
+     */
+    protected Single&amp;lt;JsonObject&amp;gt; invokeRestfulService(String serviceName, HttpMethod method, String uri, JsonObject body) {
+        logger.debug("invokeRestfulService, service name:{}, uri:{}", serviceName, uri);
+        return this.getCircuitBreaker(serviceName).rxExecuteCommand(future -&amp;gt; this.getWebEndPoint(serviceName).subscribe(
+                webClient -&amp;gt; {
+                    HttpRequest request = webClient.request(method, uri);
+                    Single&amp;lt;HttpResponse&amp;lt;Buffer&amp;gt;&amp;gt; result;
+                    if (null == body) {
+                        result = request.rxSend();
+                    } else {
+                        result = request.rxSendJsonObject(body);
+                    }
+                    result.map(HttpResponse::bodyAsJsonObject).subscribe(future::complete, future::fail);
+                },
+                throwable -&amp;gt; future.fail("Service [" + serviceName + "] not found"))
+        );
+    }
+
+    /**
+     * Invoke a restful service by given host and port
+     *
+     * @param method HTTP method
+     * @param port   port of EndPoint
+     * @param host   host of EndPoint
+     * @param uri    uri of request
+     * @param body   body of request
+     * @return
+     */
+    protected Single&amp;lt;JsonObject&amp;gt; invokeRestful(HttpMethod method, int port, String host, String uri, JsonObject body) {
+        logger.debug("invokeRestfulService, host:{}, port:{}, uri:{}", host, port, uri);
+        HttpRequest&amp;lt;Buffer&amp;gt; request = WebClient.create(vertx).request(method, port, host, uri);
         Single&amp;lt;HttpResponse&amp;lt;Buffer&amp;gt;&amp;gt; result;
-        if (null != context.request().formAttributes() &amp;amp;&amp;amp; !context.request().formAttributes().isEmpty()) {
-            result = httpRequest.rxSendForm(context.request().formAttributes());
-        } else if (null != context.getBody()) {
-            result = httpRequest.rxSendBuffer(context.getBody());
+        if (null == body) {
+            result = request.rxSend();
         } else {
-            result = httpRequest.rxSend();
-        }
-        result.subscribe(response -&amp;gt; {
-            if (!context.response().ended()) {
-                context.response().setStatusCode(response.statusCode());
-                response.headers().getDelegate().forEach(header -&amp;gt; context.response().putHeader(header.getKey(), header.getValue()));
-                context.response().end(response.body());
+            result = request.rxSendJsonObject(body);
+        }
+        return result.map(HttpResponse::bodyAsJsonObject);
+    }
+
+    private Single&amp;lt;Boolean&amp;gt; unpublishRecord() {
+        return Single.create(emitter -&amp;gt; {
+            if (null != this.publishedRecord) {
+                discovery.rxUnpublish(this.publishedRecord.getRegistration())
+                        .subscribe(() -&amp;gt; {
+                            logger.debug("Service {} unpublished", this.publishedRecord.getName());
+                            this.publishedRecord = null;
+                            emitter.onSuccess(true);
+                        }, emitter::onError);
+            } else {
+                emitter.onSuccess(true);
             }
-            future.complete();
-        }, future::fail);
+        });
+    }
+
+    private void closeCachedEndPoint(String serviceName) {
+        Object endPoint = this.serviceEndPointMap.get(serviceName);
+        if (null != endPoint) {
+            logger.debug("Close cached EndPoint for service {}", serviceName);
+            if (endPoint instanceof WebClient) {
+                ((WebClient) endPoint).close();
+            } else if (endPoint instanceof HttpClient) {
+                ((HttpClient) endPoint).close();
+            }
+            this.serviceEndPointMap.remove(serviceName);
+        }
     }
 }
-
 ~~~
&lt;/pre&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Gary Cheng</dc:creator><pubDate>Wed, 18 Apr 2018 01:44:50 -0000</pubDate><guid>https://sourceforge.net5b40cd51ac75d94372e1ea0a7427c8aaac09cc1a</guid></item><item><title>BaseHttpMicroServicesVerticle modified by Gary Cheng</title><link>https://sourceforge.net/p/garyproject00/wiki/BaseHttpMicroServicesVerticle/</link><description>&lt;div class="markdown_content"&gt;&lt;pre&gt;--- v5
+++ v6
@@ -1,12 +1,16 @@
 ~~~
-package com.example.microservices.com;
+package com.example.common;

+import io.reactivex.Single;
 import io.vertx.core.Handler;
 import io.vertx.core.http.HttpMethod;
-import io.vertx.reactivex.core.http.HttpClient;
-import io.vertx.reactivex.core.http.HttpClientRequest;
+import io.vertx.reactivex.core.Future;
+import io.vertx.reactivex.core.buffer.Buffer;
 import io.vertx.reactivex.ext.web.Router;
 import io.vertx.reactivex.ext.web.RoutingContext;
+import io.vertx.reactivex.ext.web.client.HttpRequest;
+import io.vertx.reactivex.ext.web.client.HttpResponse;
+import io.vertx.reactivex.ext.web.client.WebClient;
 import io.vertx.reactivex.ext.web.handler.CorsHandler;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -41,58 +45,42 @@
         router.route().handler(corsHandler);
     }

-    /**
-     * Dispatch a http request to MicroServices http end point
-     *
-     * @param context
-     * @param serviceName
-     * @param errorHandler
-     */
-    protected void dispatchHttpRequest(RoutingContext context, String serviceName, Handler errorHandler) {
+    protected void dispatchRequest(RoutingContext context, String serviceName, Handler errorHandler) {
         logger.debug("Dispatch Http Request {} to service {}", context.request().uri(), serviceName);
-        this.getCircuitBreaker(serviceName).rxExecuteCommandWithFallback(
-                future -&amp;gt; this.getServiceHttpClient(serviceName)
-                        .subscribe(httpClient -&amp;gt; this.doDispatchHttpRequest(context, httpClient, future),
-                                throwable -&amp;gt; future.fail("Service [" + serviceName + "] not published")),
-                throwable -&amp;gt; this.circuitFallback(errorHandler, throwable))
-                .subscribe(v -&amp;gt; logger.debug("dispatch request completed"));
+        this.getCircuitBreaker(serviceName).&amp;lt;Void&amp;gt;rxExecuteCommand(
+                future -&amp;gt; this.dispatchRequestHandler(context, serviceName, future))
+                .subscribe(v -&amp;gt; logger.debug("dispatch request completed"), errorHandler::handle);
     }

-    private Void circuitFallback(Handler errorHandler, Throwable throwable) {
-        errorHandler.handle(throwable);
-        return null;
+    protected void dispatchRequestHandler(RoutingContext context, String serviceName, Future&amp;lt;Void&amp;gt; future) {
+        this.getWebEndPoint(serviceName)
+                .subscribe(webClient -&amp;gt; invokeDispatchHttpRequest(context, webClient, future),
+                        throwable -&amp;gt; future.fail("Service [" + serviceName + "] not published"));
     }

-    private void doDispatchHttpRequest(RoutingContext context, HttpClient httpClient, io.vertx.reactivex.core.Future&amp;lt;Void&amp;gt; future) {
-        logger.debug("doDispatchHttpRequest, uri:{}", context.request().uri());
-        HttpClientRequest clientRequest = httpClient.request(context.request().method(), context.request().uri());
-        this.addHttpResponseHandler(context, clientRequest, future);
-        context.request().headers().getDelegate().forEach(header -&amp;gt; clientRequest.putHeader(header.getKey(), header.getValue()));
+    private void invokeDispatchHttpRequest(RoutingContext context, WebClient webClient, Future&amp;lt;Void&amp;gt; future) {
+        logger.debug("invokeDispatchHttpRequest, uri:{}", context.request().uri());
+        HttpRequest&amp;lt;Buffer&amp;gt; httpRequest = webClient.request(context.request().method(), context.request().uri());
+        context.request().headers().getDelegate().forEach(header -&amp;gt; httpRequest.putHeader(header.getKey(), header.getValue()));
         if (context.user() != null) {
-            clientRequest.putHeader("user-principal", context.user().principal().encode());
+            httpRequest.putHeader("user-principal", context.user().principal().encode());
         }
-        if (null != context.getBody()) {
-            clientRequest.end(context.getBody());
+        Single&amp;lt;HttpResponse&amp;lt;Buffer&amp;gt;&amp;gt; result;
+        if (null != context.request().formAttributes() &amp;amp;&amp;amp; !context.request().formAttributes().isEmpty()) {
+            result = httpRequest.rxSendForm(context.request().formAttributes());
+        } else if (null != context.getBody()) {
+            result = httpRequest.rxSendBuffer(context.getBody());
         } else {
-            clientRequest.end();
+            result = httpRequest.rxSend();
         }
-    }
-
-    private void addHttpResponseHandler(RoutingContext context, HttpClientRequest clientRequest, io.vertx.reactivex.core.Future&amp;lt;Void&amp;gt; future) {
-        clientRequest.toFlowable()
-                .flatMap(response -&amp;gt; {
-                    if (!context.response().ended()) {
-                        context.response().setStatusCode(response.statusCode());
-                        response.headers().getDelegate().forEach(header -&amp;gt; context.response().putHeader(header.getKey(), header.getValue()));
-                    }
-                    return response.toFlowable();
-                })
-                .subscribe(buffer -&amp;gt; {
-                    if (!context.response().ended()) {
-                        context.response().end(buffer);
-                    }
-                    future.complete();
-                }, future::fail);
+        result.subscribe(response -&amp;gt; {
+            if (!context.response().ended()) {
+                context.response().setStatusCode(response.statusCode());
+                response.headers().getDelegate().forEach(header -&amp;gt; context.response().putHeader(header.getKey(), header.getValue()));
+                context.response().end(response.body());
+            }
+            future.complete();
+        }, future::fail);
     }
 }

&lt;/pre&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Gary Cheng</dc:creator><pubDate>Mon, 16 Apr 2018 20:17:40 -0000</pubDate><guid>https://sourceforge.net47216aacb7845e09d54d15403f816300466839e8</guid></item><item><title>BaseHttpMicroServicesVerticle modified by Gary Cheng</title><link>https://sourceforge.net/p/garyproject00/wiki/BaseHttpMicroServicesVerticle/</link><description>&lt;div class="markdown_content"&gt;&lt;pre&gt;--- v4
+++ v5
@@ -1,140 +1,99 @@
-#### RxEventBusApp .java
 ~~~
-package com.example.rx;
+package com.example.microservices.com;

-import io.reactivex.Single;
-import io.vertx.core.DeploymentOptions;
-import io.vertx.core.json.JsonObject;
-import io.vertx.reactivex.core.Vertx;
+import io.vertx.core.Handler;
+import io.vertx.core.http.HttpMethod;
+import io.vertx.reactivex.core.http.HttpClient;
+import io.vertx.reactivex.core.http.HttpClientRequest;
+import io.vertx.reactivex.ext.web.Router;
+import io.vertx.reactivex.ext.web.RoutingContext;
+import io.vertx.reactivex.ext.web.handler.CorsHandler;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;

+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;

-public class RxEventBusApp {
-    private static final Logger logger = LoggerFactory.getLogger(RxEventBusApp.class);
+/**
+ * The abstract verticle which work as HTTP server
+ *
+ * @author Gary Cheng
+ */
+public abstract class BaseHttpMicroServicesVerticle extends BaseMicroServicesVerticle {
+    private static final Logger logger = LoggerFactory.getLogger(BaseMicroServicesVerticle.class);

-    public static void main(String[] args) {
-        Vertx vertx = Vertx.vertx();
+    /**
+     * Enable CORS
+     *
+     * @param router
+     */
+    protected void enableCorsSupport(Router router) {
+        Set&amp;lt;String&amp;gt; allowedHeaders = new HashSet&amp;lt;&amp;gt;();
+        allowedHeaders.add("x-requested-with");
+        allowedHeaders.add("Access-Control-Allow-Origin");
+        allowedHeaders.add("origin");
+        allowedHeaders.add("Content-Type");
+        allowedHeaders.add("accept");

-        deployReceiver(vertx, "Receiver 1")
-                .flatMap(deploymentId -&amp;gt; deployReceiver(vertx, "Receiver 2"))
-                .flatMap(deploymentId -&amp;gt; vertx.rxDeployVerticle(RxEventBusSenderVerticle.class.getName()))
-                .subscribe(deploymentId -&amp;gt; logger.debug("Deployment completed"));
+        CorsHandler corsHandler = CorsHandler.create("*").allowedHeaders(allowedHeaders);
+        Arrays.asList(HttpMethod.values()).stream().forEach(method -&amp;gt; corsHandler.allowedMethod(method));
+        router.route().handler(corsHandler);
     }

-    private static Single&amp;lt;String&amp;gt; deployReceiver(Vertx vertx, String name) {
-        JsonObject config = new JsonObject();
-        config.put("name", name);
-        return vertx.rxDeployVerticle(RxEventBusReceiverVerticle.class.getName(), new DeploymentOptions().setConfig(config));
-    }
-}
-~~~
-
-### V2
-~~~
-package com.example.rx;
-
-import io.reactivex.Single;
-import io.vertx.core.DeploymentOptions;
-import io.vertx.core.json.JsonObject;
-import io.vertx.reactivex.core.Vertx;
-import io.vertx.reactivex.core.eventbus.EventBus;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-
-public class RxEventBusApp {
-    private static final Logger logger = LoggerFactory.getLogger(RxEventBusApp.class);
-    private Vertx vertx;
-
-    private RxEventBusApp() throws InterruptedException {
-        logger.debug("RxEventBusApp staring");
-        this.vertx = Vertx.vertx();
-        Single&amp;lt;String&amp;gt; deployment1 = deployReceiver("Receiver 1");
-        Single&amp;lt;String&amp;gt; deployment2 = deployReceiver("Receiver 2");
-        Single.zipArray(ids -&amp;gt; ids, deployment1, deployment2).blockingGet();
-        this.sendMessages();
+    /**
+     * Dispatch a http request to MicroServices http end point
+     *
+     * @param context
+     * @param serviceName
+     * @param errorHandler
+     */
+    protected void dispatchHttpRequest(RoutingContext context, String serviceName, Handler errorHandler) {
+        logger.debug("Dispatch Http Request {} to service {}", context.request().uri(), serviceName);
+        this.getCircuitBreaker(serviceName).rxExecuteCommandWithFallback(
+                future -&amp;gt; this.getServiceHttpClient(serviceName)
+                        .subscribe(httpClient -&amp;gt; this.doDispatchHttpRequest(context, httpClient, future),
+                                throwable -&amp;gt; future.fail("Service [" + serviceName + "] not published")),
+                throwable -&amp;gt; this.circuitFallback(errorHandler, throwable))
+                .subscribe(v -&amp;gt; logger.debug("dispatch request completed"));
     }

-    public static void main(String[] args) throws InterruptedException {
-        new RxEventBusApp();
+    private Void circuitFallback(Handler errorHandler, Throwable throwable) {
+        errorHandler.handle(throwable);
+        return null;
     }

-    private Single&amp;lt;String&amp;gt; deployReceiver(String name) {
-        JsonObject config = new JsonObject();
-        config.put("name", name);
-        return this.vertx.rxDeployVerticle(RxEventBusReceiverVerticle.class.getName(), new DeploymentOptions().setConfig(config));
+    private void doDispatchHttpRequest(RoutingContext context, HttpClient httpClient, io.vertx.reactivex.core.Future&amp;lt;Void&amp;gt; future) {
+        logger.debug("doDispatchHttpRequest, uri:{}", context.request().uri());
+        HttpClientRequest clientRequest = httpClient.request(context.request().method(), context.request().uri());
+        this.addHttpResponseHandler(context, clientRequest, future);
+        context.request().headers().getDelegate().forEach(header -&amp;gt; clientRequest.putHeader(header.getKey(), header.getValue()));
+        if (context.user() != null) {
+            clientRequest.putHeader("user-principal", context.user().principal().encode());
+        }
+        if (null != context.getBody()) {
+            clientRequest.end(context.getBody());
+        } else {
+            clientRequest.end();
+        }
     }

-    private void sendMessages() throws InterruptedException {
-        logger.debug("Start send messages to event bus");
-        EventBus eventBus = vertx.eventBus();
-        eventBus.publish("anAddress", "Published a message");
-        eventBus.rxSend("anAddress", "Sent a message")
-                .subscribe(reply -&amp;gt; {
-                    logger.debug("Received reply:{}", reply.body());
-                    reply.reply("replied to reply");
-                });
-        logger.debug("send message completed");
+    private void addHttpResponseHandler(RoutingContext context, HttpClientRequest clientRequest, io.vertx.reactivex.core.Future&amp;lt;Void&amp;gt; future) {
+        clientRequest.toFlowable()
+                .flatMap(response -&amp;gt; {
+                    if (!context.response().ended()) {
+                        context.response().setStatusCode(response.statusCode());
+                        response.headers().getDelegate().forEach(header -&amp;gt; context.response().putHeader(header.getKey(), header.getValue()));
+                    }
+                    return response.toFlowable();
+                })
+                .subscribe(buffer -&amp;gt; {
+                    if (!context.response().ended()) {
+                        context.response().end(buffer);
+                    }
+                    future.complete();
+                }, future::fail);
     }
 }

 ~~~
-#### RxEventBusSenderVerticle .java
-~~~
-package com.example.rx;
-
-import io.vertx.reactivex.core.AbstractVerticle;
-import io.vertx.reactivex.core.eventbus.EventBus;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class RxEventBusSenderVerticle extends AbstractVerticle {
-    private static final Logger logger = LoggerFactory.getLogger(RxEventBusSenderVerticle.class);
-
-    @Override
-    public void start() throws Exception {
-        logger.debug("Start Sender verticle");
-        EventBus eventBus = vertx.eventBus();
-        eventBus.publish("anAddress", "Published a message");
-        eventBus.
-                rxSend("anAddress", "Sent a message")
-                .subscribe(reply -&amp;gt; {
-                    logger.debug("Received reply:{}", reply.body());
-                    reply.reply("replied to reply");
-                });
-    }
-}
-~~~
-
-#### RxEventBusReceiverVerticle .java
-~~~
-package com.example.rx;
-
-import io.vertx.reactivex.core.AbstractVerticle;
-import io.vertx.reactivex.core.eventbus.Message;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class RxEventBusReceiverVerticle extends AbstractVerticle {
-    private static final Logger logger = LoggerFactory.getLogger(RxEventBusReceiverVerticle.class);
-    private String name;
-
-    @Override
-    public void start() throws Exception {
-        this.name = config().getString("name");
-        logger.debug("Start Receiver verticle, name:{}", name);
-        vertx.eventBus()
-                .&amp;lt;String&amp;gt;consumer("anAddress")
-                .toFlowable()
-                .subscribe(message -&amp;gt; this.onMessage(message));
-    }
-
-    private void onMessage(Message&amp;lt;String&amp;gt; message) {
-        logger.debug("{} Received message: {}", this.name, message.body());
-        String replyMessage = "Message replied from receiver[" + this.name + "]";
-        message.&amp;lt;String&amp;gt;rxReply(replyMessage).
-                subscribe(result -&amp;gt; logger.debug("Received message after replied:{}", result.body()));
-    }
-}
-~~~
&lt;/pre&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Gary Cheng</dc:creator><pubDate>Sun, 15 Apr 2018 23:26:44 -0000</pubDate><guid>https://sourceforge.net2c78bd00fb190c02dbbfa0e7e02f290ae68be1b7</guid></item><item><title>Vertx.EventBus modified by Gary Cheng</title><link>https://sourceforge.net/p/garyproject00/wiki/Vertx.EventBus/</link><description>&lt;div class="markdown_content"&gt;&lt;pre&gt;--- v3
+++ v4
@@ -35,7 +35,6 @@
 package com.example.rx;

 import io.reactivex.Single;
-import io.reactivex.schedulers.Schedulers;
 import io.vertx.core.DeploymentOptions;
 import io.vertx.core.json.JsonObject;
 import io.vertx.reactivex.core.Vertx;
@@ -48,16 +47,16 @@
     private static final Logger logger = LoggerFactory.getLogger(RxEventBusApp.class);
     private Vertx vertx;

-    private RxEventBusApp() {
+    private RxEventBusApp() throws InterruptedException {
         logger.debug("RxEventBusApp staring");
         this.vertx = Vertx.vertx();
-        deployReceiver("Receiver 1")
-                .flatMap(deploymentId -&amp;gt; deployReceiver("Receiver 2"))
-                .subscribe(this::sendMessages);
-        logger.debug("RxEventBusApp started");
+        Single&amp;lt;String&amp;gt; deployment1 = deployReceiver("Receiver 1");
+        Single&amp;lt;String&amp;gt; deployment2 = deployReceiver("Receiver 2");
+        Single.zipArray(ids -&amp;gt; ids, deployment1, deployment2).blockingGet();
+        this.sendMessages();
     }

-    public static void main(String[] args) {
+    public static void main(String[] args) throws InterruptedException {
         new RxEventBusApp();
     }

@@ -67,18 +66,15 @@
         return this.vertx.rxDeployVerticle(RxEventBusReceiverVerticle.class.getName(), new DeploymentOptions().setConfig(config));
     }

-    private void sendMessages(String deploymentId) throws InterruptedException {
-        logger.debug("Receivers deployed successful, deploymentId:{}", deploymentId);
+    private void sendMessages() throws InterruptedException {
         logger.debug("Start send messages to event bus");
         EventBus eventBus = vertx.eventBus();
         eventBus.publish("anAddress", "Published a message");
         eventBus.rxSend("anAddress", "Sent a message")
-                .subscribeOn(Schedulers.io())
                 .subscribe(reply -&amp;gt; {
                     logger.debug("Received reply:{}", reply.body());
                     reply.reply("replied to reply");
                 });
-        Thread.sleep(5000);
         logger.debug("send message completed");
     }
 }
&lt;/pre&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Gary Cheng</dc:creator><pubDate>Mon, 02 Apr 2018 17:00:14 -0000</pubDate><guid>https://sourceforge.net9b9939e392924727646e7943a9e1a1bf2458997e</guid></item><item><title>Vertx.EventBus modified by Gary Cheng</title><link>https://sourceforge.net/p/garyproject00/wiki/Vertx.EventBus/</link><description>&lt;div class="markdown_content"&gt;&lt;pre&gt;--- v2
+++ v3
@@ -30,6 +30,60 @@
 }
 ~~~

+### V2
+~~~
+package com.example.rx;
+
+import io.reactivex.Single;
+import io.reactivex.schedulers.Schedulers;
+import io.vertx.core.DeploymentOptions;
+import io.vertx.core.json.JsonObject;
+import io.vertx.reactivex.core.Vertx;
+import io.vertx.reactivex.core.eventbus.EventBus;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class RxEventBusApp {
+    private static final Logger logger = LoggerFactory.getLogger(RxEventBusApp.class);
+    private Vertx vertx;
+
+    private RxEventBusApp() {
+        logger.debug("RxEventBusApp staring");
+        this.vertx = Vertx.vertx();
+        deployReceiver("Receiver 1")
+                .flatMap(deploymentId -&amp;gt; deployReceiver("Receiver 2"))
+                .subscribe(this::sendMessages);
+        logger.debug("RxEventBusApp started");
+    }
+
+    public static void main(String[] args) {
+        new RxEventBusApp();
+    }
+
+    private Single&amp;lt;String&amp;gt; deployReceiver(String name) {
+        JsonObject config = new JsonObject();
+        config.put("name", name);
+        return this.vertx.rxDeployVerticle(RxEventBusReceiverVerticle.class.getName(), new DeploymentOptions().setConfig(config));
+    }
+
+    private void sendMessages(String deploymentId) throws InterruptedException {
+        logger.debug("Receivers deployed successful, deploymentId:{}", deploymentId);
+        logger.debug("Start send messages to event bus");
+        EventBus eventBus = vertx.eventBus();
+        eventBus.publish("anAddress", "Published a message");
+        eventBus.rxSend("anAddress", "Sent a message")
+                .subscribeOn(Schedulers.io())
+                .subscribe(reply -&amp;gt; {
+                    logger.debug("Received reply:{}", reply.body());
+                    reply.reply("replied to reply");
+                });
+        Thread.sleep(5000);
+        logger.debug("send message completed");
+    }
+}
+
+~~~
 #### RxEventBusSenderVerticle .java
 ~~~
 package com.example.rx;
&lt;/pre&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Gary Cheng</dc:creator><pubDate>Mon, 02 Apr 2018 15:58:35 -0000</pubDate><guid>https://sourceforge.netdaa8c4c07a73ff5a8d293e4630572827d5965529</guid></item><item><title>Vertx.EventBus modified by Gary Cheng</title><link>https://sourceforge.net/p/garyproject00/wiki/Vertx.EventBus/</link><description>&lt;div class="markdown_content"&gt;&lt;pre&gt;--- v1
+++ v2
@@ -1,3 +1,4 @@
+#### RxEventBusApp .java
 ~~~
 package com.example.rx;

@@ -27,12 +28,11 @@
         return vertx.rxDeployVerticle(RxEventBusReceiverVerticle.class.getName(), new DeploymentOptions().setConfig(config));
     }
 }
-
 ~~~

+#### RxEventBusSenderVerticle .java
 ~~~
 package com.example.rx;
-

 import io.vertx.reactivex.core.AbstractVerticle;
 import io.vertx.reactivex.core.eventbus.EventBus;
@@ -57,9 +57,9 @@
 }
 ~~~

+#### RxEventBusReceiverVerticle .java
 ~~~
 package com.example.rx;
-

 import io.vertx.reactivex.core.AbstractVerticle;
 import io.vertx.reactivex.core.eventbus.Message;
&lt;/pre&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Gary Cheng</dc:creator><pubDate>Mon, 02 Apr 2018 12:52:46 -0000</pubDate><guid>https://sourceforge.netd8bd85a51e2b01f93585392bfc90ce8a577c1c5b</guid></item></channel></rss>