com.stepsdk.android.api.APIClient.java Source code

Java tutorial

Introduction

Here is the source code for com.stepsdk.android.api.APIClient.java

Source

/**
 * Copyright (c) 2012 Alvin S.J. Ng
 * 
 * Permission is hereby granted, free of charge, to any person obtaining 
 * a copy of this software and associated documentation files (the 
 * "Software"), to deal in the Software without restriction, including 
 * without limitation the rights to use, copy, modify, merge, publish, 
 * distribute, sublicense, and/or sell copies of the Software, and to 
 * permit persons to whom the Software is furnished to do so, subject 
 * to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be 
 * included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT 
 * WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR 
 * PURPOSE AND NONINFRINGEMENT. IN NO EVENT 
 * SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR 
 * IN CONNECTION WITH THE SOFTWARE OR 
 * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 * 
 * @author       Alvin S.J. Ng <alvinsj.ng@gmail.com>
 * @copyright   2012   Alvin S.J. Ng
 * 
 */
package com.stepsdk.android.api;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
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.conn.ClientConnectionManager;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.ContentBody;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.InputStreamBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.DefaultRedirectHandler;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;

import android.content.Context;
import android.net.Uri;
import android.os.AsyncTask;
import android.util.Log;
import android.webkit.MimeTypeMap;
import android.webkit.WebView;

import com.stepsdk.android.api.data.APIDataRequestHandler;
import com.stepsdk.android.api.data.DownloadFileTask;
import com.stepsdk.android.api.strategy.CacheStrategy;
import com.stepsdk.android.cache.CacheStore;
import com.stepsdk.android.cache.api.CachableHttpEntity;
import com.stepsdk.android.http.CountingMultipartEntity;
import com.stepsdk.android.http.CountingMultipartEntity.ProgressListener;
import com.stepsdk.android.util.DeviceUtil;
import com.stepsdk.android.util.FileUtil;
import com.stepsdk.android.util.NetworkUtil;
import com.stepsdk.android.util.NetworkUtil.NetworkDownException;

public class APIClient {
    public static final String TAG = "APIManager";

    public static final int NO_ERROR = 0;

    public static final int FAIL_LOGIN = 1;

    public static final int INTERNET_ERROR = 2;

    public static final int RESPONSE_ERROR = 3;

    public static final int DATA_ERROR = 4;

    public static final int REQUEST_ERROR = 5;

    public static final int HTTP_POST_ERROR = 6;

    private Context mContext = null;

    private DefaultHttpClient mHttpclient;

    public static String WEB_USER_AGENT;

    public APIClient(Context context, CacheStore cacheStore) {
        initWithContext(context);
        mCacheStore = cacheStore;
    }

    public CacheStore cacheStore() {
        return mCacheStore;
    }

    public APIClient(Context context) {
        initWithContext(context);
    }

    private void initWithContext(Context context) {
        mContext = context;
    }

    public Context getContext() {
        return mContext;
    }

    public void cachedGet(CacheStrategy strategy, String address, final Map<String, String> headerParams,
            APIRequestHandler handler) {
        strategy.getRequest(this, address, headerParams, handler);
    }

    public void cachedPost(CacheStrategy strategy, String address, Map<String, String> params,
            APIRequestHandler handler) {
        strategy.postRequest(this, address, params, handler);
    }

    public void get(final String address, final Map<String, String> headerParams, final APIRequestHandler handler) {
        log(TAG, "GET: " + address);
        new AsyncTask<Void, Void, Void>() {
            private boolean mInterrupt = false;

            @Override
            protected void onPreExecute() {
                log(TAG, "starting request for " + address);
                handler.before();
            };

            @Override
            protected Void doInBackground(Void... params) {
                Integer retryRemaining = 3;

                while (retryRemaining > 0) {
                    try {
                        if (!NetworkUtil.isOnline(mContext)) {
                            handler.onException(new NetworkDownException());
                            return null;
                        }

                        log(TAG, "processing request for " + address);
                        HttpEntity response = getRequest(address, headerParams);
                        handler.onResponse(response);
                        break;
                    } catch (ClientProtocolException e) {
                        if (--retryRemaining == 0) {
                            handler.onException(e);
                        }
                    } catch (IOException e) {
                        if (--retryRemaining == 0) {
                            handler.onException(e);
                        }
                    } catch (NetworkDownException e) {
                        if (--retryRemaining == 0) {
                            handler.onException(e);
                        }
                    } catch (HttpGetException e) {
                        if (--retryRemaining == 0) {
                            handler.onException(e);
                        }
                    } catch (Exception e) {
                        if (--retryRemaining == 0) {
                            handler.onException(e);
                            e.printStackTrace();
                        }
                    }
                }

                return null;
            };

            @Override
            protected void onPostExecute(Void result) {
                log(TAG, "Completed request for " + address);
                if (!mInterrupt)
                    handler.after();
            };

        }.execute();
    }

