free.yhc.netmbuddy.model.NetLoader.java Source code

Java tutorial

Introduction

Here is the source code for free.yhc.netmbuddy.model.NetLoader.java

Source

/******************************************************************************
 * Copyright (C) 2012, 2013, 2014
 * Younghyung Cho. <yhcting77@gmail.com>
 * All rights reserved.
 *
 * This file is part of NetMBuddy
 *
 * This program is licensed under the FreeBSD license
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * The views and conclusions contained in the software and documentation
 * are those of the authors and should not be interpreted as representing
 * official policies, either expressed or implied, of the FreeBSD Project.
 *****************************************************************************/

package free.yhc.netmbuddy.model;

import static free.yhc.netmbuddy.utils.Utils.eAssert;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.UnknownHostException;

import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.client.params.CookiePolicy;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;

import android.net.Uri;
import free.yhc.netmbuddy.utils.Utils;

public class NetLoader {
    private static final boolean DBG = false;
    private static final Utils.Logger P = new Utils.Logger(NetLoader.class);

    private boolean mUserClose = false;
    private HttpClient mHttpClient = null;

    public static enum Err {
        NO_ERR, IO_NET, HTTPGET, INTERRUPTED, UNKNOWN, // err inside module
    }

    public static class LocalException extends java.lang.Exception {
        static final long serialVersionUID = 0; // to make compiler be happy

        private final Err _mErr;
        private final Object _mExtra;

        public LocalException(Err err, Object extra) {
            _mErr = err;
            _mExtra = extra;
        }

        public LocalException(Err err) {
            this(err, null);
        }

        public Err error() {
            return _mErr;
        }

        public Object extra() {
            return _mExtra;
        }
    }

    public static class HttpRespContent {
        public int stcode; // status code
        public InputStream stream;
        public String type;

        HttpRespContent(int aStcode, InputStream aStream, String aType) {
            stcode = aStcode;
            stream = aStream;
            type = aType;
        }
    }

    private boolean isValidProxyAddr(String proxy) {
        return null != proxy && !proxy.isEmpty();
    }

    private HttpClient newHttpClient(String proxyAddr) {
        if (isValidProxyAddr(proxyAddr)) {
            // TODO
            // Not supported yet.
            eAssert(false);
            return null;
        }
        HttpClient hc = new DefaultHttpClient();
        HttpParams params = hc.getParams();
        HttpConnectionParams.setConnectionTimeout(params, Policy.NETWORK_CONN_TIMEOUT);
        HttpConnectionParams.setSoTimeout(params, Policy.NETWORK_CONN_TIMEOUT);
        HttpProtocolParams.setUserAgent(hc.getParams(), Policy.HTTP_UASTRING);
        params.setParameter(ClientPNames.COOKIE_POLICY, CookiePolicy.RFC_2109);
        return hc;
    }

    public NetLoader() {
    }

    public NetLoader open() {
        return open(null);
    }

    public NetLoader open(String proxy) {
        mUserClose = false;
        eAssert(null == mHttpClient);
        if (null == proxy)
            proxy = "";
        mHttpClient = newHttpClient(proxy);
        return this;
    }

    public void close() {
        mUserClose = true;
        // Kind of hack!
        // There is no fast-way to cancel running-java thread.
        // So, make input-stream closed by force to stop loading/DOM-parsing etc.
        if (null != mHttpClient)
            mHttpClient.getConnectionManager().shutdown();
        mHttpClient = null;
    }

    public void readHttpData(OutputStream outs, Uri uri) throws LocalException {
        eAssert(null != mHttpClient);
        // Proxy is not supported yet.
        HttpRespContent content = getHttpContent(uri, false);
        // 256K is experimental value small enough to contains most feed text.
        byte[] rbuf = new byte[256 * 1024];
        int bytes;
        try {
            while (-1 != (bytes = content.stream.read(rbuf)))
                outs.write(rbuf, 0, bytes);
            content.stream.close();
        } catch (IOException e) {
            throw new LocalException(Err.IO_NET);
        }
    }

