com.puppetlabs.geppetto.forge.client.ForgeHttpClient.java Source code

Java tutorial

Introduction

Here is the source code for com.puppetlabs.geppetto.forge.client.ForgeHttpClient.java

Source

/**
 * This code was initially copied from the egit-github project
 * 
 *  http://git.eclipse.org/c/egit/egit-github.git/
 * 
 * and then adjusted for this API. The original contained this copyright:
 *
 *  Copyright (c) 2011 GitHub Inc.
 *  All rights reserved. This program and the accompanying materials
 *  are made available under the terms of the Eclipse Public License v1.0
 *  which accompanies this distribution, and is available at
 *  http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 *   Kevin Sawicki (GitHub Inc.) - initial API and implementation
 *   Thomas Hallgren (Puppet Labs, Inc.) - Stackhammer changes
 */
package com.puppetlabs.geppetto.forge.client;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Type;
import java.net.URI;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.http.HttpEntity;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.StatusLine;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.HttpResponseException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
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.HttpRequestBase;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.InputStreamBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.message.BasicNameValuePair;

import com.google.gson.Gson;
import com.google.inject.Inject;
import com.google.inject.name.Named;
import com.puppetlabs.geppetto.common.annotations.Nullable;
import com.puppetlabs.geppetto.forge.client.Authenticator.AuthResponse;
import com.puppetlabs.geppetto.forge.model.Constants;

/**
 * Class responsible for all request and response processing
 */
public class ForgeHttpClient implements Constants, ForgeClient {
    public static final Charset UTF_8 = Charset.forName("UTF-8");

    static InputStream getStream(HttpEntity entity) throws IOException {
        if (entity == null)
            return null;

        return entity.getContent();
    }

    @Inject
    @Named(Constants.BASE_URL_NAME)
    private String baseURL;

    @Inject
    @Named(Constants.API_V1_URL_NAME)
    private String v1URL;

    @Inject
    @Named(Constants.API_V2_URL_NAME)
    private String v2URL;

    @Inject
    @Named(Constants.API_V3_URL_NAME)
    private String v3URL;

    @Inject
    private Gson gson;

    @Inject
    private HttpClient httpClient;

    @Inject(optional = true)
    @Nullable
    private Authenticator authenticator;

    private String userAgent = USER_AGENT;

    private transient String credentials;

    private transient HttpRequestBase currentRequest;

    public synchronized void abortCurrentRequest() {
        if (currentRequest != null) {
            currentRequest.abort();
            currentRequest = null;
        }
    }

    protected void assignJSONContent(HttpEntityEnclosingRequestBase request, Object params) {
        if (params != null) {
            request.addHeader(HttpHeaders.CONTENT_TYPE, CONTENT_TYPE_JSON + "; charset=" + UTF_8.name()); //$NON-NLS-1$
            byte[] data = toJson(params).getBytes(UTF_8);
            request.setEntity(new ByteArrayEntity(data));
        }
    }

    public void authenticate() throws IOException {
        if (credentials == null && authenticator != null) {
            AuthResponse auth = authenticator.authenticate(httpClient);
            this.credentials = "Bearer " + auth.getToken();
        }
    }

    protected void configureRequest(final HttpRequestBase request) {
        if (credentials != null)
            request.addHeader(HttpHeaders.AUTHORIZATION, credentials);
        else
            request.addHeader(HttpHeaders.USER_AGENT, userAgent);
    }

    private HttpGet createGetRequest(String urlStr, Map<String, String> params) {
        StringBuilder bld = new StringBuilder(urlStr);
        if (params != null && !params.isEmpty()) {
            List<BasicNameValuePair> pairs = new ArrayList<BasicNameValuePair>();
            for (Map.Entry<String, String> param : params.entrySet())
                pairs.add(new BasicNameValuePair(param.getKey(), param.getValue()));
            bld.append('?');
            bld.append(URLEncodedUtils.format(pairs, UTF_8.name()));
        }
        return new HttpGet(URI.create(bld.toString()));
    }

    /**
     * Create full v1 URI from path
     * 
     * @param path
     * @return uri
     */
    protected String createV1Uri(final String path) {
        return v1URL + path;
    }

    /**
     * Create full v2 URI from path
     * 
     * @param path
     * @return uri
     */
    protected String createV2Uri(final String path) {
        return v2URL + path;
    }

    @Override
    public void delete(final String uri) throws IOException {
        HttpDelete request = new HttpDelete(createV2Uri(uri));
        configureRequest(request);
        executeRequest(request, null);
    }

