domderrien.wrapper.UrlFetch.UrlFetchHttpConnection.java Source code

Java tutorial

Introduction

Here is the source code for domderrien.wrapper.UrlFetch.UrlFetchHttpConnection.java

Source

/******************************************************************************* 
 *  Adaptation for the Amazon FPS library to work on the Java platform of
 *  Google App Engine.
 *  
 *  Copyright 2010 Dom Derrien
 *  Licensed under the Apache License, Version 2.0
 */

package domderrien.wrapper.UrlFetch;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.Socket;
import java.net.SocketException;
import java.net.URL;

import javamocks.io.MockInputStream;
import javamocks.io.MockOutputStream;

import org.apache.commons.httpclient.HostConfiguration;
import org.apache.commons.httpclient.HttpConnection;
import org.apache.commons.httpclient.HttpConnectionManager;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.params.HttpConnectionParams;
import org.apache.commons.httpclient.protocol.Protocol;

import com.google.appengine.api.urlfetch.FetchOptions;
import com.google.appengine.api.urlfetch.HTTPHeader;
import com.google.appengine.api.urlfetch.HTTPMethod;
import com.google.appengine.api.urlfetch.HTTPRequest;
import com.google.appengine.api.urlfetch.HTTPResponse;
import com.google.appengine.api.urlfetch.URLFetchService;
import com.google.appengine.api.urlfetch.URLFetchServiceFactory;

public class UrlFetchHttpConnection extends HttpConnection {

    private static URLFetchService urlFS = URLFetchServiceFactory.getURLFetchService();

    private HostConfiguration hostConfiguration;
    private HTTPRequest _request;
    private HTTPResponse _response;
    private MockOutputStream _requestBody = new MockOutputStream();
    private MockInputStream _responseBody = new MockInputStream();

    private HTTPRequest getRequest() throws MalformedURLException {
        if (_request == null) {
            _request = new HTTPRequest(new URL(hostConfiguration.getHostURL()), HTTPMethod.POST, // AmazonFPSClient#invoke(Class<T>, Map<String,String>) uses only POST method
                    FetchOptions.Builder.disallowTruncate().followRedirects());
        }
        return _request;
    }

    private static final String SEPARATOR = ": ";
    private static final int SEPARATOR_LENGTH = SEPARATOR.length();
    private static final String NEW_LINE = "\r\n";

    private HTTPResponse getResponse() throws MalformedURLException, IOException {
        if (_response == null) {
            // Get the response from the remote service
            _response = urlFS.fetch(getRequest());
            // Rebuild stream of HTTP headers (except the HTTP status retrieved from readLine(String) method)
            StringBuilder buffer = new StringBuilder();
            for (HTTPHeader header : _response.getHeaders()) {
                buffer.append(header.getName()).append(SEPARATOR).append(header.getValue()).append(NEW_LINE);
            }
            buffer.append("Content-Length: ").append(_response.getContent().length).append(NEW_LINE);
            buffer.append(NEW_LINE);
            // Rebuild stream of HTTP content (chunked-encoded)
            buffer.append(Integer.toString(_response.getContent().length, 16)).append(";chunk size")
                    .append(NEW_LINE);
            buffer.append(new String(_response.getContent())).append(NEW_LINE);
            buffer.append("0;").append(NEW_LINE);
            _responseBody.resetActualContent(buffer.toString());
        }
        return _response;
    }

    /**
     * Default constructor
     * @param hostConfiguration
     */
    public UrlFetchHttpConnection(HostConfiguration hostConfiguration) {
        super(hostConfiguration);
        this.hostConfiguration = hostConfiguration;
    }

    @Override
    protected void assertNotOpen() throws IllegalStateException {
        throw new RuntimeException("assertNotOpen()");
    }

    @Override
    protected void assertOpen() throws IllegalStateException {
        assert (_response != null);
    }

    @Override
    public void close() {
        // Nothing to do!
    }

    @Override
    public boolean closeIfStale() throws IOException {
        // Safe call, passed to the inherited method
        return super.closeIfStale();
    }

    @Override
    protected void closeSocketAndStreams() {
        throw new RuntimeException("closeSocketAndStreams()");
    }

    @Override
    public void flushRequestOutputStream() throws IOException {
        getRequest().setPayload(_requestBody.getStream().toString().getBytes());
    }