    public HttpRespContent getHttpContent(Uri uri, boolean source) throws LocalException {
        if (null == mHttpClient) {
            if (DBG)
                P.v("NetLoader Fail to get HttpClient");
            throw new LocalException(Err.UNKNOWN);
        }

        if (!Utils.isNetworkAvailable())
            throw new LocalException(Err.IO_NET);

        String uriString = uri.toString();
        if (source)
            uriString = uriString.replace(uri.getScheme() + "://" + uri.getHost(), "");

        int retry = Policy.NETOWRK_CONN_RETRY;
        while (0 < retry--) {
            try {
                HttpGet httpGet = new HttpGet(uriString);
                HttpHost httpTarget = new HttpHost(uri.getHost());

                if (DBG)
                    P.v("executing request: " + httpGet.getRequestLine().toString());
                //logI("uri: " + httpGet.getURI().toString());
                //logI("target: " + httpTarget.getHostName());

                HttpResponse httpResp = mHttpClient.execute(httpTarget, httpGet);
                if (DBG)
                    P.v("NetLoader HTTP response status line : " + httpResp.getStatusLine().toString());

                // TODO
                // Need more case-handling-code.
                // Ex. Redirection etc.
                int statusCode = httpResp.getStatusLine().getStatusCode();
                switch (statusCode) {
                case HttpUtils.SC_OK:
                case HttpUtils.SC_NO_CONTENT:
                    ;// expected response. let's move forward
                    break;

                default:
                    // Unexpected response
                    if (DBG)
                        P.w("Unexpected Response  status code : " + httpResp.getStatusLine().getStatusCode());
                    throw new LocalException(Err.HTTPGET, statusCode);
                }

                InputStream contentStream = null;
                String contentType = null;
                if (HttpUtils.SC_NO_CONTENT == statusCode) {
                    ;
                } else {
                    HttpEntity httpEntity = httpResp.getEntity();

                    if (null == httpEntity) {
                        if (DBG)
                            P.w("Unexpected NULL entity");
                        throw new LocalException(Err.HTTPGET, statusCode);
                    }
                    contentStream = httpEntity.getContent();
                    try {
                        contentType = httpResp.getFirstHeader("Content-Type").getValue().toLowerCase();
                    } catch (NullPointerException e) {
                        // Unexpected response data.
                        if (DBG)
                            P.v("NetLoader IOException : " + e.getMessage());
                        throw new LocalException(Err.IO_NET);
                    }
                }

                return new HttpRespContent(statusCode, contentStream, contentType);
            } catch (ClientProtocolException e) {
                if (DBG)
                    P.v("NetLoader ClientProtocolException : " + e.getMessage());
                throw new LocalException(Err.UNKNOWN);
            } catch (IllegalArgumentException e) {
                if (DBG)
                    P.v("Illegal Argument Exception : " + e.getMessage() + "\n" + "URI : " + uriString);
                throw new LocalException(Err.IO_NET);
            } catch (UnknownHostException e) {
                if (DBG)
                    P.v("NetLoader UnknownHostException : Maybe timeout?" + e.getMessage());
                if (mUserClose)
                    throw new LocalException(Err.INTERRUPTED);

                if (0 >= retry)
                    throw new LocalException(Err.IO_NET);

                ; // continue next retry after some time.
                try {
                    Thread.sleep(300);
                } catch (InterruptedException ie) {
                    throw new LocalException(Err.INTERRUPTED);
                }
                throw new LocalException(Err.IO_NET);
            } catch (IOException e) {
                if (DBG)
                    P.v("NetLoader IOException : " + e.getMessage());
                throw new LocalException(Err.IO_NET);
            } catch (IllegalStateException e) {
                if (DBG)
                    P.v("NetLoader IllegalStateException : " + e.getMessage());
                throw new LocalException(Err.UNKNOWN);
            }
        }
        eAssert(false);
        return null;
    }
}