org.myrobotlab.service.HttpClient.java Source code

Java tutorial

Introduction

Here is the source code for org.myrobotlab.service.HttpClient.java

Source

/**
 *                    
 * @author greg (at) myrobotlab.org
 *  
 * This file is part of MyRobotLab (http://myrobotlab.org).
 *
 * MyRobotLab 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 2 of the License, or
 * (at your option) any later version (subject to the "Classpath" exception
 * as provided in the LICENSE.txt file that accompanied this code).
 *
 * MyRobotLab is distributed in the hope that it will be useful or fun,
 * 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.
 *
 * All libraries in thirdParty bundle are subject to their own license
 * requirements - please refer to http://myrobotlab.org/libraries for 
 * details.
 * 
 * Enjoy !
 * 
 * */

package org.myrobotlab.service;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.StatusLine;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.myrobotlab.framework.Service;
import org.myrobotlab.framework.ServiceType;
import org.myrobotlab.logging.Level;
import org.myrobotlab.logging.LoggerFactory;
import org.myrobotlab.logging.Logging;
import org.myrobotlab.logging.LoggingFactory;
import org.myrobotlab.service.data.HttpData;
import org.myrobotlab.service.interfaces.HttpDataListener;
import org.myrobotlab.service.interfaces.HttpResponseListener;
import org.myrobotlab.service.interfaces.ServiceInterface;
import org.slf4j.Logger;

/**
 * HttpClient - wrapper for Apache HttpClient
 * 
 * @author GroG
 * 
 *         TODO - asynchronous call back similar to AngularJS promise - or at
 *         least a callback method is call .. onHttpResponse
 * 
 *         Synchronous or Asynchrounous - Synchronous by default, Asynchronous
 *         if a callback method is supplied or Non-Blocking method is called
 */
public class HttpClient extends Service implements HttpDataListener, HttpResponseListener {

    private static final long serialVersionUID = 1L;

    public final static Logger log = LoggerFactory.getLogger(HttpClient.class);

    /**
     * This static method returns all the details of the class without it having
     * to be constructed. It has description, categories, dependencies, and peer
     * definitions.
     * 
     * @return ServiceType - returns all the data
     * 
     */
    static public ServiceType getMetaData() {

        ServiceType meta = new ServiceType(HttpClient.class.getCanonicalName());
        meta.addDescription("an HTTP client, used to fetch information on the web");
        meta.addCategory("network");
        meta.addDependency("org.apache.commons.httpclient", "4.5.2");
        return meta;
    }

    transient CloseableHttpClient client;

    transient HashMap<String, String> formFields = new HashMap<String, String>();

    public HttpClient(String n) {
        super(n);
    }

    public void addFormField(String name, String value) {
        formFields.put(name, value);
    }

    public void addHttpDataListener(ServiceInterface listener) {
        /*
         * TODO - finish this thought out .. it would mean a Map of method
         * signatures to interface methods .. and direct callbacks Pro - is an
         * optimization Con - is potentially blocking the callback thread for "too"
         * long
         * 
         * if (SerialDataListener.class.isAssignableFrom(listener.getClass()) &&
         * listener.isLocal()) { // direct callback
         * listeners.put(si.getName(),(SerialDataListener) si); } else {
         */

        // pub sub
        // instead of getting the data twice and expecting 2 methods for more or
        // less the same material
        // we will leave it up to the subscribing service to do subscribe and
        // implement onHttpData
        listener.subscribe(getName(), "publishHttpData");

        // }
    }

    public void addHttpResponseListener(ServiceInterface listener) {
        listener.subscribe(getName(), "publishHttpResponse");
    }

    public void clearForm() {
        formFields.clear();
    }

    public String get(String uri) throws ClientProtocolException, IOException {
        HttpData response = processResponse((HttpUriRequest) new HttpGet(uri), null);
        if (response.data != null) {
            return new String(response.data);
        }
        return null;
    }

    public byte[] getBytes(String uri) throws ClientProtocolException, IOException {
        return processResponse((HttpUriRequest) new HttpGet(uri), null).data;
    }

    /**
     * publishHttpData contains more information content type, response code,
     * etc... need to subscribe to it manually for testing purposes
     * 
     */
    @Override
    public void onHttpData(HttpData data) {
        log.info(data.toString());
    }

