org.pentaho.pac.server.common.ThreadSafeHttpClient.java Source code

Java tutorial

Introduction

Here is the source code for org.pentaho.pac.server.common.ThreadSafeHttpClient.java

Source

/*
 * Copyright 2005-2008 Pentaho Corporation.  All rights reserved. 
 * This program is free software; you can redistribute it and/or modify it under the 
 * terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software 
 * Foundation.
 *
 * You should have received a copy of the GNU Lesser General Public License along with this 
 * program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html 
 * or from the Free Software Foundation, Inc., 
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * 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 Lesser General Public License for more details.
 *
 * Copyright 2008 - 2009 Pentaho Corporation.  All rights reserved.
 *
 * Created  
 * @author Steven Barkdull
 */

package org.pentaho.pac.server.common;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.HttpMethodBase;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.pentaho.pac.server.i18n.Messages;

/**
 * Provides a thread safe HttpClient with ability to do post and get.
 * 
 * Reuse notes: this class should be easily reusable in other applications. The
 * ONLY dependency on Pentaho code is for localized messages. To minimize coupling
 * (dependencies on other classes), and keep this code reusable by the
 * largest number of clients, this class should never have dependencies on 
 * other pentaho code.
 * 
 * @author Steven Barkdull
 *
 */
public class ThreadSafeHttpClient {
    private static final Log logger = LogFactory.getLog(ThreadSafeHttpClient.class);
    private static final String REQUESTED_MIME_TYPE = "requestedMimeType"; //$NON-NLS-1$
    public static final String DEFAULT_CONSOLE_PROPERTIES_FILE_NAME = "console.properties"; //$NON-NLS-1$
    public static final String CONTENT_CHARACTERSET_PROPERTY = "content.characterset"; //$NON-NLS-1$
    public static final String DEFAULT_CONTENT_CHARACTERSET_VALUE = "utf-8"; //$NON-NLS-1$
    public static String contentCharacterSet = null;

    public enum HttpMethodType {
        POST, GET
    };

    /*
     * @see: http://hc.apache.org/httpclient-3.x/threading.html
     */
    private static final HttpClient CLIENT;
    static {
        MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
        CLIENT = new HttpClient(connectionManager);
        CLIENT.getParams().setParameter("http.useragent", ThreadSafeHttpClient.class.getName()); //$NON-NLS-1$
        loadProperties();
    }

    /**
     * Base Constructor
     */
    public ThreadSafeHttpClient() {
        super();
    }

    /**
     * 
     * @param serviceName
     * @param methodType
     * @param mapParams
     * @return
     * @throws ProxyException if the attempt to communicate with the server fails,
     * if the attempt to read the response from the server fails, if the response
     * stream is unable to be converted into a String.
     */
    public String execRemoteMethod(String baseUrl, String serviceName, HttpMethodType methodType,
            Map<String, Object> mapParams) throws ProxyException {
        return execRemoteMethod(baseUrl, serviceName, methodType, mapParams, "text/xml"); //$NON-NLS-1$
    }

    /**
     * 
     * @param serviceName String can be null or empty string.
     * @param mapParams
     * @param requestedMimeType
     * @return
     * @throws ProxyException  ProxyException if the attempt to communicate with the server fails,
     * if the attempt to read the response from the server fails, if the response
     * stream is unable to be converted into a String.
     */
    public String execRemoteMethod(String baseUrl, String serviceName, HttpMethodType methodType,
            Map<String, Object> mapParams, String requestedMimeType) throws ProxyException {

        assert null != baseUrl : "baseUrl cannot be null"; //$NON-NLS-1$

        String serviceUrl = baseUrl;
        if (!StringUtils.isEmpty(serviceName)) {
            if (!serviceUrl.endsWith("/")) { //$NON-NLS-1$
                serviceUrl = serviceUrl + "/"; //$NON-NLS-1$
            }
            serviceUrl = serviceUrl + serviceName;
        }
        if (null == mapParams) {
            mapParams = new HashMap<String, Object>();
        }
        mapParams.put(REQUESTED_MIME_TYPE, requestedMimeType);

        HttpMethodBase method = null;
        switch (methodType) {
        case POST:
            method = new PostMethod(serviceUrl);
            method.getParams().setContentCharset(contentCharacterSet);//$NON-NLS-1$
            setPostMethodParams((PostMethod) method, mapParams);
            method.setFollowRedirects(false);
            break;
        case GET:
            method = new GetMethod(serviceUrl);
            method.getParams().setContentCharset(contentCharacterSet); //$NON-NLS-1$  
            setGetMethodParams((GetMethod) method, mapParams);
            method.setFollowRedirects(true);
            break;
        default:
            throw new RuntimeException(Messages.getErrorString(
                    "ThreadSafeHttpClient.ERROR_0002_INVALID_HTTP_METHOD_TYPE", methodType.toString())); // can never happen //$NON-NLS-1$
        }
        return executeMethod(method);
    }

