org.vas.test.rest.RestImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.vas.test.rest.RestImpl.java

Source

/**
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Vincent Vergnolle
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package org.vas.test.rest;

import io.undertow.util.Headers;

import java.text.MessageFormat;
import java.util.Base64;
import java.util.Collections;
import java.util.Map;
import java.util.stream.Collectors;

import org.apache.http.HttpHeaders;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.StatusLine;
import org.apache.http.client.fluent.Request;
import org.apache.http.entity.ContentType;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.vas.commons.bean.MsgBean;
import org.vas.commons.utils.GsonUtils;

import com.google.common.collect.Maps;
import com.google.gson.JsonSyntaxException;

public class RestImpl implements Rest {

    private static final int TIMEOUT = 4000;
    private static final String USER_AGENT = "Vas-Rest-Agent";

    protected final Logger logger = LoggerFactory.getLogger(getClass());
    protected final Map<String, String> defaultHeaders;

    public RestImpl() {
        this(Maps.newHashMap());
    }

    public RestImpl(Map<String, String> defaultHeaders) {
        super();
        if (defaultHeaders == null) {
            this.defaultHeaders = Maps.newHashMap();
        } else {
            this.defaultHeaders = defaultHeaders;
        }

        if (!this.defaultHeaders.containsKey(HttpHeaders.ALLOW)) {
            this.defaultHeaders.put(HttpHeaders.ALLOW, ContentType.APPLICATION_JSON.getMimeType());
        }
    }

    @Override
    public Rest withBasic(String username, String password) {
        Map<String, String> map = Maps.newHashMap();
        map.put(Headers.AUTHORIZATION_STRING, digestCredentials(username, password));
        map.putAll(defaultHeaders);

        return createRestBasicInstance(map);
    }

    private String digestCredentials(String username, String password) {
        String credential = username + ":" + password;
        String digest = Base64.getEncoder().encodeToString(credential.getBytes());
        return "Basic " + digest;
    }

    @Override
    public <T> Response<T> get(String uri, Class<T> klass, Object... args) {
        uri = formattedUri(uri, args);

        try {
            org.apache.http.client.fluent.Response response = httpGet(uri).execute();
            return extractResponse(klass, response);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public <T> Response<T> post(String uri, Class<T> klass, Object... args) {
        return post(uri, Collections.emptyMap(), klass, args);
    }

    @Override
    public <T> Response<T> post(String uri, Map<String, String> datas, Class<T> klass, Object... args) {
        uri = formattedUri(uri, args);

        Request request = httpPost(uri);
        request.bodyForm(nameValuePairOf(datas));

        try {
            org.apache.http.client.fluent.Response response = request.execute();
            return extractResponse(klass, response);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public <T> Response<T> put(String uri, Class<T> klass, Object... args) {
        return put(uri, Collections.emptyMap(), klass, args);
    }

    @Override
    public <T> Response<T> put(String uri, Map<String, String> datas, Class<T> klass, Object... args) {
        uri = formattedUri(uri, args);

        Request request = httpPut(uri);
        request.bodyForm(nameValuePairOf(datas));

        try {
            org.apache.http.client.fluent.Response response = request.execute();
            return extractResponse(klass, response);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public <T> Response<T> delete(String uri, Class<T> klass, Object... args) {
        uri = formattedUri(uri, args);

        Request request = httpDelete(uri);
        try {
            org.apache.http.client.fluent.Response response = request.execute();
            return extractResponse(klass, response);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    protected Iterable<? extends NameValuePair> nameValuePairOf(Map<String, String> datas) {
        return datas.entrySet().stream().map(entry -> new BasicNameValuePair(entry.getKey(), entry.getValue()))
                .collect(Collectors.toList());
    }

    protected <T> T lookupBody(Class<T> klass, byte[] content) throws Exception {
        if (klass == String.class) {
            return content == null ? klass.cast("") : klass.cast(new String(content));
        } else if (klass == byte[].class) {
            return klass.cast(content);
        } else if (klass == Void.class) {
            return null;
        } else {
            try {
                return GsonUtils.GSON.fromJson(new String(content), klass);
            } catch (JsonSyntaxException e) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Fail to parse json", e);
                }
                return null;
            }
        }
    }

    protected Request httpGet(String uri) {
        Request request = Request.Get(uri);
        configureRequest(request);

        return request;
    }

    protected Request httpPost(String uri) {
        Request request = Request.Post(uri);
        configureRequest(request);

        return request;
    }

    protected Request httpPut(String uri) {
        Request request = Request.Put(uri);
        configureRequest(request);

        return request;
    }

    protected Request httpDelete(String uri) {
        Request request = Request.Delete(uri);
        configureRequest(request);

        return request;
    }

    protected void configureRequest(Request request) {
        request.connectTimeout(TIMEOUT).socketTimeout(TIMEOUT).userAgent(USER_AGENT);

        defaultHeaders.forEach((header, value) -> request.addHeader(header, value));
    }

    protected <T> Response<T> extractResponse(Class<T> klass, org.apache.http.client.fluent.Response response)
            throws Exception {
        HttpResponse httpResponse = response.returnResponse();

        byte[] content = null;
        try {
            content = EntityUtils.toByteArray(httpResponse.getEntity());
        } catch (IllegalArgumentException e) {
            if (logger.isDebugEnabled()) {
                logger.debug("Error when reading entity", e);
            }
        }

        StatusLine statusLine = httpResponse.getStatusLine();
        int status = statusLine.getStatusCode();

        /*
         * Short circuit the content extraction if the 401 status has been returned
         * - by default the response is in HTML for this status so the json parsing
         * will fail.
         */
        if (status == 401) {
            return Response.of(status, null, content);
        } else if (status == 204) {
            return Response.of(status, null, content);
        }

        T body = lookupBody(klass, content);
        if (body == null) {
            try {
                MsgBean msg = GsonUtils.GSON.fromJson(new String(content), MsgBean.class);
                return Response.of(status, body, content, msg);
            } catch (JsonSyntaxException e) {
                logger.warn("Fail to fallback on a MsgBean body", e);
            }
        }

        return Response.of(statusLine.getStatusCode(), body, content);
    }

    protected String formattedUri(String uri, Object... args) {
        if (args != null && args.length > 0) {
            uri = MessageFormat.format(uri, args);
        }

        return uri;
    }

    protected RestImpl createRestBasicInstance(Map<String, String> map) {
        return new RestImpl(map);
    }
}