code.google.restclient.client.HitterClient.java Source code

Java tutorial

Introduction

Here is the source code for code.google.restclient.client.HitterClient.java

Source

/*******************************************************************************
 * Copyright (c) 2010 Yadu.
 * 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:
 *     Yadu - initial API and implementation
 ******************************************************************************/

package code.google.restclient.client;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.entity.FileEntity;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.entity.StringEntity;
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.message.BasicNameValuePair;
import org.apache.log4j.Logger;

import code.google.restclient.common.RCConstants;
import code.google.restclient.common.RCUtil;
import code.google.restclient.core.Hitter;
import code.google.restclient.core.HttpHandler;
import code.google.restclient.exception.RCException;
import code.google.restclient.init.Configurator;
import code.google.restclient.mime.MimeTypeUtil;

/**
 * @author Yaduvendra.Singh
 */
public class HitterClient {

    private static final Logger LOG = Logger.getLogger(HitterClient.class);
    private static final boolean DEBUG_ENABLED = LOG.isDebugEnabled();

    private static final SimpleDateFormat SDF = new SimpleDateFormat("MMddyyyyHHmmssSS");
    private volatile boolean abort = false;

    public boolean isAbort() {
        return abort;
    }

    public void setAbort(boolean abort) {
        this.abort = abort;
    }

    public void hit(ViewRequest req, ViewResponse resp) throws RCException {
        Hitter hitter = new Hitter();
        HttpHandler handler = new HttpHandler();
        // hitter.setProxy("", -1); // set proxy taking values from UI
        try {
            String url = req.getUrlToHit();
            HttpEntity reqBodyEntity = null;
            if (RCUtil.isEntityEnclosingMethod(req.getMethod())) { // if request method has body
                if (req.isPostParams())
                    reqBodyEntity = getUrlEncodedFormEntity(req);
                else if (req.isMultipart())
                    reqBodyEntity = getMultipartEntity(req);
                else
                    reqBodyEntity = getStringOrFileEntity(req.getBodyToPost());
                handler.setReqBodyEntity(reqBodyEntity);
            }
            hitter.hit(url, req.getMethod(), handler, req.getInputHeaders());
        } catch (UnknownHostException uhe) {
            LOG.error("hit(): Error: Uknown host", uhe);
            throw new RCException("Error: Uknown host");
        } catch (Exception e) {
            LOG.error("hit(): Error occured while hiting url", e);
            throw new RCException("Error: " + RCUtil.removeMethodName(e.getMessage()));
        } finally {
            req = prepareViewRequest(req, handler);
            resp = prepareViewResponse(resp, handler);
            if (!handler.isReqAborted())
                handler.closeConnection();
        }
    }

    /* ***************** Entity creator methods ***************** */
    private HttpEntity getStringOrFileEntity(String body) throws RCException {
        if (body == null)
            body = "";
        HttpEntity reqEntity = null;
        if (body.startsWith("@")) {
            String path = Pattern.compile("^@").matcher(body).replaceAll("");
            String mimeType = MimeTypeUtil.getMimeType(path);
            // TODO not specifying charset as part of mime type i.e. "text/plain" and not "text/plain; charset=UTF-8"
            reqEntity = new FileEntity(new File(path), mimeType); // second argument is contentType e.g. "text/plain; charset=\"UTF-8\"");
        } else {
            try {
                reqEntity = new StringEntity(body, RCConstants.DEFAULT_CHARSET);
            } catch (UnsupportedEncodingException e) {
                throw new RCException(
                        "getStringOrFileEntity(): Could not prepare string post entity due to unsupported encoding",
                        e);
            }
        }
        return reqEntity;
    }

