<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Recent changes to ServiceDiscovery</title><link>https://sourceforge.net/p/garyproject00/wiki/ServiceDiscovery/</link><description>Recent changes to ServiceDiscovery</description><atom:link href="https://sourceforge.net/p/garyproject00/wiki/ServiceDiscovery/feed" rel="self"/><language>en</language><lastBuildDate>Fri, 13 Apr 2018 19:53:56 -0000</lastBuildDate><atom:link href="https://sourceforge.net/p/garyproject00/wiki/ServiceDiscovery/feed" rel="self" type="application/rss+xml"/><item><title>ServiceDiscovery modified by Gary Cheng</title><link>https://sourceforge.net/p/garyproject00/wiki/ServiceDiscovery/</link><description>&lt;div class="markdown_content"&gt;&lt;pre&gt;--- v3
+++ v4
@@ -1,41 +1,275 @@
-GatewayVerticle
-
-~~~
-package com.example.discovery;
-
-import io.vertx.core.Future;
-import io.vertx.core.VertxOptions;
+~~~
+package com.example.common;
+
+import io.reactivex.Completable;
+import io.reactivex.Single;
+import io.vertx.circuitbreaker.CircuitBreakerOptions;
+import io.vertx.core.impl.ConcurrentHashSet;
 import io.vertx.core.json.JsonObject;
+import io.vertx.reactivex.circuitbreaker.CircuitBreaker;
 import io.vertx.reactivex.core.AbstractVerticle;
