com.redhat.developers.msa.api_gateway.GenericFeignClient.java Source code

Java tutorial

Introduction

Here is the source code for com.redhat.developers.msa.api_gateway.GenericFeignClient.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.api_gateway;

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

import com.github.kristofa.brave.Brave;
import com.github.kristofa.brave.ClientRequestInterceptor;
import com.github.kristofa.brave.ClientResponseInterceptor;
import com.github.kristofa.brave.ServerSpan;
import com.github.kristofa.brave.http.DefaultSpanNameProvider;
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;

/**
 * This class constructs a Feign Client to be invoked
 *
 */
public abstract class GenericFeignClient<T> {

    private String serviceName;

    private Class<T> classType;

    private T fallBack;

    private Brave brave;

    /**
     * We need the following information to instantiate a FeignClient
     * 
     * @param classType Service that will be invoked
     * @param serviceName the name of the service. It will be used in the hostname and in zipking tracing
     * @param fallback the fallback implementation
     * @param brave {@link Brave} instance used to configure {@link ClientRequestInterceptor} and
     *        {@link ClientResponseInterceptor}
     */
    public GenericFeignClient(Class<T> classType, String serviceName, T fallback, Brave brave) {
        this.classType = classType;
        this.serviceName = serviceName;
        this.fallBack = fallback;
        this.brave = brave;
    }

    /**
     * This should be implemented to call each service interface using the original {@link ServerSpan}
     * 
     * @param serverSpan The original {@link ServerSpan} received from ZipKin
     * @return Return for each endpoint
     */
    public abstract String invokeService(ServerSpan serverSpan);

    /**
     * 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.
     * 
     * @param - The original ServerSpan
     * 
     * @return The feign pointing to the service URL and with Hystrix fallback.
     */
    protected T createFeign(ServerSpan serverSpan) {
        final CloseableHttpClient httpclient = HttpClients.custom()
                .addInterceptorFirst(new BraveHttpRequestInterceptor(brave.clientRequestInterceptor(),
                        new DefaultSpanNameProvider()))
                .addInterceptorFirst(new BraveHttpResponseInterceptor(brave.clientResponseInterceptor())).build();
        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
                .requestInterceptor((t) -> brave.serverSpanThreadBinder().setCurrentSpan(serverSpan))
                .logger(new Logger.ErrorLogger()).logLevel(Level.BASIC).target(classType, url, fallBack);
    }

}