    /**
     * for testing purposes
     * 
     * @param data
     * @return
     */
    @Override
    public void onHttpResponse(String data) {
        log.info(data);
    }

    public String post(String uri) throws ClientProtocolException, IOException {
        HttpData response = processResponse((HttpUriRequest) new HttpPost(uri), null);
        if (response.data != null) {
            return new String(response.data);
        }
        return null;
    }

    public String post(String uri, HashMap<String, String> fields) throws ClientProtocolException, IOException {
        byte[] data = postBytes(uri, fields);
        if (data != null) {
            return new String(data);
        }
        return null;
    }

    public byte[] postBytes(String uri, HashMap<String, String> fields)
            throws ClientProtocolException, IOException {
        return processResponse((HttpUriRequest) new HttpPost(uri), fields).data;
    }

    public HttpData processResponse(HttpUriRequest request, HashMap<String, String> fields) throws IOException {
        HttpData data = new HttpData(request.getURI().toString());
        if (fields == null) {

            fields = formFields;
        }

        if (request.getClass().equals(HttpPost.class) && formFields.size() > 0) {
            List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(fields.size());
            for (String nvPairKey : fields.keySet()) {
                nameValuePairs.add(new BasicNameValuePair(nvPairKey, fields.get(nvPairKey)));
                ((HttpPost) request).setEntity(new UrlEncodedFormEntity(nameValuePairs));
            }
        }
        HttpResponse response = client.execute(request);
        StatusLine statusLine = response.getStatusLine();
        data.responseCode = statusLine.getStatusCode();
        HttpEntity entity = response.getEntity();
        Header header = entity.getContentType();
        if (header != null) {
            data.contentType = header.getValue().toString();
        }

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        response.getEntity().writeTo(baos);
        data.data = baos.toByteArray();

        // publishing
        invoke("publishHttpData", data);
        if (data.data != null) {
            invoke("publishHttpResponse", new String(data.data));
        }

        return data;
    }

    /**
     * publishing point for any http request this is the asynchronous callback
     * which will arrive typically at publishHttpData(data)
     * 
     * contains more data than just the text, can be used for any content type
     * too, since the payload is in a byte[]
     * 
     * @param data
     * @return
     */
    public HttpData publishHttpData(HttpData data) {
        return data;
    }

    /**
     * publishing point for any http request this is the asynchronous callback
     * which will arrive typically at onHttpRespone(data)
     * 
     * @param data
     * @return
     */
    public String publishHttpResponse(String data) {
        return data;
    }

    public void startService() {
        super.startService();
        if (client == null) {
            // new MultiThreadedHttpConnectionManager()
            client = HttpClients.createDefault();
        }
    }

    // Set the default host/protocol for the methods to connect to.
    // This value will only be used if the methods are not given an absolute URI
    // httpClient.getHostConfiguration().setHost("hc.apache.org", 80, "http");

    // Map<String, HttpData> clients = new HashMap<String, HttpData>();

    // TODO - proxy !
    // TODO - authentication !

    public static void main(String[] args) {
        LoggingFactory.init(Level.INFO);

        try {

            HttpClient client = (HttpClient) Runtime.start("client", "HttpClient");
            // this is how a listener might subscribe
            // TODO - put dynamically subscribing into framework
            // with interface inspection ??
            client.addHttpResponseListener(client);
            client.addHttpDataListener(client);

            // TODO - getByteArray(...)
            String index = client.get("https://www.cs.tut.fi/~jkorpela/forms/testing.html");
            log.info(index);

            client.addFormField("Comments", "This is a different comment");
            client.addFormField("Box", "yes");
            client.addFormField("Unexpected", "this is an unexpected field");
            client.addFormField("hidden field", "something else");

            String response = client.post("http://www.cs.tut.fi/cgi-bin/run/~jkorpela/echo.cgi");

            log.info(response);

            client.clearForm();
            client.addFormField("hidden field", "something else");
            response = client.post("http://www.cs.tut.fi/cgi-bin/run/~jkorpela/echo.cgi");
            log.info(response);

            response = client.get("http://www.google.com/search?hl=en&q=myrobotlab&btnG=Google+Search&aq=f&oq=");
            log.info(response);

        } catch (Exception e) {
            Logging.logError(e);
        }

    }

}