    @Override
    public String getHost() {
        return hostConfiguration.getHost();
    }

    @Override
    public HttpConnectionManager getHttpConnectionManager() {
        throw new RuntimeException("getHttpConnectionManager()");
    }

    @Override
    public InputStream getLastResponseInputStream() {
        throw new RuntimeException("getLastResponseInputStream()");
    }

    @Override
    public InetAddress getLocalAddress() {
        throw new RuntimeException("getLocalAddress()");
    }

    @Override
    public HttpConnectionParams getParams() {
        return new HttpConnectionParams();
    }

    @Override
    public int getPort() {
        return hostConfiguration.getPort();
    }

    @Override
    public Protocol getProtocol() {
        return hostConfiguration.getProtocol();
    }

    @Override
    public String getProxyHost() {
        throw new RuntimeException("getProxyHost()");
    }

    @Override
    public int getProxyPort() {
        throw new RuntimeException("getProxyPort()");
    }

    @Override
    public OutputStream getRequestOutputStream() throws IOException, IllegalStateException {
        return _requestBody;
    }

    @Override
    public InputStream getResponseInputStream() throws IOException {
        return _responseBody;
    }

    @Override
    public int getSendBufferSize() throws SocketException {
        throw new RuntimeException("getSendBufferSize()");
    }

    @Override
    protected Socket getSocket() {
        throw new RuntimeException("getSocket()");
    }

    @Override
    public int getSoTimeout() throws SocketException {
        throw new RuntimeException("getSoTimeout()");
    }

    @Override
    public String getVirtualHost() {
        throw new RuntimeException("getVirtualHost()");
    }

    @Override
    protected boolean isLocked() {
        throw new RuntimeException("isLocked()");
    }

    @Override
    public boolean isOpen() {
        // Safe call, passed to inherited method
        return super.isOpen();
    }

    @Override
    public boolean isProxied() {
        // Safe call, passed to inherited method
        return super.isProxied();
    }

    @Override
    public boolean isResponseAvailable() throws IOException {
        return _response != null;
    }

    @Override
    public boolean isResponseAvailable(int timeout) throws IOException {
        return _response != null;
    }

    @Override
    public boolean isSecure() {
        return hostConfiguration.getPort() == 443;
    }

    @Override
    protected boolean isStale() throws IOException {
        throw new RuntimeException("isStale()");
    }

    @Override
    public boolean isStaleCheckingEnabled() {
        throw new RuntimeException("isStaleCheckingEnabled()");
    }

    @Override
    public boolean isTransparent() {
        // Safe call, passed to the inherited method
        return super.isTransparent();
    }

    @Override
    public void open() throws IOException {
        // Nothing to do
    }

    @Override
    public void print(String data, String charset) throws IOException, IllegalStateException {
        // Save the passed HTTP headers for the request
        int idx = data.indexOf(SEPARATOR);
        if (idx != -1) {
            String name = data.substring(0, idx);
            String value = data.substring(idx + SEPARATOR_LENGTH).trim();
            getRequest().addHeader(new HTTPHeader(name, value));
        }
        // Other information are just ignored safely 
    }

    @Override
    public void print(String data) throws IOException, IllegalStateException {
        throw new RuntimeException("print(string): " + data);
    }

    @Override
    public void printLine() throws IOException, IllegalStateException {
        throw new RuntimeException("printLine()");
    }

    @Override
    public void printLine(String data, String charset) throws IOException, IllegalStateException {
        throw new RuntimeException("printLine(string, String): " + data + " -- " + charset);
    }

    @Override
    public void printLine(String data) throws IOException, IllegalStateException {
        throw new RuntimeException("printLine(string): " + data);
    }

    @Override
    public String readLine() throws IOException, IllegalStateException {
        throw new RuntimeException("readLine()");
    }

    private boolean waitForHttpStatus = true;