    public void post(final String address, final Map<String, String> params, final APIRequestHandler handler) {
        post(address, params, null, handler);
    }

    public void post(final String address, final Map<String, String> params, final Map<String, String> files,
            final APIRequestHandler handler) {
        log(TAG, "POST: " + address + "(" + params.toString() + ")");

        new AsyncTask<Void, Void, Void>() {

            private boolean mInterrupt = false;

            @Override
            protected void onPreExecute() {
                handler.before();
            };

            @Override
            protected Void doInBackground(Void... nothing) {
                Integer retryRemaining = 3;

                while (retryRemaining > 0) {
                    try {
                        if (!NetworkUtil.isOnline(mContext)) {
                            handler.onException(new NetworkDownException());
                            return null;
                        }

                        HttpEntity response = null;
                        if (files == null || files.size() == 0)
                            response = postRequest(address, params);
                        else
                            response = postRequest(address, params, files);
                        handler.onResponse(response);
                        break;
                    } catch (ClientProtocolException e) {
                        if (retryRemaining-- < 0) {
                            handler.onException(e);
                        }
                    } catch (IOException e) {
                        if (retryRemaining-- < 0) {
                            handler.onException(e);
                        }
                    } catch (NetworkDownException e) {
                        if (retryRemaining-- < 0) {
                            handler.onException(e);
                        }
                    } catch (HttpGetException e) {
                        if (retryRemaining-- < 0) {
                            handler.onException(e);
                        }
                    } catch (Exception e) {
                        if (retryRemaining-- < 0) {
                            handler.onException(e);
                        }
                    }
                }

                return null;
            };

            @Override
            protected void onPostExecute(Void result) {
                if (!mInterrupt)
                    handler.after();
            };

        }.execute();
    }

    private CacheStore mCacheStore;

    protected CacheStore defaultCacheStore() throws Exception {
        if (mCacheStore == null)
            return new CacheStore(getContext()) {

                @Override
                public String storeName() {
                    return "APIClient";
                }
            };
        else
            return mCacheStore;
    }

    public static class CacheStoreNotSetException extends Exception {
        private static final long serialVersionUID = 0;

        public CacheStoreNotSetException(String message) {
            super(message);
        }
    }

    public void download(final String address, final String cacheFileId, final APIDataRequestHandler handler,
            final File folder) {

        new DownloadFileTask(mContext, address, cacheFileId) {
            public File defaultCacheFolder(Context context) {
                return folder;
            };

            @Override
            protected void onPreExecute() {
                super.onPreExecute();
                handler.before();
            };

            @Override
            protected Boolean doInBackground(Void... nothing) {
                boolean result = super.doInBackground(nothing);
                if (result)
                    handler.onResponse(getData());
                return result;

            };

            @Override
            protected void onPostExecute(Boolean result) {
                super.onPostExecute(result);
                handler.after();
            };

            @Override
            protected void onProgressUpdate(Integer[] changed) {

                handler.onProgressUpdate(changed[0]);
            };

        }.execute();
    }

    public void cancelRequest() {
        if (mHttpclient != null)
            mHttpclient.getConnectionManager().shutdown();
    }

    public HttpEntity getRequest(String url, Map<String, String> headerParams)
            throws NetworkDownException, HttpGetException {
        HttpEntity response = httpGet(url, headerParams);
        return response;
    }

    public HttpEntity postRequest(String url, Map<String, String> params)
            throws NetworkDownException, HttpGetException, UnsupportedEncodingException, HttpPostException {
        List<BasicNameValuePair> nameValuePairs = new ArrayList<BasicNameValuePair>(2);

        Iterator<Entry<String, String>> i = params.entrySet().iterator();
        while (i.hasNext()) {
            Entry<String, String> next = i.next();
            nameValuePairs.add(new BasicNameValuePair(next.getKey(), next.getValue()));
        }

        UrlEncodedFormEntity postEnt = new UrlEncodedFormEntity(nameValuePairs);

        HttpEntity response = httpPost(url, postEnt);
        return response;
    }

