com.wadpam.guja.oauth2.social.NetworkTemplate.java Source code

Java tutorial

Introduction

Here is the source code for com.wadpam.guja.oauth2.social.NetworkTemplate.java

Source

/*
 * INSERT COPYRIGHT HERE
 */

package com.wadpam.guja.oauth2.social;

/*
 * #%L
 * guja-core
 * %%
 * Copyright (C) 2014 Wadpam
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public
 * License along with this program.  If not, see
 * <http://www.gnu.org/licenses/gpl-3.0.html>.
 * #L%
 */

import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.ImmutableMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.*;
import java.util.Map.Entry;

/**
 * @author sosandstrom
 */
public class NetworkTemplate {
    public static final String ACCEPT = "Accept";
    public static final String AUTHORIZATION = "Authorization";
    public static final String CONTENT_TYPE = "Content-Type";
    public static final String LOCATION = "Location";

    public static final String MIME_JSON = "application/json";
    public static final String MIME_FORM = "application/x-www-form-urlencoded";
    public static final String MIME_CHARSET = "charset=";

    public static final String SEPARATOR_QUERY = "?";
    public static final String SEPARATOR_FRAGMENT = "#";

    static final List<String> CONTENT_METHODS_LIST = Arrays.asList("POST", "PUT");
    static final Set<String> CONTENT_METHODS = new HashSet<String>(CONTENT_METHODS_LIST);

    public static final ObjectMapper MAPPER = new ObjectMapper();

    static {
        MAPPER.setSerializationInclusion(Include.NON_NULL);
        MAPPER.getDeserializationConfig().without(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
    }

    protected static final Logger LOG = LoggerFactory.getLogger(NetworkTemplate.class);

    protected String accept = MIME_JSON;
    private final String baseUrl;
    private String authorization = null;

    public NetworkTemplate(String baseUrl) {
        this.baseUrl = baseUrl;
    }

    public NetworkTemplate() {
        this.baseUrl = null;
    }

    public static Map<String, String> asMap(String... nameValues) {
        final TreeMap<String, String> map = new TreeMap<String, String>();

        if (null != nameValues) {
            for (int i = 0; i + 1 < nameValues.length; i += 2) {
                map.put(nameValues[i], nameValues[i + 1]);
            }
        }

        return map;
    }

    public <J> J delete(String url, Class<J> responseClass) {
        return exchange("DELETE", url, null, null, responseClass);
    }

    public <J> J exchange(String method, String url, Map<String, String> requestHeaders, Object requestBody,
            Class<J> responseClass) {
        final NetworkResponse<J> response = exchangeForResponse(method, url, requestHeaders, requestBody,
                responseClass, true);
        return response.getBody();
    }

    public <J> NetworkResponse<J> exchangeForResponse(String method, String url, Map<String, String> requestHeaders,
            Object requestBody, Class<J> responseClass, boolean followRedirects) {

        // so that we can read in case of Exception
        InputStream in = null;
        try {

            // expand url?
            if (null != requestBody && !CONTENT_METHODS.contains(method)) {
                Map<String, Object> paramMap = requestBody instanceof Map ? (Map) requestBody
                        : MAPPER.convertValue(requestBody, Map.class);
                url = expandUrl(url, paramMap);
            }

            // create the connection
            URL u = new URL(url);
            HttpURLConnection con = (HttpURLConnection) u.openConnection();
            con.setInstanceFollowRedirects(followRedirects);

            // override default method
            if (null != method) {
                con.setRequestMethod(method);
            }
            LOG.info("{} {}", method, url);

            // Accept
            if (null != accept) {
                con.addRequestProperty(ACCEPT, accept);
                LOG.trace("{}: {}", ACCEPT, accept);
            }

            // Authorization
            if (null != authorization) {
                con.addRequestProperty(AUTHORIZATION, authorization);
                LOG.trace("{}: {}", AUTHORIZATION, authorization);
            }

            // other request headers:
            String contentType = null;
            if (null != requestHeaders) {
                for (Entry<String, String> entry : requestHeaders.entrySet()) {
                    con.addRequestProperty(entry.getKey(), entry.getValue());
                    LOG.info("{}: {}", entry.getKey(), entry.getValue());
                    if (CONTENT_TYPE.equalsIgnoreCase(entry.getKey())) {
                        contentType = entry.getValue();
                    }
                }
            }

            if (null != requestBody) {
                if (CONTENT_METHODS.contains(method)) {

                    // content-type not specified in request headers?
                    if (null == contentType) {
                        contentType = MIME_JSON;
                        con.addRequestProperty(CONTENT_TYPE, MIME_JSON);
                    }
                    con.setDoOutput(true);
                    OutputStream out = con.getOutputStream();
                    if (MIME_JSON.equals(contentType)) {
                        MAPPER.writeValue(out, requestBody);
                        final String json = MAPPER.writeValueAsString(requestBody);
                        LOG.debug("json Content: {}", json);
                    } else {
                        // application/www-form-urlencoded
                        PrintWriter writer = new PrintWriter(out);
                        if (requestBody instanceof String) {
                            writer.print(requestBody);
                            LOG.debug("Content: {}", requestBody);
                        } else {
                            Map<String, Object> params = MAPPER.convertValue(requestBody, Map.class);
                            String content = expandUrl("", params);
                            writer.print(content.substring(1));
                            LOG.debug("Content: {}", content.substring(1));
                        }
                        writer.flush();
                    }
                    out.close();
                }
            }

            NetworkResponse<J> response = new NetworkResponse<J>(con.getResponseCode(), con.getHeaderFields(),
                    con.getResponseMessage());
            LOG.info("HTTP {} {}", response.getCode(), response.getMessage());

            // response content to read and parse?
            if (null != con.getContentType()) {
                final String responseType = con.getContentType();
                LOG.debug("Content-Type: {}", responseType);
                in = con.getInputStream();

                if (con.getContentType().startsWith(MIME_JSON)) {
                    response.setBody(MAPPER.readValue(in, responseClass));
                    LOG.debug("Response JSON: {}", response.getBody());
                } else if (String.class.equals(responseClass)) {
                    String s = readResponseAsString(in, responseType);
                    LOG.info("Read {} bytes from {}", s.length(), con.getContentType());
                    response.setBody((J) s);
                } else if (400 <= response.getCode()) {
                    String s = readResponseAsString(in, responseType);
                    LOG.warn(s);
                }

                in.close();
            }

            return response;
        } catch (IOException ioe) {
            if (null != in) {
                try {
                    BufferedReader br = new BufferedReader(new InputStreamReader(in));
                    String s;
                    while (null != (s = br.readLine())) {
                        LOG.warn(s);
                    }
                } catch (IOException ignore) {
                }
            }
            throw new RuntimeException(String.format("NetworkTemplate.exchange: %s", ioe.getMessage()), ioe);
        }
    }

    protected String readResponseAsString(InputStream in, final String contentType)
            throws IOException, UnsupportedEncodingException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte b[] = new byte[1024];
        int count;
        while (0 < (count = in.read(b))) {
            baos.write(b, 0, count);
        }
        String charset = "UTF-8";
        int beginIndex = contentType.lastIndexOf(MIME_CHARSET);
        if (0 < beginIndex) {
            charset = contentType.substring(beginIndex + MIME_CHARSET.length());
        }
        final String s = baos.toString(charset);
        return s;
    }

