com.vmware.photon.controller.client.RestClient.java Source code

Java tutorial

Introduction

Here is the source code for com.vmware.photon.controller.client.RestClient.java

Source

/*
 * Copyright 2015 VMware, Inc. All Rights Reserved.
 *
 * 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.vmware.photon.controller.client;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.annotations.VisibleForTesting;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.concurrent.FutureCallback;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.util.EntityUtils;

import java.io.File;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

/**
 * Rest client.
 */
public class RestClient {

    // OAuth2.0 Authorization Request Header: http://tools.ietf.org/html/draft-ietf-oauth-v2-bearer-20#section-2.1
    public static final String AUTHORIZATION_HEADER = HttpHeaders.AUTHORIZATION;

    // OAuth2.0 Bearer Token: http://self-issued.info/docs/draft-ietf-oauth-v2-bearer.html
    public static final String AUTHORIZATION_METHOD = "Bearer ";

    /**
     * Possible http verbs.
     */
    public enum Method {
        GET, PUT, POST, DELETE;
    }

    private final CloseableHttpAsyncClient asyncClient;
    private final String target;
    private String sharedSecret;

    // For testing only
    private HttpClient mockHttpClient;

    /**
     * Initializes RestClient with a mock http async client.
     *
     * @param asyncClient
     */
    public RestClient(String target, CloseableHttpAsyncClient asyncClient) {
        if (null == asyncClient) {
            throw new IllegalArgumentException("Client cannot be null");
        }
        if (null == target) {
            throw new IllegalArgumentException("Target cannot be null");
        }
        this.target = target;
        this.asyncClient = asyncClient;
    }

    public RestClient(String target, CloseableHttpAsyncClient asyncClient, String sharedSecret) {
        if (null == asyncClient) {
            throw new IllegalArgumentException("Client cannot be null");
        }
        if (null == target) {
            throw new IllegalArgumentException("Target cannot be null");
        }
        if (null == sharedSecret) {
            throw new IllegalArgumentException("SharedSecret cannot be null");
        }
        this.target = target;
        this.asyncClient = asyncClient;
        this.sharedSecret = sharedSecret;
    }

    public RestClient(String target, CloseableHttpAsyncClient asyncClient, HttpClient mockHttpClient) {
        this.target = target;
        this.asyncClient = asyncClient;
        this.mockHttpClient = mockHttpClient;
    }

    /**
     * Perform an http request synchronously.
     * @param method
     * @param path
     * @param payload
     * @return
     * @throws IOException
     */
    public HttpResponse perform(final Method method, final String path, final HttpEntity payload)
            throws IOException {
        try {
            return performAsync(method, path, payload, null /* callback */).get();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Perform an http request asynchronously.
     * @param method
     * @param path
     * @param payload
     * @param responseHandler
     * @return
     * @throws IOException
     */
    public Future<HttpResponse> performAsync(final Method method, final String path, final HttpEntity payload,
            final FutureCallback<HttpResponse> responseHandler) throws IOException {
        HttpUriRequest request = createHttpRequest(method, path, payload);
        return asyncClient.execute(request, new BasicHttpContext(), responseHandler);
    }

    private HttpUriRequest createHttpRequest(final Method method, final String path, final HttpEntity payload)
            throws IOException {
        String uri = target + path;
        HttpUriRequest request = null;

        switch (method.name().toLowerCase()) {
        case "get":
            request = new HttpGet(uri);
            break;

        case "put":
            request = new HttpPut(uri);
            ((HttpPut) request).setEntity(payload);
            break;

        case "post":
            request = new HttpPost(uri);
            ((HttpPost) request).setEntity(payload);
            break;

        case "delete":
            request = new HttpDelete(uri);
            break;

        default:
            throw new RuntimeException("Unknown method: " + method);
        }

        request = addAuthHeader(request);
        return request;
    }

    @VisibleForTesting
    protected HttpUriRequest addAuthHeader(HttpUriRequest request) {
        if (sharedSecret != null) {
            request.addHeader(AUTHORIZATION_HEADER, AUTHORIZATION_METHOD + sharedSecret);
        }
        return request;
    }

    public void checkResponse(HttpResponse httpResponse, int expected) {
        int statusCode = httpResponse.getStatusLine().getStatusCode();

        if (statusCode != expected) {
            StringBuilder msg = new StringBuilder();
            msg.append("HTTP request failed with: ");
            msg.append(statusCode);
            if (httpResponse.getEntity() != null) {
                try {
                    msg.append(", ");
                    msg.append(EntityUtils.toString(httpResponse.getEntity()));
                } catch (IOException e) {
                    // ignore exception here and use partial error message.
                }
            }
            throw new RuntimeException(msg.toString());
        }
    }

    public <T> T parseHttpResponse(HttpResponse response, TypeReference<T> classType) throws IOException {
        ObjectMapper objectMapper = new ObjectMapper();
        return objectMapper.readValue(response.getEntity().getContent(), classType);
    }

    public HttpResponse upload(String path, String inputFileName, Map<String, String> arguments)
            throws IOException {
        HttpClient client = getHttpClient();
        HttpPost httppost = new HttpPost(target + path);
        File file = new File(inputFileName);
        if (sharedSecret != null) {
            httppost.addHeader(AUTHORIZATION_HEADER, AUTHORIZATION_METHOD + sharedSecret);
        }

        MultipartEntity mpEntity = new MultipartEntity();

        FileBody cbFile = new FileBody(file, "application/octect-stream");
        for (Map.Entry<String, String> argument : arguments.entrySet()) {
            StringBody stringBody = new StringBody(argument.getValue());
            mpEntity.addPart(argument.getKey(), stringBody);
        }
        mpEntity.addPart("file", cbFile);
        httppost.setEntity(mpEntity);

        return client.execute(httppost);
    }

    private HttpClient getHttpClient() {
        if (mockHttpClient != null) {
            return mockHttpClient;
        }
        return HttpClients.createDefault();
    }
}