microsoft.aspnet.signalr.client.http.android.AndroidHttpConnection.java Source code

Java tutorial

Introduction

Here is the source code for microsoft.aspnet.signalr.client.http.android.AndroidHttpConnection.java

Source

/*
Copyright (c) Microsoft Open Technologies, Inc.
All Rights Reserved
See License.txt in the project root for license information.
*/

package microsoft.aspnet.signalr.client.http.android;

import android.annotation.SuppressLint;
import android.net.http.AndroidHttpClient;
import android.os.AsyncTask;
import android.os.Build;

import org.apache.http.Header;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.entity.StringEntity;
import org.apache.http.message.BasicHttpEntityEnclosingRequest;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.SocketTimeoutException;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import microsoft.aspnet.signalr.client.*;
import microsoft.aspnet.signalr.client.http.*;
import microsoft.aspnet.signalr.client.http.HttpConnectionFuture.ResponseCallback;

/**
 * Android HttpConnection implementation, based on AndroidHttpClient and
 * AsyncTask for async operations
 */
public class AndroidHttpConnection implements HttpConnection {
    private Logger mLogger;

    /**
     * Initializes the AndroidHttpConnection
     * 
     * @param logger
     *            logger to log activity
     */
    public AndroidHttpConnection(Logger logger) {
        if (logger == null) {
            throw new IllegalArgumentException("logger");
        }

        mLogger = logger;
    }

    @Override
    public HttpConnectionFuture execute(final Request request, final ResponseCallback responseCallback) {

        mLogger.log("Create new AsyncTask for HTTP Connection", LogLevel.Verbose);

        final HttpConnectionFuture future = new HttpConnectionFuture();

        final RequestTask requestTask = new RequestTask() {

            AndroidHttpClient mClient;
            InputStream mResponseStream;

            @Override
            protected Void doInBackground(Void... voids) {
                if (request == null) {
                    future.triggerError(new IllegalArgumentException("request"));
                }

                mClient = AndroidHttpClient.newInstance(Platform.getUserAgent());
                mResponseStream = null;
                URI uri;

                try {
                    mLogger.log("Create an Android-specific request", LogLevel.Verbose);
                    request.log(mLogger);
                    HttpRequest realRequest = createRealRequest(request);
                    uri = new URI(request.getUrl());

                    HttpHost host = new HttpHost(uri.getHost(), uri.getPort(), uri.getScheme());

                    mLogger.log("Execute the HTTP Request", LogLevel.Verbose);
                    HttpResponse response;

                    try {
                        response = mClient.execute(host, realRequest);
                    } catch (SocketTimeoutException timeoutException) {
                        closeStreamAndClient();
                        mLogger.log("Timeout executing request: " + timeoutException.getMessage(),
                                LogLevel.Information);

                        future.triggerTimeout(timeoutException);

                        return null;
                    }

                    mLogger.log("Request executed", LogLevel.Verbose);

                    mResponseStream = response.getEntity().getContent();
                    Header[] headers = response.getAllHeaders();
                    Map<String, List<String>> headersMap = new HashMap<String, List<String>>();
                    for (Header header : headers) {
                        String headerName = header.getName();
                        if (headersMap.containsKey(headerName)) {
                            headersMap.get(headerName).add(header.getValue());
                        } else {
                            List<String> headerValues = new ArrayList<String>();
                            headerValues.add(header.getValue());
                            headersMap.put(headerName, headerValues);
                        }
                    }

                    responseCallback.onResponse(new StreamResponse(mResponseStream,
                            response.getStatusLine().getStatusCode(), headersMap));
                    future.setResult(null);
                    closeStreamAndClient();
                } catch (Exception e) {
                    closeStreamAndClient();
                    mLogger.log("Error executing request: " + e.getMessage(), LogLevel.Critical);

                    future.triggerError(e);
                }

                return null;
            }

            protected void closeStreamAndClient() {
                if (mResponseStream != null) {
                    try {
                        mResponseStream.close();
                    } catch (IOException e) {
                    }
                }

                if (mClient != null) {
                    mClient.close();
                }
            }
        };

        future.onCancelled(new Runnable() {

            @Override
            public void run() {
                AsyncTask<Void, Void, Void> cancelTask = new AsyncTask<Void, Void, Void>() {
                    @Override
                    protected Void doInBackground(Void... params) {
                        requestTask.closeStreamAndClient();
                        return null;
                    }
                };

                executeTask(cancelTask);
            }
        });

        executeTask(requestTask);

        return future;
    }

    @SuppressLint("NewApi")
    private void executeTask(AsyncTask<Void, Void, Void> task) {
        // If it's running with Honeycomb or greater, it must execute each
        // request in a different thread
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
        } else {
            task.execute();
        }
    }

    /**
     * Internal class to represent an async operation that can close a stream
     */
    private abstract class RequestTask extends AsyncTask<Void, Void, Void> {

        /**
         * Closes the internal stream and http client, if they exist
         */
        abstract protected void closeStreamAndClient();
    }

    /**
     * Creates a request that can be accepted by the AndroidHttpClient
     * 
     * @param request
     *            The request information
     * @throws java.io.UnsupportedEncodingException
     */
    private static BasicHttpEntityEnclosingRequest createRealRequest(Request request)
            throws UnsupportedEncodingException {
        BasicHttpEntityEnclosingRequest realRequest = new BasicHttpEntityEnclosingRequest(request.getVerb(),
                request.getUrl());

        if (request.getContent() != null) {
            realRequest.setEntity(new StringEntity(request.getContent()));
        }

        Map<String, String> headers = request.getHeaders();

        for (String key : headers.keySet()) {
            realRequest.addHeader(key, headers.get(key));
        }

        return realRequest;
    }
}