com.redhat.developers.msa.aloha.AlohaVerticle.java Source code

Java tutorial

Introduction

Here is the source code for com.redhat.developers.msa.aloha.AlohaVerticle.java

Source

/**
 * JBoss, Home of Professional Open Source
 * Copyright 2016, Red Hat, Inc. and/or its affiliates, and individual
 * contributors by the @authors tag. See the copyright.txt in the
 * distribution for a full listing of individual contributors.
 * <p/>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.redhat.developers.msa.aloha;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;

import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;

import com.github.kennedyoliveira.hystrix.contrib.vertx.metricsstream.EventMetricsStreamHandler;
import com.github.kristofa.brave.Brave;
import com.github.kristofa.brave.Brave.Builder;
import com.github.kristofa.brave.EmptySpanCollectorMetricsHandler;
import com.github.kristofa.brave.ServerRequestInterceptor;
import com.github.kristofa.brave.ServerSpan;
import com.github.kristofa.brave.http.DefaultSpanNameProvider;
import com.github.kristofa.brave.http.HttpServerRequestAdapter;
import com.github.kristofa.brave.http.HttpServerResponseAdapter;
import com.github.kristofa.brave.http.HttpSpanCollector;
import com.github.kristofa.brave.httpclient.BraveHttpRequestInterceptor;
import com.github.kristofa.brave.httpclient.BraveHttpResponseInterceptor;

import feign.Logger;
import feign.Logger.Level;
import feign.httpclient.ApacheHttpClient;
import feign.hystrix.HystrixFeign;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.Handler;
import io.vertx.core.http.HttpMethod;
import io.vertx.core.json.Json;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.auth.User;
import io.vertx.ext.auth.jwt.JWTAuth;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.handler.BodyHandler;
import io.vertx.ext.web.handler.CorsHandler;
import io.vertx.ext.web.handler.JWTAuthHandler;
import io.vertx.ext.web.handler.StaticHandler;

public class AlohaVerticle extends AbstractVerticle {

    private static Brave BRAVE = null;

    public AlohaVerticle() {
        String zipkingServer = System.getenv("ZIPKIN_SERVER_URL");
        Builder builder = new Brave.Builder("aloha");
        if (null == zipkingServer) {
            // Default configuration
            BRAVE = builder.build();
            System.out.println("No ZIPKIN_SERVER_URL defined. Printing zipkin traces to console.");
        } else {
            // Brave configured for a Server
            BRAVE = builder.spanCollector(HttpSpanCollector.create(System.getenv("ZIPKIN_SERVER_URL"),
                    new EmptySpanCollectorMetricsHandler())).build();
        }
    }

    @Override
    public void start() throws Exception {
        Router router = Router.router(vertx);
        router.route().handler(ctx -> {
            // note: this is *not* an example of how to properly integrate vert.x with zipkin
            // for a more appropriate way to do that, check the vert.x documentation
            ServerRequestInterceptor serverRequestInterceptor = BRAVE.serverRequestInterceptor();
            serverRequestInterceptor.handle(new HttpServerRequestAdapter(new VertxHttpServerRequest(ctx.request()),
                    new DefaultSpanNameProvider()));
            ctx.data().put("zipkin.span", BRAVE.serverSpanThreadBinder().getCurrentServerSpan());
            ctx.next();
            ctx.addBodyEndHandler(v -> BRAVE.serverResponseInterceptor()
                    .handle(new HttpServerResponseAdapter(() -> ctx.response().getStatusCode())));
        });
        router.route().handler(BodyHandler.create());
        router.route()
                .handler(CorsHandler.create("*").allowedMethods(new HashSet<>(Arrays.asList(HttpMethod.values())))
                        .allowedHeader("Origin, X-Requested-With, Content-Type, Accept, Authorization"));

        // Aloha EndPoint
        router.get("/api/aloha").handler(ctx -> ctx.response().end(aloha()));

        String keycloackServer = System.getenv("KEYCLOAK_AUTH_SERVER_URL");

        if (keycloackServer != null) {
            // Create a JWT Auth Provider
            JWTAuth jwt = JWTAuth.create(vertx, new JsonObject().put("public-key",
                    "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArfmb1i36YGxYxusjzpNxmw9a/+M40naa5RxtK826nitmWESF9XiXm6bHLWmRQyhAZluFK4RZDLhQJFZTLpC/w8HdSDETYGqnrP04jL3/pV0Mw1ReKSpzi3tIde+04xGuiQM6nuR84iRraLxtoNyIiqFmHy5pmI9hQhctfZNOVvggntnhXdt/VKuguBXqitFwGbfEgrJTeRvnTkK+rR5MsRDHA3iu2ZYaM4YNAoDbqGyoI4Jdv5Kl1LsP3qESYNeagRz6pIfDZWOoJ58p/TldVt2h70S1bzappbgs8ZbmJXg+pHWcKvNutp5y8nYw30qzU73pX6DW9JS936OB6PiU0QIDAQAB"));
            router.route("/api/aloha-secured").handler(JWTAuthHandler.create(jwt));
        }
        router.get("/api/aloha-secured").handler(ctx -> {
            User user = ctx.user();
            ctx.response()
                    .end("This is a secured resource. You're logged as " + user.principal().getString("name"));
        });

        // Aloha Chained Endpoint
        router.get("/api/aloha-chaining").handler(ctx -> alohaChaining(ctx,
                (list) -> ctx.response().putHeader("Content-Type", "application/json").end(Json.encode(list))));

        // Health Check
        router.get("/api/health").handler(ctx -> ctx.response().end("I'm ok"));

        // Hystrix Stream Endpoint
        router.get(EventMetricsStreamHandler.DEFAULT_HYSTRIX_PREFIX)
                .handler(EventMetricsStreamHandler.createHandler());

        // Static content
        router.route("/*").handler(StaticHandler.create());

        vertx.createHttpServer().requestHandler(router::accept).listen(8080);
        System.out.println("Service running at 0.0.0.0:8080");
    }

    private String aloha() {
        String hostname = System.getenv().getOrDefault("HOSTNAME", "unknown");
        return String.format("Aloha mai %s", hostname);
    }

    private void alohaChaining(RoutingContext context, Handler<List<String>> resultHandler) {
        vertx.<String>executeBlocking(
                // Invoke the service in a worker thread, as it's blocking.
                future -> future.complete(getNextService(context).bonjour()), ar -> {
                    // Back to the event loop
                    // result cannot be null, hystrix would have called the fallback.
                    String result = ar.result();
                    List<String> greetings = new ArrayList<>();
                    greetings.add(aloha());
                    greetings.add(result);
                    resultHandler.handle(greetings);
                });
    }

    /**
     * This is were the "magic" happens: it creates a Feign, which is a proxy interface for remote calling a REST endpoint with
     * Hystrix fallback support.
     *
     * @return The feign pointing to the service URL and with Hystrix fallback.
     */
    private BonjourService getNextService(RoutingContext context) {
        final String serviceName = "bonjour";
        // This stores the Original/Parent ServerSpan from ZiPkin.
        final ServerSpan serverSpan = (ServerSpan) context.data().get("zipkin.span");
        final CloseableHttpClient httpclient = HttpClients.custom()
                .addInterceptorFirst(new BraveHttpRequestInterceptor(BRAVE.clientRequestInterceptor(),
                        new DefaultSpanNameProvider()))
                .addInterceptorFirst(new BraveHttpResponseInterceptor(BRAVE.clientResponseInterceptor())).build();
        final String url = String.format("http://%s:8080/", serviceName);
        return HystrixFeign.builder()
                // Use apache HttpClient which contains the ZipKin Interceptors
                .client(new ApacheHttpClient(httpclient))
                // Bind Zipkin Server Span to Feign Thread, but this probably won't work in a real-world scenario
                // as a concurrent request might override the value set to this thread
                .requestInterceptor((t) -> BRAVE.serverSpanThreadBinder().setCurrentSpan(serverSpan))
                .logger(new Logger.ErrorLogger()).logLevel(Level.BASIC)
                .target(BonjourService.class, url, () -> "Bonjour response (fallback)");
    }

}