com.jeffrodriguez.webtools.client.URLConnectionWebClientImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.jeffrodriguez.webtools.client.URLConnectionWebClientImpl.java

Source

/* This is free and unencumbered software released into the public domain.
 *
 * Anyone is free to copy, modify, publish, use, compile, sell, or
 * distribute this software, either in source code form or as a compiled
 * binary, for any purpose, commercial or non-commercial, and by any
 * means.
 *
 * In jurisdictions that recognize copyright laws, the author or authors
 * of this software dedicate any and all copyright interest in the
 * software to the public domain. We make this dedication for the benefit
 * of the public at large and to the detriment of our heirs and
 * successors. We intend this dedication to be an overt act of
 * relinquishment in perpetuity of all present and future rights to this
 * software under copyright law.
 *
 * 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 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.
 *
 * For more information, please refer to <http://unlicense.org/>
 */
package com.jeffrodriguez.webtools.client;

import com.jeffrodriguez.xmlwrapper.XML;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import net.sf.jsog.JSOG;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;

/**
 * A URLConnection-based WebClient implementation.
 * @author Jeff
 */
public class URLConnectionWebClientImpl implements WebClient {
    private static final Logger logger = Logger.getLogger(URLConnectionWebClientImpl.class.toString());

    private static void checkForErrors(HttpURLConnection connection) throws IOException {

        // If this is a 200-range response code, just return
        if (connection.getResponseCode() >= 200 && connection.getResponseCode() < 300) {
            return;
        }

        // Build the IO Exception
        IOException e = new IOException(connection.getResponseCode() + ": " + connection.getResponseMessage());

        // Get the response as a string
        String response = IOUtils.toString(connection.getErrorStream(), "ISO-8859-1");

        // Log it
        logger.log(Level.SEVERE, response, e);

        // Throw it
        throw e;
    }

    private static <T> T disconnectAndReturn(HttpURLConnection connection, T result) throws IOException {
        connection.disconnect();
        return result;
    }

    /**
     * The timeout when establishing a connection and reading/writing data.
     */
    private int timeout = 0;

    @Override
    public void setTimeout(int timeout) {
        this.timeout = timeout;
    }

    /**
     * The authorization header to send, if any.
     */
    private String authorization;

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

    @Override
    public void setAuthorization(String username, String password) {
        String userPass = username + ":" + password;
        try {
            authorization = "Basic " + Base64.encodeBase64String(userPass.getBytes("ISO-8859-1"));
        } catch (UnsupportedEncodingException e) {
            throw new Error(e);
        }
    }

    /**
     * Builds a document from an input stream.
     *
     * Override this method if you need a special Document building facility.
     * @param in the input stream.
     * @return the document.
     * @throws IOException
     * @throws ParserConfigurationException
     * @throws SAXException
     */
    protected Document buildDocument(InputStream in)
            throws IOException, ParserConfigurationException, SAXException {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder db = dbf.newDocumentBuilder();
        return db.parse(in);
    }

    private HttpURLConnection buildConnection(String urlString) throws IOException {
        URL url = new URL(urlString);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setDoInput(true);
        connection.setConnectTimeout(timeout);
        connection.setReadTimeout(timeout);
        connection.setUseCaches(false);

        // Set the authorization header if one has been specified
        if (authorization != null) {
            connection.setRequestProperty("Authorization", authorization);
        }

        return connection;
    }

    @Override
    public void get(String url, OutputStream out) throws IOException {
        logger.log(Level.INFO, "Getting from {0}", url);

        // Build and connect
        HttpURLConnection connection = buildConnection(url);
        connection.connect();

        // Check for errors
        checkForErrors(connection);

        // Get the result
        disconnectAndReturn(connection, IOUtils.copy(connection.getInputStream(), out));
    }