    /**
     * Execute the <param>method</param>, and return the server's response as a string
     * @param method the HttpMethod specifying the server URL and parameters to be 
     * passed to the server.
     * @return a string containing the server's response
     * 
     * @throws ProxyException if the attempt to communicate with the server fails,
     * if the attempt to read the response from the server fails, if the response
     * stream is unable to be converted into a String.
     */
    private String executeMethod(HttpMethod method) throws ProxyException {
        InputStream responseStrm = null;
        try {
            int httpStatus = CLIENT.executeMethod(method);
            if (httpStatus != HttpStatus.SC_OK) {
                // If the response comes as unauthorized access we will throw a proxy exception explaining the reason and
                // what needs to be done to correct it
                if (httpStatus == HttpStatus.SC_UNAUTHORIZED) {
                    throw new ProxyException(
                            Messages.getErrorString("ThreadSafeHttpClient.ERROR_0003_AUTHORIZATION_FAILED"));
                }
                String status = method.getStatusLine().toString();
                String uri = method.getURI().toString();
                String errorMsg = Messages.getErrorString("ThreadSafeHttpClient.ERROR_0001_CLIENT_REQUEST_FAILED", //$NON-NLS-1$
                        uri, status);
                logger.error(errorMsg);
                throw new ProxyException(status); // TODO
            }
            responseStrm = method.getResponseBodyAsStream();
            // trim() is necessary because some jsp's put \n\r at the beginning of
            // the returned text, and the xml processor chokes on \n\r at the beginning.
            String response = IOUtils.toString(responseStrm).trim();
            return response;
        } catch (Exception e) {
            throw new ProxyException(e);
        } finally {
            method.releaseConnection();
        }
    }

    private static void setGetMethodParams(GetMethod method, Map<String, Object> mapParams) {
        NameValuePair[] params = mapToNameValuePair(mapParams);
        method.setQueryString(params);
    }

    private static void setPostMethodParams(PostMethod method, Map<String, Object> mapParams) {
        for (Map.Entry<String, Object> entry : mapParams.entrySet()) {
            Object o = entry.getValue();
            if (o instanceof String[]) {
                for (String s : (String[]) o) {
                    method.addParameter(entry.getKey(), s);
                }
            } else {
                method.setParameter(entry.getKey(), (String) o);
            }
        }
    }

    private static NameValuePair[] mapToNameValuePair(Map<String, Object> paramMap) {
        NameValuePair[] pairAr = new NameValuePair[paramMap.size()];
        int idx = 0;
        for (Map.Entry<String, Object> me : paramMap.entrySet()) {
            pairAr[idx] = new NameValuePair(me.getKey(), (String) me.getValue());
            idx++;
        }
        return pairAr;
    }

    private static void loadProperties() {
        FileInputStream fis = null;
        Properties properties = null;
        try {
            URL url = ClassLoader.getSystemResource(DEFAULT_CONSOLE_PROPERTIES_FILE_NAME);
            fis = new FileInputStream(new File(url.toURI()));
        } catch (Exception e) {
            contentCharacterSet = DEFAULT_CONTENT_CHARACTERSET_VALUE;
        }
        if (null != fis) {
            properties = new Properties();
            try {
                properties.load(fis);
            } catch (IOException e) {
                contentCharacterSet = DEFAULT_CONTENT_CHARACTERSET_VALUE;
            }
        }
        if (properties != null) {
            contentCharacterSet = properties.getProperty(CONTENT_CHARACTERSET_PROPERTY,
                    DEFAULT_CONTENT_CHARACTERSET_VALUE);
        } else {
            contentCharacterSet = DEFAULT_CONTENT_CHARACTERSET_VALUE;
        }
    }
}