    private void doDownload(String urlStr, Map<String, String> params, final OutputStream output)
            throws IOException {
        HttpGet request = createGetRequest(urlStr, params);
        configureRequest(request);
        httpClient.execute(request, new ResponseHandler<Void>() {
            @Override
            public Void handleResponse(HttpResponse response) throws ClientProtocolException, IOException {
                StatusLine statusLine = response.getStatusLine();
                int code = statusLine.getStatusCode();
                if (code != HttpStatus.SC_OK)
                    throw new HttpResponseException(statusLine.getStatusCode(), statusLine.getReasonPhrase());

                HttpEntity entity = response.getEntity();
                entity.writeTo(output);
                return null;
            }
        });
    }

    private <V> V doGet(String urlStr, Map<String, String> params, Type type) throws IOException {
        HttpGet request = createGetRequest(urlStr, params);
        configureRequest(request);
        return executeRequest(request, type);
    }

    public InputStream download(String urlStr, Map<String, String> params) throws IOException {
        HttpGet request = createGetRequest(v3URL + urlStr, params);
        configureRequest(request);
        HttpResponse response = httpClient.execute(request);
        return response.getEntity().getContent();
    }

    @Override
    public void download(String urlStr, Map<String, String> params, final OutputStream output) throws IOException {
        doDownload(v3URL + urlStr, params, output);
    }

    @Override
    public void downloadV2(String urlStr, Map<String, String> params, final OutputStream output)
            throws IOException {
        doDownload(v2URL + urlStr, params, output);
    }

    private synchronized void endRequest() {
        currentRequest = null;
    }

    protected <V> V executeRequest(final HttpRequestBase request, final Type type) throws IOException {
        startRequest(request);
        try {
            return httpClient.execute(request, new JSonResponseHandler<V>(gson, type));
        } finally {
            endRequest();
        }
    }

    @Override
    public <V> V getBaseRelative(String urlStr, Map<String, String> params, Type type) throws IOException {
        return doGet(baseURL + urlStr, params, type);
    }

    @Override
    public <V> V getV1(String urlStr, Map<String, String> params, Type type) throws IOException {
        return doGet(v1URL + urlStr, params, type);
    }

    @Override
    public <V> V getV2(String urlStr, Map<String, String> params, Type type) throws IOException {
        return doGet(v2URL + urlStr, params, type);
    }

    @Override
    public <V> V get(String urlStr, Map<String, String> params, Type type) throws IOException {
        return doGet(v3URL + urlStr, params, type);
    }

    @Override
    public <V> V patch(final String uri, final Object params, final Class<V> type) throws IOException {
        // HttpPatch is introduced in 4.2. We need to be compatible with 4.1 in order to
        // play nice with other Juno and Kepler features
        HttpPost request = new HttpPost(createV2Uri(uri)) {
            @Override
            public String getMethod() {
                return "PATCH";
            }
        };

        configureRequest(request);
        assignJSONContent(request, params);
        return executeRequest(request, type);
    }

    @Override
    public void post(String uri) throws IOException {
        postJSON(uri, null, null);
    }

    @Override
    public <V> V postJSON(final String uri, final Object params, final Class<V> type) throws IOException {
        HttpPost request = new HttpPost(createV2Uri(uri));
        configureRequest(request);
        assignJSONContent(request, params);
        return executeRequest(request, type);
    }

    @Override
    public <V> V postUpload(String uri, Map<String, String> stringParts, InputStream in, String mimeType,
            String fileName, final long fileSize, Class<V> type) throws IOException {
        HttpPost request = new HttpPost(createV2Uri(uri));
        configureRequest(request);

        MultipartEntity entity = new MultipartEntity();
        for (Map.Entry<String, String> entry : stringParts.entrySet())
            entity.addPart(entry.getKey(), StringBody.create(entry.getValue(), "text/plain", UTF_8));

        entity.addPart("file", new InputStreamBody(in, mimeType, fileName) {
            @Override
            public long getContentLength() {
                return fileSize;
            }
        });
        request.setEntity(entity);
        return executeRequest(request, type);
    }

    @Override
    public void put(String uri) throws IOException {
        put(uri, null, null);
    }

    @Override
    public <V> V put(final String uri, final Object params, final Class<V> type) throws IOException {
        HttpPut request = new HttpPut(createV2Uri(uri));
        configureRequest(request);
        assignJSONContent(request, params);
        return executeRequest(request, type);
    }

    @Override
    public ForgeClient setUserAgent(final String agent) {
        if (agent != null && agent.length() > 0)
            userAgent = agent;
        else
            userAgent = USER_AGENT;
        return this;
    }

    private synchronized void startRequest(HttpRequestBase request) {
        if (currentRequest != null)
            currentRequest.abort();
        currentRequest = request;
    }

    /**
     * Convert object to a JSON string
     * 
     * @param object
     * @return JSON string
     * @throws IOException
     */
    protected String toJson(Object object) {
        return gson.toJson(object);
    }
}