    @Override
    public String readLine(String charset) throws IOException, IllegalStateException {
        if (waitForHttpStatus) {
            // Dom Derrien: called only once to get the HTTP status, other information being read from the response output stream
            int responseCode = getResponse().getResponseCode();
            String line = "HTTP/1.1 " + responseCode;
            switch (responseCode) {
            case HttpStatus.SC_OK:
                line += " OK";
                break;
            case HttpStatus.SC_BAD_REQUEST:
                line += " BAD REQUEST";
                break;
            case HttpStatus.SC_UNAUTHORIZED:
                line += " UNAUTHORIZED";
                break;
            case HttpStatus.SC_FORBIDDEN:
                line += " FORBIDDEN";
                break;
            case HttpStatus.SC_NOT_FOUND:
                line += " NOT FOUND";
                break;
            case HttpStatus.SC_INTERNAL_SERVER_ERROR:
                line += " INTERNAL SERVER ERROR";
                break;
            case HttpStatus.SC_SERVICE_UNAVAILABLE:
                line += " SERVICE UNAVAILABLE";
                break;
            default:
                line = "HTTP/1.1 " + HttpStatus.SC_BAD_REQUEST + " BAD REQUEST";
            }
            waitForHttpStatus = false;
            return line;
        }
        throw new RuntimeException("readLine(String)");
    }

    @Override
    public void releaseConnection() {
        // Do nothing, connection closed automatically...
    }

    @Override
    public void setConnectionTimeout(int timeout) {
        throw new RuntimeException("setConnectionTimeout(int)");
    }

    @Override
    public void setHost(String host) throws IllegalStateException {
        throw new RuntimeException("setHost(String");
    }

    @Override
    public void setHttpConnectionManager(HttpConnectionManager httpConnectionManager) {
        throw new RuntimeException("setHttpConnectionManager(HttpConnectionManager");
    }

    @Override
    public void setLastResponseInputStream(InputStream inStream) {
        // Safe call, passed to inherited method
        super.setLastResponseInputStream(inStream);
    }

    @Override
    public void setLocalAddress(InetAddress localAddress) {
        throw new RuntimeException("setLocalAddress(InetAddress)");
    }

    @Override
    protected void setLocked(boolean locked) {
        // Safe call, passed to inherited method
        super.setLocked(locked);
    }

    @Override
    public void setParams(HttpConnectionParams params) {
        throw new RuntimeException("setParams(HttpConnectionParams)");
    }

    @Override
    public void setPort(int port) throws IllegalStateException {
        throw new RuntimeException("setPort(int)");
    }

    @Override
    public void setProtocol(Protocol protocol) {
        throw new RuntimeException("setProtocol(Protocol)");
    }

    @Override
    public void setProxyHost(String host) throws IllegalStateException {
        throw new RuntimeException("setProxyHost(String)");
    }

    @Override
    public void setProxyPort(int port) throws IllegalStateException {
        throw new RuntimeException("setProxyPort(int)");
    }

    @Override
    public void setSendBufferSize(int sendBufferSize) throws SocketException {
        throw new RuntimeException("setSendBufferSize(int)");
    }

    @Override
    public void setSocketTimeout(int timeout) throws SocketException, IllegalStateException {
        // Safe call, passed to inherited method
        super.setSocketTimeout(timeout);
    }

    @Override
    public void setSoTimeout(int timeout) throws SocketException, IllegalStateException {
        throw new RuntimeException("setSoTimeout(int)");
    }

    @Override
    public void setStaleCheckingEnabled(boolean staleCheckEnabled) {
        throw new RuntimeException("setStaleCheckingEnabled(boolean)");
    }

    @Override
    public void setVirtualHost(String host) throws IllegalStateException {
        throw new RuntimeException("setVirtualHost(String)");
    }

    @Override
    public void shutdownOutput() {
        throw new RuntimeException("shutdownOutput()");
    }

    @Override
    public void tunnelCreated() throws IllegalStateException, IOException {
        throw new RuntimeException("tunnelCreated()");
    }

    @Override
    public void write(byte[] data, int offset, int length) throws IOException, IllegalStateException {
        throw new RuntimeException("write(byte[], int, int): " + new String(data) + ", " + offset + ", " + length);
    }

    @Override
    public void write(byte[] data) throws IOException, IllegalStateException {
        throw new RuntimeException("write(byte[]): " + new String(data));
    }

    @Override
    public void writeLine() throws IOException, IllegalStateException {
        // Safe call, new line being inserted automatically by the HTTPRequest renderer
    }

    @Override
    public void writeLine(byte[] data) throws IOException, IllegalStateException {
        throw new RuntimeException("writeLine(byte[]): " + new String(data));
    }
}