    @Override
    public byte[] get(String url, Map<String, List<String>> headers) throws IOException {
        logger.log(Level.INFO, "Getting byte[] from {0}", url);

        // Build and connect
        HttpURLConnection connection = buildConnection(url);
        applyHeaders(connection, headers);
        connection.connect();

        // Check for errors
        checkForErrors(connection);

        // Get the result
        return disconnectAndReturn(connection, IOUtils.toByteArray(connection.getInputStream()));
    }

    @Override
    public byte[] get(String url) throws IOException {
        logger.log(Level.INFO, "Getting byte[] from {0}", url);

        // Build and connect
        HttpURLConnection connection = buildConnection(url);
        connection.connect();

        // Check for errors
        checkForErrors(connection);

        // Get the result
        return disconnectAndReturn(connection, IOUtils.toByteArray(connection.getInputStream()));
    }

    @Override
    public byte[] post(String url, byte[] data, Map<String, List<String>> headers) throws IOException {

        // Build and connect
        HttpURLConnection connection = buildConnection(url);
        applyHeaders(connection, headers);
        connection.setDoOutput(true);
        connection.setDoInput(true);
        connection.connect();

        // Send the request
        connection.getOutputStream().write(data);
        connection.getOutputStream().flush();
        connection.getOutputStream().close();

        // Check for errors
        checkForErrors(connection);

        // Get the result
        return disconnectAndReturn(connection, IOUtils.toByteArray(connection.getInputStream()));
    }

    @Override
    public byte[] post(String url, byte[] data) throws IOException {

        // Build and connect
        HttpURLConnection connection = buildConnection(url);
        connection.setDoOutput(true);
        connection.setDoInput(true);
        connection.connect();

        // Send the request
        connection.getOutputStream().write(data);
        connection.getOutputStream().flush();
        connection.getOutputStream().close();

        // Check for errors
        checkForErrors(connection);

        // Get the result
        return disconnectAndReturn(connection, IOUtils.toByteArray(connection.getInputStream()));
    }

    @Override
    public String getString(String url) throws IOException {
        logger.log(Level.INFO, "Getting String from {0}", url);

        // Build and connect
        HttpURLConnection connection = buildConnection(url);
        connection.connect();

        // Check for errors
        checkForErrors(connection);

        // Get the result
        return disconnectAndReturn(connection, IOUtils.toString(connection.getInputStream(), "ISO-8859-1"));
    }

    @Override
    public String postString(String url, String data) throws IOException {

        // Build and connect
        HttpURLConnection connection = buildConnection(url);
        connection.setDoOutput(true);
        connection.setDoInput(true);
        connection.connect();

        // Send the request
        connection.getOutputStream().write(data.getBytes("ISO-8859-1"));
        connection.getOutputStream().flush();
        connection.getOutputStream().close();

        // Check for errors
        checkForErrors(connection);

        // Get the result
        return disconnectAndReturn(connection, IOUtils.toString(connection.getInputStream(), "ISO-8859-1"));
    }

    @Override
    public Document getDocument(String url) throws IOException, ParserConfigurationException, SAXException {
        logger.log(Level.INFO, "Getting Document from {0}", url);

        // Build and connect
        HttpURLConnection connection = buildConnection(url);
        connection.connect();

        // Check for errors
        checkForErrors(connection);

        // Get the result
        return disconnectAndReturn(connection, buildDocument(connection.getInputStream()));
    }

    @Override
    public Document postDocument(String url, Document data)
            throws IOException, TransformerException, SAXException, ParserConfigurationException {
        logger.log(Level.INFO, "Posting document to {0}", url);

        // Build and connect
        HttpURLConnection connection = buildConnection(url);
        connection.setDoOutput(true);
        OutputStream out = connection.getOutputStream();
        connection.connect();

        // Write the document
        Transformer transformer = TransformerFactory.newInstance().newTransformer();
        transformer.transform(new DOMSource(data), new StreamResult(out));
        out.flush();
        out.close();

        // Check for errors
        checkForErrors(connection);

        // Get the result
        return disconnectAndReturn(connection, buildDocument(connection.getInputStream()));
    }