    private UrlEncodedFormEntity getUrlEncodedFormEntity(ViewRequest req) throws RCException {
        List<NameValuePair> formparams = new ArrayList<NameValuePair>();
        Map<String, String> params = req.getParams();
        for (String paramName : params.keySet()) {
            formparams.add(new BasicNameValuePair(paramName, params.get(paramName)));
        }
        try {
            UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formparams, RCConstants.DEFAULT_CHARSET);
            if (DEBUG_ENABLED)
                LOG.debug("getParamsPostEntity() - post body: " + streamToString(entity.getContent()));
            return entity;
        } catch (UnsupportedEncodingException e) {
            throw new RCException(
                    "getParamsPostEntity(): Could not prepare params post entity due to unsupported encoding", e);
        } catch (IOException e) {
            throw new RCException("getParamsPostEntity(): request entity body could not be read");
        }
    }

    private MultipartEntity getMultipartEntity(ViewRequest req) throws RCException {
        MultipartEntity reqEntity = new MultipartEntity();
        Map<String, String> params = req.getParams();
        String paramValue = null;
        StringBody stringBody = null;

        try {
            for (String paramName : params.keySet()) {
                paramValue = params.get(paramName);
                stringBody = new StringBody(paramValue, Charset.forName(RCConstants.DEFAULT_CHARSET));
                reqEntity.addPart(paramName, stringBody);
            }
            String fileParamName = req.getFileParamName();
            File selectedFile = new File(req.getFilePath());

            if (selectedFile.exists() && !RCUtil.isEmpty(fileParamName)) {
                String mimeType = MimeTypeUtil.getMimeType(req.getFilePath());
                FileBody fileBody = new FileBody(selectedFile, mimeType);
                reqEntity.addPart(fileParamName, fileBody);
            }
        } catch (UnsupportedEncodingException e) {
            throw new RCException(
                    "getMultipartEntity(): Could not prepare multipart entity due to unsupported encoding", e);
        }
        return reqEntity;
    }

    /**
     * Method to get file entity from file object
     */
    private FileEntity hit(File body) throws Exception {
        FileEntity fileEntity = new FileEntity(body, ""); // second argument is contentType e.g. "text/plain; charset=\"UTF-8\"");
        return fileEntity;
    }

    /**
     * Method to make get input stream entity from input stream object
     */
    private InputStreamEntity hit(InputStream body) throws Exception {
        InputStreamEntity isEntity = new InputStreamEntity(body, -1); // content length is unknown so -1
        return isEntity;
    }

    /* ***************** Methods to prepare view request and response objects ***************** */
    private ViewRequest prepareViewRequest(ViewRequest req, HttpHandler handler) {
        if (handler != null && req != null) {
            req.setReqLine(handler.getRequestLine());
            // req.setUrl(handler.getUrl());
            req.setHeaders(handler.getRequestHeaders());
            URI uri = handler.getUri();
            if (uri != null) {
                req.setHost(uri.getHost());
                req.setPort(uri.getPort());
                req.setPath(uri.getRawPath());
                req.setScheme(uri.getScheme());
                req.setQueryStrRaw(uri.getRawQuery());
            }
            req.setProtocolVersion(handler.getProtocolVersion());
        }
        return req;
    }

    private ViewResponse prepareViewResponse(ViewResponse resp, HttpHandler handler) throws RCException {
        if (handler != null && resp != null) {
            resp.setStatusLine(handler.getStatusLine());
            resp.setUrl(handler.getUrl());
            resp.setHeaders(handler.getResponseHeaders());
            String contentType = handler.getResponseContentType();
            resp.setContentType(contentType);

            String respStr = null;
            if (isTextOrXmlResponse(handler)) {
                respStr = streamToString(handler);
                resp.setBodyStr(respStr);
            } else
                resp.setBodyFile(streamToFile(handler, contentType));

            // writing xml response to file as well as keeping it as body string. This is just for showing
            // xml in browser with syntax highlighting until there is syntax highlighter for response pane
            if (!RCUtil.isEmpty(respStr) && isXmlResponse(handler)) {
                resp.setBodyFile(stringToFile(respStr, contentType));
            }
        }
        return resp;
    }

    /* ***************** Helper methods ***************** */
    private String streamToString(HttpHandler handler) throws RCException {
        InputStream is = handler.getResponseStream();
        if (is == null)
            return null;
        StringBuilder sb = new StringBuilder();
        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
        String line = null;
        try {
            while ((line = reader.readLine()) != null) {
                sb.append("\n");
                if (abort) {
                    handler.abort();
                    abort = false;
                    break;
                }
                sb.append(line);
            }
        } catch (IOException e) {
            throw new RCException("streamToString(): error occurred while converting response stream to string", e);
        } finally {
            try {
                if (reader != null && !handler.isReqAborted())
                    reader.close();
            } catch (IOException e) {
                throw new RCException("streamToString(): error occurred while closing input stream", e);
            }
        }
        return sb.toString().replaceFirst("\n", "");
    }

    private String streamToString(InputStream is) throws RCException {
        if (is == null)
            return null;
        StringBuilder sb = new StringBuilder();
        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
        String line = null;
        try {
            while ((line = reader.readLine()) != null) {
                sb.append("\n");
                sb.append(line);
            }
        } catch (IOException e) {
            throw new RCException("streamToString(): error occurred while converting response stream to string", e);
        } finally {
            try {
                if (reader != null)
                    reader.close();
            } catch (IOException e) {
                throw new RCException("streamToString(): error occurred while closing input stream", e);
            }
        }
        return sb.toString().replaceFirst("\n", "");
    }

    private File streamToFile(HttpHandler handler, String contentType) throws RCException {
        InputStream is = handler.getResponseStream();
        if (is == null)
            return null;
        String timeStamp = SDF.format(new Date());
        File tmpFile = new File(Configurator.getTempRespFilesDir(),
                "output_" + timeStamp + "." + RCConstants.TEMP_FILE_EXT);
        File outputFile = null;
        FileOutputStream fos = null;
        byte[] buf = new byte[2 * 1024];
        int len;
        try {
            fos = new FileOutputStream(tmpFile);
            while ((len = is.read(buf)) != -1) {
                if (abort) {
                    handler.abort();
                    abort = false;
                    break;
                }
                fos.write(buf, 0, len);
            }
            fos.flush();
        } catch (Exception e) {
            throw new RCException("streamToFile(): error occurred while writing to file", e);
        } finally {
            try {
                if (fos != null)
                    fos.close();
                outputFile = changeFileExtension(tmpFile, contentType);
            } catch (IOException e) {
                throw new RCException("streamToFile(): error occurred while closing input/output stream", e);
            }
        }
        return outputFile;
    }

    private File stringToFile(String str, String contentType) throws RCException {

        if (RCUtil.isEmpty(str))
            return null;
        String timeStamp = SDF.format(new Date());
        File tmpFile = new File(Configurator.getTempRespFilesDir(),
                "output_" + timeStamp + "." + RCConstants.TEMP_FILE_EXT);
        File outputFile = null;
        FileWriter fw = null;
        try {
            fw = new FileWriter(tmpFile);
            fw.write(str);
            fw.flush();
        } catch (Exception e) {
            throw new RCException("stringToFile(): error occurred while writing to file", e);
        } finally {
            try {
                if (fw != null)
                    fw.close();
                outputFile = changeFileExtension(tmpFile, contentType);
            } catch (IOException e) {
                throw new RCException("stringToFile(): error occurred while closing file writer", e);
            }
        }
        return outputFile;
    }

    private File changeFileExtension(File tmpFile, String contentType) throws IOException {
        // change extension of file to its media type
        String ext = "";
        if (RCUtil.isEmpty(contentType))
            contentType = MimeTypeUtil.getMimeType(tmpFile);

        ext = getSubType(contentType);
        if (ext.contains("xml"))
            ext = "xml";
        /*
        if ( contentType != null && contentType.indexOf("/") > 0 ) { // i.e. application/ssml+xml; charset=UTF-8
        ext = contentType.substring(contentType.indexOf("/") + 1);
        if ( ext.indexOf(";") > 0 ) ext = ext.substring(0, ext.indexOf(";")).trim();
        if ( ext.contains("xml") ) ext = "xml";
        }
        */
        if (!RCUtil.isEmpty(ext)) {
            String filePath = tmpFile.getCanonicalPath();
            String newFileName = filePath.replaceFirst("\\." + RCConstants.TEMP_FILE_EXT + "$", "." + ext);
            File outputFile = new File(newFileName);
            boolean success = tmpFile.renameTo(outputFile);
            if (success)
                return outputFile;
        }
        return tmpFile;
    }

    /**
     * Returns true if response is of text or xml type or if content type is null
     */
    private boolean isTextOrXmlResponse(HttpHandler handler) {
        String contentType = handler.getResponseContentType();
        if (contentType != null) {
            if (contentType.indexOf(";") > 0) {
                contentType = contentType.substring(0, contentType.indexOf(";")).trim();
            }
            // check for extra text content types specified in config file
            String[] extraTextContTypes = RCConstants.EXTRA_TEXT_CONTENT_TYPES.split(",");
            for (String extraContType : extraTextContTypes) {
                if (extraContType.equalsIgnoreCase(contentType))
                    return true;
            }
        }
        if (contentType != null && !contentType.startsWith("text"))
            return false;
        return true;
    }

    private boolean isXmlResponse(HttpHandler handler) {
        String contentType = handler.getResponseContentType();
        String subType = getSubType(contentType);
        if (subType != null) {
            if (contentType.startsWith("text") && subType.contains("xml"))
                return true;
            // check for extra text content types specified in config file
            String[] extraTextContTypes = RCConstants.EXTRA_TEXT_CONTENT_TYPES.split(",");
            for (String extraContType : extraTextContTypes) {
                String xSubType = extraContType.substring(extraContType.indexOf("/") + 1);
                if (xSubType.equalsIgnoreCase(subType))
                    return true;
            }
        }
        return false;
    }

    private String getSubType(String contentType) {
        // process content type which is generally in format "type/subtype; charset=XYZ"
        // i.e. application/ssml+xml; charset=UTF-8
        String subType = null;
        if (contentType != null && contentType.indexOf("/") > 0) {
            // remove type
            subType = contentType.substring(contentType.indexOf("/") + 1);
            // remove charset
            if (subType.indexOf(";") > 0)
                subType = subType.substring(0, subType.indexOf(";")).trim();
        }
        if (DEBUG_ENABLED)
            LOG.debug("getSubType() - returning sub type " + subType);
        return subType;
    }

    /*
       public static void main(String[] args) {
      HitterClient client = new HitterClient();
      ViewRequest req = new ViewRequest();
      ViewResponse resp = new ViewResponse();
      req.setUrl("http://localhost.mlbam.com:8080/stage/v1.1/14/content/item/read/6845668?test= you # me");
      //req.setUrl("http://localhost.mlbam.com:8080/stage/v1.1/14/content/item/viewImage?fileLocation=/images/04022010/6845668/Sunset.jpg");
      req.setHeadersStr("fingerprint=offline-fingerprint\nidentitypointid=9364");
      req.setMethod("GET");
      req.setParamsStr("output=json");
      //client.setAbort();
      try {
         client.hit(req, resp);
      } catch (RCException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
      }
      System.out.println("************ Request ****************");
      System.out.println("Request Headers: \n" + req.getDisplayHeaderPart());
      System.out.println("Request Body: \n" + req.getDisplayBodyPart());
          
      System.out.println("************ Response ****************");
      System.out.println("ViewResponse Headers:\n" + resp.getDisplayHeaderPart());
      System.out.println("ViewResponse Body:\n" + resp.getDisplayBodyPart());
      System.out.println("ViewResponse Body File Path:\n" + resp.getBodyFile());
       }
    */
}