    public HttpEntity postRequest(String url, Map<String, String> params, Map<String, String> files)
            throws NetworkDownException, HttpGetException, HttpPostException, IOException {

        MultipartEntity mpEntity = new CountingMultipartEntity(new ProgressListener() {
            private int prevPercentage = 0;

            @Override
            public void transferred(long num) {
                int percentage = (int) num;
                if (percentage > prevPercentage) {
                    prevPercentage = percentage;
                }
            }
        });

        Iterator<Entry<String, String>> i = params.entrySet().iterator();
        while (i.hasNext()) {
            Entry<String, String> next = i.next();
            mpEntity.addPart(next.getKey(), new StringBody(next.getValue()));
        }

        i = files.entrySet().iterator();
        while (i.hasNext()) {
            Entry<String, String> next = i.next();
            mpEntity = addFile(mpEntity, next.getKey(), next.getValue());
        }

        HttpEntity response = httpPost(url, mpEntity);
        return response;
    }

    public HttpEntity httpGet(String url, Map<String, String> headerParams)
            throws NetworkDownException, HttpGetException {
        HttpEntity entity = null;

        mHttpclient = new DefaultHttpClient();

        ClientConnectionManager mgr = mHttpclient.getConnectionManager();
        HttpParams params = mHttpclient.getParams();
        if (WEB_USER_AGENT != null)
            params.setParameter(CoreProtocolPNames.USER_AGENT, WEB_USER_AGENT);
        int timeoutConnection = 3000;
        HttpConnectionParams.setConnectionTimeout(params, timeoutConnection);
        int timeoutSocket = 5000;
        HttpConnectionParams.setSoTimeout(params, timeoutSocket);
        mHttpclient = new DefaultHttpClient(new ThreadSafeClientConnManager(params, mgr.getSchemeRegistry()),
                params);

        // Allow redirection from server
        // ref: http://stackoverflow.com/questions/3658721/httpclient-4-error-302-how-to-redirect
        mHttpclient.setRedirectHandler(new DefaultRedirectHandler() {
            @Override
            public boolean isRedirectRequested(HttpResponse response, HttpContext context) {
                boolean isRedirect = super.isRedirectRequested(response, context);
                if (!isRedirect) {
                    int responseCode = response.getStatusLine().getStatusCode();
                    if (responseCode == 302) {
                        return true;
                    }
                }
                return isRedirect;
            }
        });

        HttpGet get = new HttpGet(url);

        if (headerParams == null) {
            headerParams = new HashMap<String, String>();
        }

        Iterator<String> i = headerParams.keySet().iterator();

        while (i.hasNext()) {
            String key = i.next();
            get.addHeader(key, headerParams.get(key));
        }

        Integer retryRemaining = 3;

        while (entity == null) {
            try {

                if (!DeviceUtil.checkPermission(mContext, "android.permission.ACCESS_NETWORK_STATE"))
                    throw new NetworkDownException(
                            "ACCESS_NETWORK_STATE permission not set in AndroidManifest.xml");

                if (!DeviceUtil.checkPermission(mContext, "android.permission.INTERNET"))
                    throw new NetworkDownException("INTERNET permission not set in AndroidManifest.xml");

                if (!NetworkUtil.isOnline(mContext))
                    throw new NetworkDownException();

                HttpResponse response = mHttpclient.execute(get);
                if (response.getStatusLine().getStatusCode() == 404)
                    throw new HttpGetException("404");
                entity = response.getEntity();
            } catch (ClientProtocolException e) {
                if (retryRemaining-- != 0) {
                    entity = null;
                } else {
                    throw new HttpGetException(e.getMessage());
                }
            } catch (IOException e) {
                if (retryRemaining-- != 0) {
                    entity = null;
                } else {
                    throw new HttpGetException(e.getMessage());
                }
            }
        }

        return entity;
    }

    public static class HttpGetException extends Exception {
        private static final long serialVersionUID = 1L;

        public HttpGetException(String msg) {
            super(msg);
        }
    }