    @Override
    public XML getXML(String url) throws IOException, ParserConfigurationException, SAXException {
        logger.log(Level.INFO, "Getting Document from {0}", url);

        // Build and connect
        HttpURLConnection connection = buildConnection(url);
        connection.connect();

        // Check for errors
        checkForErrors(connection);

        // Get the result
        Document document = buildDocument(connection.getInputStream());
        return disconnectAndReturn(connection, new XML(document));
    }

    @Override
    public XML postXML(String url, XML data)
            throws IOException, TransformerException, SAXException, ParserConfigurationException {
        logger.log(Level.INFO, "Posting document to {0}", url);

        // Build and connect
        HttpURLConnection connection = buildConnection(url);
        connection.setDoOutput(true);
        OutputStream out = connection.getOutputStream();
        connection.connect();

        // Write the document
        Transformer transformer = TransformerFactory.newInstance().newTransformer();
        transformer.transform(new DOMSource(data.getDocument()), new StreamResult(out));
        out.flush();
        out.close();

        // Check for errors
        checkForErrors(connection);

        // Get the result
        Document document = buildDocument(connection.getInputStream());
        return disconnectAndReturn(connection, new XML(document));
    }

    @Override
    public JSOG getJsog(String url) throws IOException {
        logger.log(Level.INFO, "Getting JSOG from {0}", url);

        // Build and connect
        HttpURLConnection connection = buildConnection(url);
        connection.connect();

        // Check for errors
        checkForErrors(connection);

        // Get the result
        return disconnectAndReturn(connection,
                JSOG.parse(IOUtils.toString(connection.getInputStream(), "ISO-8859-1")));
    }

    @Override
    public JSOG postJsog(String url, JSOG data) throws IOException {

        // Build and connect
        HttpURLConnection connection = buildConnection(url);
        connection.setDoOutput(true);
        connection.setDoInput(true);
        connection.setRequestProperty("Content-Type", "application/json; charset=ISO-8859-1");
        connection.connect();

        // Send the request
        connection.getOutputStream().write(data.toString().getBytes("ISO-8859-1"));
        connection.getOutputStream().flush();
        connection.getOutputStream().close();

        // Check for errors
        checkForErrors(connection);

        // Get the result
        return disconnectAndReturn(connection,
                JSOG.parse(IOUtils.toString(connection.getInputStream(), "ISO-8859-1")));
    }

    @Override
    public Map<String, List<String>> getHeaders(String url) throws IOException {

        logger.log(Level.INFO, "Getting HEAD from {0}", url);

        // Build and connect
        HttpURLConnection connection = buildConnection(url);
        connection.setDoInput(true);
        connection.setRequestMethod("HEAD");
        connection.connect();

        // Get the headers
        return disconnectAndReturn(connection, connection.getHeaderFields());
    }

    /**
     * Applies a set of headers to the connection.
     * @param connection the connection.
     * @param headers the headers
     */
    private void applyHeaders(HttpURLConnection connection, Map<String, List<String>> headers) {

        //  Make sure there are headers to apply
        if (headers == null || headers.isEmpty()) {
            return;
        }

        // Apply the headers
        for (Map.Entry<String, List<String>> header : headers.entrySet()) {
            if (header.getValue() != null && header.getValue().size() > 0) {

                /* Concatenate the header values, based on the note in setRequestProperty:
                 * NOTE: HTTP requires all request properties which can legally have multiple
                 * instances with the same key to use a comma-seperated list syntax which
                 * enables multiple properties to be appended into a single property.
                 */
                StringBuilder headerValue = new StringBuilder();
                Iterator<String> it = header.getValue().iterator();
                while (it.hasNext()) {

                    // Get the value
                    String value = it.next();
                    if (value == null) {
                        value = "";
                    }

                    // Append the value
                    headerValue.append(value);

                    // Add a comma if there are more values
                    if (it.hasNext()) {
                        headerValue.append(',');
                    }
                }

                // Set the header
                connection.setRequestProperty(header.getKey(), headerValue.toString());
            }
        }

    }

}