    public static String expandUrl(final String url, Map<String, Object> paramMap) {
        return expandUrl(url, SEPARATOR_QUERY, paramMap);
    }

    public static String expandUrl(final String url, final String separator, Map<String, Object> paramMap) {
        StringBuffer sb = new StringBuffer(url);

        for (Entry<String, Object> entry : paramMap.entrySet()) {
            sb.append(-1 < sb.indexOf(separator) ? "&" : separator);
            sb.append(entry.getKey());
            sb.append('=');
            try {
                sb.append(URLEncoder.encode(entry.getValue().toString(), "UTF-8"));
            } catch (UnsupportedEncodingException shouldNeverHappen) {
                LOG.error("Encoding parameter", shouldNeverHappen);
            }
        }

        return sb.toString();
    }

    public <J> J get(String url, Class<J> responseClass, Object... requestBody) {
        return get(url, null, responseClass, requestBody);
    }

    public <J> J get(String url, Map<String, String> requestHeaders, Class<J> responseClass,
            Object... requestBody) {
        final Object requestParams = null != requestBody && 1 == requestBody.length ? requestBody[0] : null;
        return exchange("GET", url, requestHeaders, requestParams, responseClass);
    }

    public String getForLocation(String url, Object... requestBody) {
        return getForLocationWithHeaders(url, null, requestBody);
    }

    public String getForLocationWithHeaders(String url, Map<String, String> requestHeaders, Object... requestBody) {
        final Object requestParams = null != requestBody && 1 == requestBody.length ? requestBody[0] : null;
        NetworkResponse<Void> response = exchangeForResponse("GET", url, requestHeaders, requestParams, Void.class,
                false);
        return response.getHeader(LOCATION);
    }

    public <J> J post(String url, Object requestBody, Class<J> responseClass) {
        return post(url, null, requestBody, responseClass);
    }

    public <J> J post(String url, Map<String, String> requestHeaders, Object requestBody, Class<J> responseClass) {
        return exchange("POST", url, requestHeaders, requestBody, responseClass);
    }

    public String postForLocation(String url, Object requestBody) {
        return postForLocationWithHeaders(url, null, requestBody);
    }

    public String postForLocationWithHeaders(String url, Map<String, String> requestHeaders, Object requestBody) {
        NetworkResponse<Void> response = exchangeForResponse("POST", url, requestHeaders, requestBody, Void.class,
                false);
        return response.getHeader(LOCATION);
    }

    public static Map<String, String> parseQueryString(String s) {
        ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();

        for (String nameValue : s.split("&")) {
            String pair[] = nameValue.split("=");
            if (null != pair && 2 == pair.length) {
                try {
                    builder.put(pair[0], URLDecoder.decode(pair[1], "UTF-8"));
                } catch (UnsupportedEncodingException ex) {
                    LOG.warn("Decoding {}", pair[1]);
                }
            }
        }

        return builder.build();
    }

    // --- getters and setters ---

    public String getBaseUrl() {
        return baseUrl;
    }

    public void setAccept(String accept) {
        this.accept = accept;
    }

    public void setAuthorization(String authorization) {
        this.authorization = authorization;
    }

}