    public HttpEntity httpPost(String url, UrlEncodedFormEntity ent)
            throws NetworkDownException, HttpPostException {
        mHttpclient = new DefaultHttpClient();

        ClientConnectionManager mgr = mHttpclient.getConnectionManager();
        HttpParams params = mHttpclient.getParams();
        if (WEB_USER_AGENT != null)
            params.setParameter(CoreProtocolPNames.USER_AGENT, WEB_USER_AGENT);
        mHttpclient = new DefaultHttpClient(new ThreadSafeClientConnManager(params, mgr.getSchemeRegistry()),
                params);

        HttpPost post = new HttpPost(url);

        if (ent != null)
            post.setEntity(ent);

        try {
            if (!NetworkUtil.isOnline(mContext))
                throw new NetworkDownException();

            HttpResponse response = mHttpclient.execute(post);
            return response.getEntity();

        } catch (ClientProtocolException e) {
            throw new HttpPostException(e.getMessage());
        } catch (IOException e) {
            throw new HttpPostException(e.getMessage());
        }
    }

    private HttpEntity httpPost(String url, MultipartEntity mpEntity)
            throws NetworkDownException, HttpPostException {
        mHttpclient = new DefaultHttpClient();

        ClientConnectionManager mgr = mHttpclient.getConnectionManager();
        HttpParams params = mHttpclient.getParams();
        if (WEB_USER_AGENT != null)
            params.setParameter(CoreProtocolPNames.USER_AGENT, WEB_USER_AGENT);
        int timeoutConnection = 3000;
        HttpConnectionParams.setConnectionTimeout(params, timeoutConnection);
        int timeoutSocket = 5000;
        HttpConnectionParams.setSoTimeout(params, timeoutSocket);
        mHttpclient = new DefaultHttpClient(new ThreadSafeClientConnManager(params, mgr.getSchemeRegistry()),
                params);

        HttpPost httppost = new HttpPost(url);
        httppost.setEntity(mpEntity);

        try {
            if (!NetworkUtil.isOnline(mContext))
                throw new NetworkDownException();
            log(TAG, "executing request " + httppost.getRequestLine());
            HttpResponse response = mHttpclient.execute(httppost);
            log(TAG, response.getStatusLine().toString());
            HttpEntity result = response.getEntity();
            if (response != null) {
                log(TAG, EntityUtils.toString(result));
                result.consumeContent();
            }
            mHttpclient.getConnectionManager().shutdown();
            return result;

        } catch (ClientProtocolException e) {
            mHttpclient.getConnectionManager().shutdown();

            throw new HttpPostException(e.getMessage());

        } catch (IOException e) {
            mHttpclient.getConnectionManager().shutdown();
            throw new HttpPostException(e.getMessage());

        }
    }

    private MultipartEntity addFile(MultipartEntity mpEntity, String key, String fromPath) throws IOException {

        String filepath;
        try {
            filepath = URLDecoder.decode(fromPath, "UTF-8"); // handle special character
        } catch (Exception e) {
            filepath = fromPath;
        }
        String fromFilename = filepath.substring(filepath.lastIndexOf("/") + 1);

        String filename = "";
        long filesize = 0;
        ContentBody cbFile = null;

        log(TAG, "from upload path: " + fromPath);

        // upload from content uri
        if (fromPath.indexOf("content://") > -1) {
            Uri uri = Uri.parse(fromPath);
            String mime = mContext.getContentResolver().getType(uri);
            String extension = MimeTypeMap.getSingleton().getExtensionFromMimeType(mime);
            String mediatype = mime.substring(0, mime.indexOf('/'));

            InputStream is = mContext.getContentResolver().openInputStream(uri);
            filesize = is.available();
            filename = mediatype + fromFilename + "." + extension;
            cbFile = new InputStreamBody(is, mime, filename);

        } else { //upload from file uri
            File file = new File(filepath);

            filesize = file.length();
            filename = fromFilename;
            cbFile = new FileBody(file, FileUtil.getMimeTypeFromFilePath(fromPath));
        }

        //final String finalfilename = filename;
        final long finalfilesize = filesize;
        //final int task_id = params[1].getIntExtra("cancel_task_id", 0);
        //final Intent cancelintent = params[1];
        //final Intent doneintent = params[2];

        mpEntity.addPart(key, cbFile);

        return mpEntity;
    }

    public static class HttpPostException extends Exception {
        private static final long serialVersionUID = 1L;

        public HttpPostException(String msg) {
            super(msg);
        }
    }

    public void log(String where, String message) {
    }

}