-import io.vertx.reactivex.core.Vertx;
+import io.vertx.reactivex.core.http.HttpClient;
+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.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * The base verticle class which provided some common functions include service discovery
+ *
+ * @author Gary Cheng
+ */
+public abstract class BaseMicroServicesVerticle extends AbstractVerticle {
+    public static final String KEY_SERVICE_NAME = "service.name";
+    public static final String KEY_HOST = "host";
+    public static final String KEY_PORT = "port";
+    public static final String KEY_ROOT = "root";
+    private static final String KEY_NAME = "name";
+
+    private static final Logger logger = LoggerFactory.getLogger(BaseMicroServicesVerticle.class);
+
+    protected ServiceDiscovery discovery;
+    private Collection&amp;lt;Record&amp;gt; publishedRecords = new ConcurrentHashSet&amp;lt;&amp;gt;();
+    private Map&amp;lt;String, CircuitBreaker=""&amp;gt; circuitBreakerMap = new ConcurrentHashMap&amp;lt;&amp;gt;();
+    private Map&amp;lt;String, Object=""&amp;gt; serviceClientMap = 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());
+        if (null != discovery) {
+            List&amp;lt;Completable&amp;gt; completables = new ArrayList&amp;lt;&amp;gt;();
+            publishedRecords.forEach(record -&amp;gt; completables.add(discovery.rxUnpublish(record.getRegistration())));
+            Completable.merge(completables)
+                    .subscribe(() -&amp;gt; {
+                        logger.debug("All services have been un-published");
+                        discovery.close();
+                    });
+        }
+    }
+
+    /**
+     * Return Service discovery configure, the default implementation store them in verticle's config()
+     *
+     * @return
+     */
+    protected JsonObject getServiceDiscoveryConfig() {
+        return this.config();
+    }
+
+    /**
+     * Return circuit breaker of service by service name
+     *
+     * @param serviceName the name of service
+     * @return
+     */
+    protected final CircuitBreaker getCircuitBreaker(String 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
+     */
+    protected CircuitBreaker createCircuitBreaker(String serviceName) {
+        logger.debug("create circuit breaker 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))
+                .halfOpenHandler(v -&amp;gt; logger.debug("{} half opened", circuitBreakerName))
+                .closeHandler(v -&amp;gt; logger.debug("{} closed", circuitBreakerName));
+    }
+
+    /**
+     * Lookup ServiceDiscovery by service name and return an async HttpClient
+     *
+     * @param serviceName
+     * @return
+     */
+    protected final Single&amp;lt;HttpClient&amp;gt; getServiceHttpClient(String serviceName) {
+        logger.debug("Get HTTP client by service name[{}]", serviceName);
+        Object serviceClient = this.serviceClientMap.get(serviceName);
+        if (null != serviceClient) {
+            return Single.just((HttpClient) serviceClient);
+        } else {
+            return HttpEndpoint.rxGetClient(discovery, new JsonObject().put(KEY_NAME, serviceName))
+                    .doOnSuccess(httpClient -&amp;gt; this.serviceClientMap.put(serviceName, httpClient));
+        }
+    }
+
+    /**
+     * 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
+     */
+    private Single&amp;lt;Record&amp;gt; publishRecord(Record record) {
+        return discovery.rxPublish(record)
+                .flatMap(r -&amp;gt; {
+                    logger.debug("Service {} has been published", record.getName());
+                    this.publishedRecords.add(r);
+                    return Single.just(r);
+                });
+    }
+}
+
+~~~
+~~~
+package com.example.common;
+
+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;
+
+/**
+ * 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);
+
+    /**
+     * 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 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.executeDispatchHttpRequest(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"));
+    }
+
+    private Void circuitFallback(Handler errorHandler, Throwable throwable) {
+        errorHandler.handle(throwable);
+        return null;
+    }
+
+    private void executeDispatchHttpRequest(RoutingContext context, HttpClient httpClient, io.vertx.reactivex.core.Future&amp;lt;Void&amp;gt; future) {
+        logger.debug("executeDispatchHttpRequest, uri:{}", context.request().uri());
+        HttpClientRequest clientRequest = httpClient.request(context.request().method(), context.request().uri());
+        clientRequest.toFlowable()
+                .flatMap(response -&amp;gt; {
+                    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; {
+                    context.response().end(buffer);
+                    future.complete();
+                }, future::fail);
+        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();
+        }
+    }
+}
+
+~~~
+
+~~~
+package com.example.discovery;
+
+import com.example.common.BaseHttpMicroServicesVerticle;
+import io.vertx.core.Future;
+import io.vertx.core.VertxOptions;
+import io.vertx.core.json.JsonObject;
+import io.vertx.reactivex.core.Vertx;
+import io.vertx.reactivex.ext.web.Router;
+import io.vertx.reactivex.ext.web.RoutingContext;
 import io.vertx.reactivex.ext.web.handler.BodyHandler;
-import io.vertx.reactivex.servicediscovery.ServiceDiscovery;
-import io.vertx.reactivex.servicediscovery.types.HttpEndpoint;
 import io.vertx.servicediscovery.rest.ServiceDiscoveryRestEndpoint;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;

-public class GatewayVerticle extends AbstractVerticle {
-    private static final Logger logger = LoggerFactory.getLogger(GatewayVerticle.class);
+public class ApiGatewayVerticle extends BaseHttpMicroServicesVerticle {
+    private static final Logger logger = LoggerFactory.getLogger(ApiGatewayVerticle.class);
     private static final int PORT = 8080;
     private static final String PREFIX_SERVICE = "/service/";
-    private ServiceDiscovery discovery;

     public static void main(String[] args) throws InterruptedException {
         Vertx.rxClusteredVertx(new VertxOptions().setClustered(true))
-                .flatMap(vertx -&amp;gt; vertx.rxDeployVerticle(GatewayVerticle.class.getName()))
+                .flatMap(vertx -&amp;gt; vertx.rxDeployVerticle(ApiGatewayVerticle.class.getName()))
                 .subscribe(id -&amp;gt; logger.debug("GatewayVerticle deployed successfully"));
     }

     @Override
     public void start(Future&amp;lt;Void&amp;gt; startFuture) throws Exception {
-        logger.debug("Starting GatewayVerticle");
-        this.discovery = ServiceDiscovery.create(vertx);
+        super.start();
         Router router = Router.router(vertx);
+        this.enableCorsSupport(router);
         ServiceDiscoveryRestEndpoint.create(router.getDelegate(), discovery.getDelegate());
         this.configureRouter(router);
         vertx.createHttpServer()
@@ -52,6 +286,7 @@
         router.route(PREFIX_SERVICE + "*").handler(this::serviceHandler);
         String regexMatcher = "^(?!" + PREFIX_SERVICE + ").*";
         router.routeWithRegex(regexMatcher).handler(this::indexHandler);
+        //router.route("/").handler(this::indexHandler);
     }

     private void indexHandler(RoutingContext context) {
@@ -69,32 +304,8 @@
         if (null == serviceName || serviceName.trim().equalsIgnoreCase("")) {
             this.error(context, 500, "Empty service name");
         } else {
-            HttpEndpoint.rxGetClient(discovery, new JsonObject().put("name", serviceName))
-                    .subscribe(httpClient -&amp;gt; this.dispatchRequest(context, httpClient), error -&amp;gt; this.serviceNotFound(context, serviceName));
-        }
-    }
-
-    private void dispatchRequest(RoutingContext context, HttpClient client) {
-        logger.debug("Dispatch Request, uri:{}", context.request().uri());
-        HttpClientRequest clientRequest = client.request(context.request().method(), context.request().uri());
-        clientRequest.toFlowable()
-                .flatMap(res -&amp;gt; {
-                    context.response().setStatusCode(res.statusCode());
-                    res.headers().getDelegate().forEach(header -&amp;gt; context.response().putHeader(header.getKey(), header.getValue()));
-                    return res.toFlowable();
-                })
-                .doAfterTerminate(() -&amp;gt; ServiceDiscovery.releaseServiceObject(discovery, client))
-                .subscribe(context.response()::end, error -&amp;gt; this.error(context, error));
-        context.request().headers().getDelegate().forEach(header -&amp;gt; clientRequest.putHeader(header.getKey(), header.getValue()));
-        if (null != context.getBody()) {
-            clientRequest.end(context.getBody());
-        } else {
-            clientRequest.end();
-        }
-    }
-
-    private void serviceNotFound(RoutingContext context, String serviceName) {
-        this.error(context, 404, "Service [" + serviceName + "] not found");
+            this.dispatchHttpRequest(context, serviceName, error -&amp;gt; this.error(context, error));
+        }
     }

     private void error(RoutingContext context, Throwable throwable) {
@@ -102,135 +313,11 @@
     }

     private void error(RoutingContext context, int statusCode, String errorMessage) {
-        context.response().setStatusCode(statusCode).putHeader("content-type", "application/json")
-                .end(new JsonObject().put("statusCode", statusCode).put("error", errorMessage).encodePrettily());
+        if (!context.response().ended()) {
+            context.response().setStatusCode(statusCode).putHeader("content-type", "application/json")
+                    .end(new JsonObject().put("statusCode", statusCode).put("error", errorMessage).encodePrettily());
+        }
     }
 }

 ~~~
-
-BaseServiceVerticle
-~~~
-package com.example.discovery;
-
-import io.reactivex.Completable;
-import io.reactivex.Single;
-import io.vertx.core.Handler;
-import io.vertx.core.impl.ConcurrentHashSet;
-import io.vertx.core.json.JsonObject;
-import io.vertx.reactivex.core.AbstractVerticle;
-import io.vertx.reactivex.core.http.HttpServerRequest;
-import io.vertx.reactivex.ext.web.Router;
-import io.vertx.reactivex.servicediscovery.ServiceDiscovery;
-import io.vertx.reactivex.servicediscovery.types.HttpEndpoint;
-import io.vertx.servicediscovery.Record;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Set;
-
-public abstract class BaseServiceVerticle extends AbstractVerticle {
-    private static final Logger logger = LoggerFactory.getLogger(BaseServiceVerticle.class);
-
-    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 ServiceDiscovery discovery;
-    private Set&amp;lt;Record&amp;gt; publishedRecords = new ConcurrentHashSet&amp;lt;&amp;gt;();
-
-    @Override
-    public void start() throws Exception {
-        logger.debug("Starting {} verticle", this.config().getString(KEY_SERVICE_NAME));
-        logger.debug("Config:{}", this.config().encodePrettily());
-        this.discovery = ServiceDiscovery.create(vertx);
-    }
-
-    @Override
-    public void stop() throws Exception {
-        logger.debug("Stopping {} verticle", this.config().getString(KEY_SERVICE_NAME));
-        if (null != discovery) {
-            List&amp;lt;Completable&amp;gt; completables = new ArrayList&amp;lt;&amp;gt;();
-            publishedRecords.forEach(record -&amp;gt; completables.add(discovery.rxUnpublish(record.getRegistration())));
-            Completable.merge(completables)
-                    .subscribe(() -&amp;gt; {
-                        logger.debug("All services have been un-published");
-                        discovery.close();
-                    });
-        }
-    }
-
-    protected Handler&amp;lt;HttpServerRequest&amp;gt; getHttpRequestHandler() {
-        Router router = Router.router(vertx);
-        router.route().handler(routingContext -&amp;gt; {
-            logger.debug("Received a http request");
-            routingContext.response()
-                    .putHeader("content-type", "text/json")
-                    .end(new JsonObject().put("message", "Welcome to " + this.config().getString(KEY_SERVICE_NAME) + " service").encodePrettily());
-        });
-        return router::accept;
-    }
-
-    protected final Single&amp;lt;Record&amp;gt; publishHttpServer() {
-        String serviceName = this.config().getString(KEY_SERVICE_NAME);
-        String host = this.config().getString(KEY_HOST, "localhost");
-        Integer port = this.config().getInteger(KEY_PORT, 8080);
-        String root = this.config().getString(KEY_ROOT, "/");
-        return vertx.createHttpServer()
-                .requestHandler(this.getHttpRequestHandler())
-                .rxListen(port)
-                .flatMap(httpServer -&amp;gt; {
-                    logger.debug("{} http server started on port {}", serviceName, port);
-                    return this.publishRecord(HttpEndpoint.createRecord(serviceName, host, port, root));
-                });
-    }
-
-    protected final Single&amp;lt;Record&amp;gt; publishRecord(Record record) {
-        return discovery.rxPublish(record)
-                .flatMap(r -&amp;gt; {
-                    logger.debug("Service {} has been published", record.getName());
-                    this.publishedRecords.add(r);
-                    return Single.just(r);
-                });
-    }
-}
-
-~~~
-
-ProductVerticle
-~~~
-package com.example.discovery;
-
-import io.vertx.core.DeploymentOptions;
-import io.vertx.core.Future;
-import io.vertx.core.VertxOptions;
-import io.vertx.core.json.JsonObject;
-import io.vertx.reactivex.core.Vertx;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class ProductVerticle extends BaseServiceVerticle {
-    private static final Logger logger = LoggerFactory.getLogger(ProductVerticle.class);
-
-    public static void main(String[] args) throws InterruptedException {
-        JsonObject config = new JsonObject()
-                .put(KEY_SERVICE_NAME, "product")
-                .put(KEY_PORT, 8081)
-                .put(KEY_ROOT, "/service/product");
-        Vertx.rxClusteredVertx(new VertxOptions().setClustered(true))
-                .flatMap(vertx -&amp;gt; vertx.rxDeployVerticle(ProductVerticle.class.getName(), new DeploymentOptions().setConfig(config)))
-                .subscribe(id -&amp;gt; logger.debug("ProductVerticle deployed successfully"));
-    }
-
-    @Override
-    public void start(Future&amp;lt;Void&amp;gt; startFuture) throws Exception {
-        super.start();
-        this.publishHttpServer()
-                .subscribe(record -&amp;gt; startFuture.complete(), startFuture::fail);
-    }
-}
-
-~~~
&lt;/pre&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Gary Cheng</dc:creator><pubDate>Fri, 13 Apr 2018 19:53:56 -0000</pubDate><guid>https://sourceforge.nete0f8a713927fcc960578e32bfbf20c39809d41a0</guid></item><item><title>ServiceDiscovery modified by Gary Cheng</title><link>https://sourceforge.net/p/garyproject00/wiki/ServiceDiscovery/</link><description>&lt;div class="markdown_content"&gt;&lt;pre&gt;--- v2
+++ v3
@@ -1,4 +1,5 @@
 GatewayVerticle
+
 ~~~
 package com.example.discovery;

@@ -43,13 +44,14 @@
                 .subscribe(s -&amp;gt; {
                     logger.debug("Gateway HTTP server started on port 8080");
                     startFuture.complete();
-                }, error -&amp;gt; startFuture.fail(error));
+                }, startFuture::fail);
     }

     private void configureRouter(Router router) {
         router.route().handler(BodyHandler.create());
         router.route(PREFIX_SERVICE + "*").handler(this::serviceHandler);
-        router.route("/").handler(this::indexHandler);
+        String regexMatcher = "^(?!" + PREFIX_SERVICE + ").*";
+        router.routeWithRegex(regexMatcher).handler(this::indexHandler);
     }

     private void indexHandler(RoutingContext context) {
@@ -104,104 +106,131 @@
                 .end(new JsonObject().put("statusCode", statusCode).put("error", errorMessage).encodePrettily());
     }
 }
-~~~
-ProductVerticle
-~~~
-package com.example.discovery.product;
-
-import io.vertx.core.DeploymentOptions;
-import io.vertx.core.Future;
-import io.vertx.core.VertxOptions;
+
+~~~
+
+BaseServiceVerticle
+~~~
+package com.example.discovery;
+
+import io.reactivex.Completable;
+import io.reactivex.Single;
+import io.vertx.core.Handler;
+import io.vertx.core.impl.ConcurrentHashSet;
+import io.vertx.core.json.JsonObject;
 import io.vertx.reactivex.core.AbstractVerticle;
-import io.vertx.reactivex.core.Vertx;
+import io.vertx.reactivex.core.http.HttpServerRequest;
+import io.vertx.reactivex.ext.web.Router;
 import io.vertx.reactivex.servicediscovery.ServiceDiscovery;
 import io.vertx.reactivex.servicediscovery.types.HttpEndpoint;
 import io.vertx.servicediscovery.Record;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;

-import static com.example.discovery.product.ProductHttpVerticle.PORT;
-
-public class ProductVerticle extends AbstractVerticle {
-    private static final Logger logger = LoggerFactory.getLogger(ProductVerticle.class);
-
-    private static final String SERVICE_NAME = "product";
-
-    private ServiceDiscovery discovery;
-    private Record record;
-
-    public static void main(String[] args) throws InterruptedException {
-        Vertx.rxClusteredVertx(new VertxOptions().setClustered(true))
-                .flatMap(vertx -&amp;gt; vertx.rxDeployVerticle(ProductVerticle.class.getName()))
-                .subscribe(id -&amp;gt; logger.debug("ProductVerticle deployed successfully"));
-    }
-
-    @Override
-    public void start(Future&amp;lt;Void&amp;gt; startFuture) throws Exception {
-        logger.debug("Starting ProductVerticle");
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+public abstract class BaseServiceVerticle extends AbstractVerticle {
+    private static final Logger logger = LoggerFactory.getLogger(BaseServiceVerticle.class);
+
+    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 ServiceDiscovery discovery;
+    private Set&amp;lt;Record&amp;gt; publishedRecords = new ConcurrentHashSet&amp;lt;&amp;gt;();
+
+    @Override
+    public void start() throws Exception {
+        logger.debug("Starting {} verticle", this.config().getString(KEY_SERVICE_NAME));
+        logger.debug("Config:{}", this.config().encodePrettily());
         this.discovery = ServiceDiscovery.create(vertx);
-        DeploymentOptions options = new DeploymentOptions().setConfig(config());
-        vertx.rxDeployVerticle(ProductHttpVerticle.class.getName(), options)
-                .flatMap(id -&amp;gt; discovery.rxPublish(HttpEndpoint.createRecord(SERVICE_NAME, "localhost", PORT, "/service/product")))
-                .subscribe(record -&amp;gt; {
-                    this.record = record;
-                    logger.debug("{} service has been published", SERVICE_NAME);
-                    startFuture.complete();
-                }, startFuture::fail);
-    }
-
-    @Override
-    public void stop(Future&amp;lt;Void&amp;gt; stopFuture) throws Exception {
-        if (null != discovery &amp;amp;&amp;amp; null != record) {
-            discovery.rxUnpublish(this.record.getRegistration())
+    }
+
+    @Override
+    public void stop() throws Exception {
+        logger.debug("Stopping {} verticle", this.config().getString(KEY_SERVICE_NAME));
+        if (null != discovery) {
+            List&amp;lt;Completable&amp;gt; completables = new ArrayList&amp;lt;&amp;gt;();
+            publishedRecords.forEach(record -&amp;gt; completables.add(discovery.rxUnpublish(record.getRegistration())));
+            Completable.merge(completables)
                     .subscribe(() -&amp;gt; {
-                        logger.debug("Service {} has been un-published", SERVICE_NAME);
-                        stopFuture.complete();
+                        logger.debug("All services have been un-published");
+                        discovery.close();
                     });
-        } else {
-            stopFuture.complete();
         }
     }
+
+    protected Handler&amp;lt;HttpServerRequest&amp;gt; getHttpRequestHandler() {
+        Router router = Router.router(vertx);
+        router.route().handler(routingContext -&amp;gt; {
+            logger.debug("Received a http request");
+            routingContext.response()
+                    .putHeader("content-type", "text/json")
+                    .end(new JsonObject().put("message", "Welcome to " + this.config().getString(KEY_SERVICE_NAME) + " service").encodePrettily());
+        });
+        return router::accept;
+    }
+
+    protected final Single&amp;lt;Record&amp;gt; publishHttpServer() {
+        String serviceName = this.config().getString(KEY_SERVICE_NAME);
+        String host = this.config().getString(KEY_HOST, "localhost");
+        Integer port = this.config().getInteger(KEY_PORT, 8080);
+        String root = this.config().getString(KEY_ROOT, "/");
+        return vertx.createHttpServer()
+                .requestHandler(this.getHttpRequestHandler())
+                .rxListen(port)
+                .flatMap(httpServer -&amp;gt; {
+                    logger.debug("{} http server started on port {}", serviceName, port);
+                    return this.publishRecord(HttpEndpoint.createRecord(serviceName, host, port, root));
+                });
+    }
+
+    protected final Single&amp;lt;Record&amp;gt; publishRecord(Record record) {
+        return discovery.rxPublish(record)
+                .flatMap(r -&amp;gt; {
+                    logger.debug("Service {} has been published", record.getName());
+                    this.publishedRecords.add(r);
+                    return Single.just(r);
+                });
+    }
 }

 ~~~

-ProductHttpVerticle
-~~~
-package com.example.discovery.product;
-
+ProductVerticle
+~~~
+package com.example.discovery;
+
+import io.vertx.core.DeploymentOptions;
 import io.vertx.core.Future;
+import io.vertx.core.VertxOptions;
 import io.vertx.core.json.JsonObject;
-import io.vertx.reactivex.core.AbstractVerticle;
-import io.vertx.reactivex.ext.web.Router;
-import io.vertx.reactivex.ext.web.RoutingContext;
+import io.vertx.reactivex.core.Vertx;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;

-public class ProductHttpVerticle extends AbstractVerticle {
-
-    public static final int PORT = 8081;
-    private static final Logger logger = LoggerFactory.getLogger(ProductHttpVerticle.class);
+public class ProductVerticle extends BaseServiceVerticle {
+    private static final Logger logger = LoggerFactory.getLogger(ProductVerticle.class);
+
+    public static void main(String[] args) throws InterruptedException {
+        JsonObject config = new JsonObject()
+                .put(KEY_SERVICE_NAME, "product")
+                .put(KEY_PORT, 8081)
+                .put(KEY_ROOT, "/service/product");
+        Vertx.rxClusteredVertx(new VertxOptions().setClustered(true))
+                .flatMap(vertx -&amp;gt; vertx.rxDeployVerticle(ProductVerticle.class.getName(), new DeploymentOptions().setConfig(config)))
+                .subscribe(id -&amp;gt; logger.debug("ProductVerticle deployed successfully"));
+    }

     @Override
     public void start(Future&amp;lt;Void&amp;gt; startFuture) throws Exception {
-        logger.debug("Starting ProductHttpVerticle");
-        Router router = Router.router(vertx);
-        router.get("/*").handler(this::productServiceHandler);
-        vertx.createHttpServer()
-                .requestHandler(router::accept)
-                .rxListen(PORT)
-                .subscribe(s -&amp;gt; {
-                    logger.debug("Product HTTP server started on port {}", PORT);
-                    startFuture.complete();
-                }, error -&amp;gt; startFuture.fail(error));
-    }
-
-    private void productServiceHandler(RoutingContext context) {
-        logger.debug("Received a product service request");
-        context.response()
-                .putHeader("content-type", "application/json")
-                .end(new JsonObject().put("message", "Welcome to product service").encodePrettily());
+        super.start();
+        this.publishHttpServer()
+                .subscribe(record -&amp;gt; startFuture.complete(), startFuture::fail);
     }
 }
-~~~
+
+~~~
&lt;/pre&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Gary Cheng</dc:creator><pubDate>Thu, 05 Apr 2018 18:56:10 -0000</pubDate><guid>https://sourceforge.netac3c1a99772cb0288c9ad631a8cab1f783774432</guid></item><item><title>ServiceDiscovery modified by Gary Cheng</title><link>https://sourceforge.net/p/garyproject00/wiki/ServiceDiscovery/</link><description>&lt;div class="markdown_content"&gt;&lt;pre&gt;--- v1
+++ v2
@@ -1,3 +1,4 @@
+GatewayVerticle
 ~~~
 package com.example.discovery;

@@ -6,18 +7,21 @@
 import io.vertx.core.json.JsonObject;
 import io.vertx.reactivex.core.AbstractVerticle;
 import io.vertx.reactivex.core.Vertx;
+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.BodyHandler;
 import io.vertx.reactivex.servicediscovery.ServiceDiscovery;
-
+import io.vertx.reactivex.servicediscovery.types.HttpEndpoint;
 import io.vertx.servicediscovery.rest.ServiceDiscoveryRestEndpoint;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;

 public class GatewayVerticle extends AbstractVerticle {
     private static final Logger logger = LoggerFactory.getLogger(GatewayVerticle.class);
-
+    private static final int PORT = 8080;
+    private static final String PREFIX_SERVICE = "/service/";
     private ServiceDiscovery discovery;

     public static void main(String[] args) throws InterruptedException {
@@ -29,29 +33,175 @@
     @Override
     public void start(Future&amp;lt;Void&amp;gt; startFuture) throws Exception {
         logger.debug("Starting GatewayVerticle");
-        discovery = ServiceDiscovery.create(vertx);
+        this.discovery = ServiceDiscovery.create(vertx);
         Router router = Router.router(vertx);
         ServiceDiscoveryRestEndpoint.create(router.getDelegate(), discovery.getDelegate());
-        this.configRouter(router);
-        router.get("/").handler(this::indexHandler);
-
-        vertx.createHttpServer().requestHandler(router::accept).rxListen(8080)
+        this.configureRouter(router);
+        vertx.createHttpServer()
+                .requestHandler(router::accept)
+                .rxListen(PORT)
                 .subscribe(s -&amp;gt; {
                     logger.debug("Gateway HTTP server started on port 8080");
                     startFuture.complete();
                 }, error -&amp;gt; startFuture.fail(error));
     }

-    private void configRouter(Router router) {
+    private void configureRouter(Router router) {
         router.route().handler(BodyHandler.create());
-        router.get("/*").handler(this::indexHandler);
+        router.route(PREFIX_SERVICE + "*").handler(this::serviceHandler);
+        router.route("/").handler(this::indexHandler);
     }

     private void indexHandler(RoutingContext context) {
+        logger.debug("Received http request");
         context.response()
                 .putHeader("content-type", "application/json")
-                .end(new JsonObject().put("message", "Hello from gateway").encodePrettily());
+                .end(new JsonObject().put("message", "Welcome to gateway").encodePrettily());
+    }
+
+    private void serviceHandler(RoutingContext context) {
+        String path = context.request().uri();
+        logger.debug("path:{}", path);
+        String serviceName = path.substring(PREFIX_SERVICE.length()).split("/")[0];
+        logger.debug("Service Name:{}", serviceName);
+        if (null == serviceName || serviceName.trim().equalsIgnoreCase("")) {
+            this.error(context, 500, "Empty service name");
+        } else {
+            HttpEndpoint.rxGetClient(discovery, new JsonObject().put("name", serviceName))
+                    .subscribe(httpClient -&amp;gt; this.dispatchRequest(context, httpClient), error -&amp;gt; this.serviceNotFound(context, serviceName));
+        }
+    }
+
+    private void dispatchRequest(RoutingContext context, HttpClient client) {
+        logger.debug("Dispatch Request, uri:{}", context.request().uri());
+        HttpClientRequest clientRequest = client.request(context.request().method(), context.request().uri());
+        clientRequest.toFlowable()
+                .flatMap(res -&amp;gt; {
+                    context.response().setStatusCode(res.statusCode());
+                    res.headers().getDelegate().forEach(header -&amp;gt; context.response().putHeader(header.getKey(), header.getValue()));
+                    return res.toFlowable();
+                })
+                .doAfterTerminate(() -&amp;gt; ServiceDiscovery.releaseServiceObject(discovery, client))
+                .subscribe(context.response()::end, error -&amp;gt; this.error(context, error));
+        context.request().headers().getDelegate().forEach(header -&amp;gt; clientRequest.putHeader(header.getKey(), header.getValue()));
+        if (null != context.getBody()) {
+            clientRequest.end(context.getBody());
+        } else {
+            clientRequest.end();
+        }
+    }
+
+    private void serviceNotFound(RoutingContext context, String serviceName) {
+        this.error(context, 404, "Service [" + serviceName + "] not found");
+    }
+
+    private void error(RoutingContext context, Throwable throwable) {
+        this.error(context, 500, throwable.getMessage());
+    }
+
+    private void error(RoutingContext context, int statusCode, String errorMessage) {
+        context.response().setStatusCode(statusCode).putHeader("content-type", "application/json")
+                .end(new JsonObject().put("statusCode", statusCode).put("error", errorMessage).encodePrettily());
     }
 }
-
-~~~
+~~~
+ProductVerticle
+~~~
+package com.example.discovery.product;
+
+import io.vertx.core.DeploymentOptions;
+import io.vertx.core.Future;
+import io.vertx.core.VertxOptions;
+import io.vertx.reactivex.core.AbstractVerticle;
+import io.vertx.reactivex.core.Vertx;
+import io.vertx.reactivex.servicediscovery.ServiceDiscovery;
+import io.vertx.reactivex.servicediscovery.types.HttpEndpoint;
+import io.vertx.servicediscovery.Record;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static com.example.discovery.product.ProductHttpVerticle.PORT;
+
+public class ProductVerticle extends AbstractVerticle {
+    private static final Logger logger = LoggerFactory.getLogger(ProductVerticle.class);
+
+    private static final String SERVICE_NAME = "product";
+
+    private ServiceDiscovery discovery;
+    private Record record;
+
+    public static void main(String[] args) throws InterruptedException {
+        Vertx.rxClusteredVertx(new VertxOptions().setClustered(true))
+                .flatMap(vertx -&amp;gt; vertx.rxDeployVerticle(ProductVerticle.class.getName()))
+                .subscribe(id -&amp;gt; logger.debug("ProductVerticle deployed successfully"));
+    }
+
+    @Override
+    public void start(Future&amp;lt;Void&amp;gt; startFuture) throws Exception {
+        logger.debug("Starting ProductVerticle");
+        this.discovery = ServiceDiscovery.create(vertx);
+        DeploymentOptions options = new DeploymentOptions().setConfig(config());
+        vertx.rxDeployVerticle(ProductHttpVerticle.class.getName(), options)
+                .flatMap(id -&amp;gt; discovery.rxPublish(HttpEndpoint.createRecord(SERVICE_NAME, "localhost", PORT, "/service/product")))
+                .subscribe(record -&amp;gt; {
+                    this.record = record;
+                    logger.debug("{} service has been published", SERVICE_NAME);
+                    startFuture.complete();
+                }, startFuture::fail);
+    }
+
+    @Override
+    public void stop(Future&amp;lt;Void&amp;gt; stopFuture) throws Exception {
+        if (null != discovery &amp;amp;&amp;amp; null != record) {
+            discovery.rxUnpublish(this.record.getRegistration())
+                    .subscribe(() -&amp;gt; {
+                        logger.debug("Service {} has been un-published", SERVICE_NAME);
+                        stopFuture.complete();
+                    });
+        } else {
+            stopFuture.complete();
+        }
+    }
+}
+
+~~~
+
+ProductHttpVerticle
+~~~
+package com.example.discovery.product;
+
+import io.vertx.core.Future;
+import io.vertx.core.json.JsonObject;
+import io.vertx.reactivex.core.AbstractVerticle;
+import io.vertx.reactivex.ext.web.Router;
+import io.vertx.reactivex.ext.web.RoutingContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ProductHttpVerticle extends AbstractVerticle {
+
+    public static final int PORT = 8081;
+    private static final Logger logger = LoggerFactory.getLogger(ProductHttpVerticle.class);
+
+    @Override
+    public void start(Future&amp;lt;Void&amp;gt; startFuture) throws Exception {
+        logger.debug("Starting ProductHttpVerticle");
+        Router router = Router.router(vertx);
+        router.get("/*").handler(this::productServiceHandler);
+        vertx.createHttpServer()
+                .requestHandler(router::accept)
+                .rxListen(PORT)
+                .subscribe(s -&amp;gt; {
+                    logger.debug("Product HTTP server started on port {}", PORT);
+                    startFuture.complete();
+                }, error -&amp;gt; startFuture.fail(error));
+    }
+
+    private void productServiceHandler(RoutingContext context) {
+        logger.debug("Received a product service request");
+        context.response()
+                .putHeader("content-type", "application/json")
+                .end(new JsonObject().put("message", "Welcome to product service").encodePrettily());
+    }
+}
+~~~
&lt;/pre&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Gary Cheng</dc:creator><pubDate>Wed, 04 Apr 2018 19:58:03 -0000</pubDate><guid>https://sourceforge.net743bd95786e4fecf1b9b3b6672407a6a707703fd</guid></item><item><title>ServiceDiscovery modified by Gary Cheng</title><link>https://sourceforge.net/p/garyproject00/wiki/ServiceDiscovery/</link><description>&lt;div class="markdown_content"&gt;&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;package&lt;/span&gt; &lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;example&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;discovery&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.vertx.core.Future&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.vertx.core.VertxOptions&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.vertx.core.json.JsonObject&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.vertx.reactivex.core.AbstractVerticle&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.vertx.reactivex.core.Vertx&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.vertx.reactivex.ext.web.Router&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.vertx.reactivex.ext.web.RoutingContext&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.vertx.reactivex.ext.web.handler.BodyHandler&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.vertx.reactivex.servicediscovery.ServiceDiscovery&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.vertx.servicediscovery.rest.ServiceDiscoveryRestEndpoint&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.slf4j.Logger&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.slf4j.LoggerFactory&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GatewayVerticle&lt;/span&gt; &lt;span class="n"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;AbstractVerticle&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;private&lt;/span&gt; &lt;span class="n"&gt;static&lt;/span&gt; &lt;span class="n"&gt;final&lt;/span&gt; &lt;span class="n"&gt;Logger&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;LoggerFactory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GatewayVerticle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;private&lt;/span&gt; &lt;span class="n"&gt;ServiceDiscovery&lt;/span&gt; &lt;span class="n"&gt;discovery&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;public&lt;/span&gt; &lt;span class="n"&gt;static&lt;/span&gt; &lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;throws&lt;/span&gt; &lt;span class="n"&gt;InterruptedException&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Vertx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rxClusteredVertx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="n"&gt;VertxOptions&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setClustered&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;true&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flatMap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vertx&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;vertx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rxDeployVerticle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GatewayVerticle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getName&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"GatewayVerticle deployed successfully"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="n"&gt;public&lt;/span&gt; &lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;startFuture&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;throws&lt;/span&gt; &lt;span class="ne"&gt;Exception&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Starting GatewayVerticle"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;discovery&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ServiceDiscovery&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vertx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;Router&lt;/span&gt; &lt;span class="n"&gt;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Router&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;router&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vertx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;ServiceDiscoveryRestEndpoint&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;router&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getDelegate&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;discovery&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getDelegate&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;configRouter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;router&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;router&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;indexHandler&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;vertx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;createHttpServer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;requestHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;router&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;accept&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rxListen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Gateway HTTP server started on port 8080"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                    &lt;span class="n"&gt;startFuture&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;startFuture&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;private&lt;/span&gt; &lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="n"&gt;configRouter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Router&lt;/span&gt; &lt;span class="n"&gt;router&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;router&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;route&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BodyHandler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;router&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"/*"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;indexHandler&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;private&lt;/span&gt; &lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="n"&gt;indexHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RoutingContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;putHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"content-type"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="n"&gt;JsonObject&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"Hello from gateway"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encodePrettily&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Gary Cheng</dc:creator><pubDate>Tue, 03 Apr 2018 20:15:40 -0000</pubDate><guid>https://sourceforge.net2e3748c07e30bf17a071abaff2fdae0a80d24eb2</guid></item></channel></rss>