org.akita.io.HttpInvoker.java Source code

Java tutorial

Introduction

Here is the source code for org.akita.io.HttpInvoker.java

Source

/*
 * Copyright 1999-2101 Alibaba Group.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *      http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.akita.io;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.SystemClock;
import android.widget.ProgressBar;
import org.akita.exception.AkInvokeException;
import org.akita.exception.AkServerStatusException;
import org.akita.util.ImageUtil;
import org.akita.util.Log;
import org.apache.http.*;
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.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

/**
 * Http/Https Invoker
 * Get
 * Post(not idempotent) 
 * Put
 * Delete
 * Post With Files (URLConnection Impl)
 * @author zhe.yangz 2011-12-30 ?01:49:38
 */
public class HttpInvoker {
    private static String TAG = "HttpInvoker";
    private static String CHARSET = HTTP.UTF_8;

    private static ThreadSafeClientConnManager connectionManager;
    private static DefaultHttpClient client;

    static {
        init();
    }

    /**
     * init
     */
    private static void init() {

        SchemeRegistry schemeRegistry = new SchemeRegistry();
        schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
        schemeRegistry.register(new Scheme("https", _FakeSSLSocketFactory.getSocketFactory(), 443));

        HttpParams params = new BasicHttpParams();
        HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
        HttpProtocolParams.setContentCharset(params, "utf-8");
        HttpConnectionParams.setConnectionTimeout(params, 8000);
        HttpConnectionParams.setSoTimeout(params, 15000);
        params.setBooleanParameter("http.protocol.expect-continue", false);

        connectionManager = new ThreadSafeClientConnManager(params, schemeRegistry);
        client = new DefaultHttpClient(connectionManager, params);

        // enable gzip support in Request and Response. 
        client.addRequestInterceptor(new HttpRequestInterceptor() {
            public void process(final HttpRequest request, final HttpContext context)
                    throws HttpException, IOException {
                if (!request.containsHeader("Accept-Encoding")) {
                    request.addHeader("Accept-Encoding", "gzip");
                }
            }
        });
        client.addResponseInterceptor(new HttpResponseInterceptor() {
            public void process(final HttpResponse response, final HttpContext context)
                    throws HttpException, IOException {
                HttpEntity entity = response.getEntity();
                //Log.i("ContentLength", entity.getContentLength()+"");
                Header ceheader = entity.getContentEncoding();
                if (ceheader != null) {
                    HeaderElement[] codecs = ceheader.getElements();
                    for (int i = 0; i < codecs.length; i++) {
                        if (codecs[i].getName().equalsIgnoreCase("gzip")) {
                            response.setEntity(new GzipDecompressingEntity(response.getEntity()));
                            return;
                        }
                    }
                }
            }
        });

    }

    public static String get(String url) throws AkServerStatusException, AkInvokeException {
        return get(url, null);
    }

    public static String get(String url, Header[] headers) throws AkServerStatusException, AkInvokeException {
        Log.v(TAG, "get:" + url);
        String retString = null;
        try {
            HttpGet request = new HttpGet(url);
            if (headers != null) {
                for (Header header : headers) {
                    request.addHeader(header);
                }
            }
            HttpResponse response = client.execute(request);
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode == HttpStatus.SC_OK || statusCode == HttpStatus.SC_CREATED
                    || statusCode == HttpStatus.SC_ACCEPTED) {
                HttpEntity resEntity = response.getEntity();
                retString = (resEntity == null) ? null : EntityUtils.toString(resEntity, CHARSET);
            } else {
                HttpEntity resEntity = response.getEntity();
                throw new AkServerStatusException(response.getStatusLine().getStatusCode(),
                        EntityUtils.toString(resEntity, CHARSET));
            }
        } catch (ClientProtocolException cpe) {
            Log.e(TAG, cpe.toString(), cpe);
            throw new AkInvokeException(AkInvokeException.CODE_HTTP_PROTOCOL_ERROR, cpe.toString(), cpe);
        } catch (IOException ioe) {
            Log.e(TAG, ioe.toString(), ioe);
            throw new AkInvokeException(AkInvokeException.CODE_CONNECTION_ERROR, ioe.toString(), ioe);
        }

        Log.v(TAG, "response:" + retString);
        return retString;
    }

    public static String post(String url, ArrayList<NameValuePair> params)
            throws AkInvokeException, AkServerStatusException {
        return post(url, params, null);
    }

    public static String post(String url, ArrayList<NameValuePair> params, Header[] headers)
            throws AkInvokeException, AkServerStatusException {
        //==log start
        Log.v(TAG, "post:" + url);
        if (params != null) {
            Log.v(TAG, "params:=====================");
            for (NameValuePair nvp : params) {
                Log.v(TAG, nvp.getName() + "=" + nvp.getValue());
            }
            Log.v(TAG, "params end:=====================");
        }
        //==log end

        String retString = null;

        try {
            HttpPost request = new HttpPost(url);
            if (headers != null) {
                for (Header header : headers) {
                    request.addHeader(header);
                }
            }
            if (params == null) {
                Log.e(TAG, "Post Parameters Null Error");
                throw new AkInvokeException(AkInvokeException.CODE_POST_PARAM_NULL_ERROR,
                        "Post Parameters Null Error");
            }
            UrlEncodedFormEntity entity = new UrlEncodedFormEntity(params, CHARSET);
            request.setEntity(entity);
            HttpResponse response = client.execute(request);
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode == HttpStatus.SC_OK || statusCode == HttpStatus.SC_CREATED
                    || statusCode == HttpStatus.SC_ACCEPTED) {
                HttpEntity resEntity = response.getEntity();
                retString = (resEntity == null) ? null : EntityUtils.toString(resEntity, CHARSET);
            } else {
                HttpEntity resEntity = response.getEntity();
                throw new AkServerStatusException(response.getStatusLine().getStatusCode(),
                        EntityUtils.toString(resEntity, CHARSET));

            }
        } catch (UnsupportedEncodingException e) {
            Log.e(TAG, e.toString(), e);
            throw new AkInvokeException(AkInvokeException.CODE_HTTP_PROTOCOL_ERROR, e.toString(), e);
        } catch (ClientProtocolException e) {
            Log.e(TAG, e.toString(), e);
            throw new AkInvokeException(AkInvokeException.CODE_HTTP_PROTOCOL_ERROR, e.toString(), e);
        } catch (IOException e) {
            Log.e(TAG, e.toString(), e);
            throw new AkInvokeException(AkInvokeException.CODE_CONNECTION_ERROR, e.toString(), e);
        } catch (ParseException e) {
            Log.e(TAG, e.toString(), e);
            throw new AkInvokeException(AkInvokeException.CODE_PARSE_EXCEPTION, e.toString(), e);
        }

        Log.v(TAG, "response:" + retString);
        return retString;
    }

    public static String put(String url, HashMap<String, String> map) {
        return "";
    }

    public static String delete(String url) {
        return "";
    }

    private static final int DEFAULT_BUFFER_SIZE = 65536;

    private static byte[] retrieveImageData(InputStream inputStream, int fileSize, ProgressBar progressBar)
            throws IOException {

        // determine the remoteimageview size and allocate a buffer
        //Log.d(TAG, "fetching remoteimageview " + imgUrl + " (" +
        //        (fileSize <= 0 ? "size unknown" : Long.toString(fileSize)) + ")");
        BufferedInputStream istream = new BufferedInputStream(inputStream);

        try {
            if (fileSize <= 0) {
                Log.w(TAG, "Server did not set a Content-Length header, will default to buffer size of "
                        + DEFAULT_BUFFER_SIZE + " bytes");
                ByteArrayOutputStream buf = new ByteArrayOutputStream(DEFAULT_BUFFER_SIZE);
                byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
                int bytesRead = 0;
                while (bytesRead != -1) {
                    bytesRead = istream.read(buffer, 0, DEFAULT_BUFFER_SIZE);
                    if (bytesRead > 0)
                        buf.write(buffer, 0, bytesRead);
                }
                return buf.toByteArray();
            } else {
                byte[] imageData = new byte[fileSize];

                int bytesRead = 0;
                int offset = 0;
                while (bytesRead != -1 && offset < fileSize) {
                    bytesRead = istream.read(imageData, offset, fileSize - offset);
                    offset += bytesRead;
                    // process reporting
                    try {
                        if (progressBar != null) {
                            progressBar.setProgress(offset * 100 / fileSize);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                return imageData;
            }
        } finally {
            // clean up
            try {
                istream.close();
                inputStream.close();
            } catch (Exception ignore) {
            }
        }
    }

    private static final int NUM_RETRIES = 2;
    private static final int DEFAULT_RETRY_SLEEP_TIME = 1000;

    /**
     * Vversion 2 remoteimageview download impl, use byte[] to decode.
     * Note: Recommanded to use this method instead of version 1.
     * NUM_RETRIES retry.
     * @param imgUrl
     * @param httpReferer http Referer
     * @return
     * @throws AkServerStatusException
     * @throws AkInvokeException
     */
    public static Bitmap getBitmapFromUrl(String imgUrl, String httpReferer, ProgressBar progressBar)
            throws AkServerStatusException, AkInvokeException {
        imgUrl = imgUrl.trim();
        Log.v(TAG, "getBitmapFromUrl:" + imgUrl);

        int timesTried = 1;

        while (timesTried <= NUM_RETRIES) {
            timesTried++;
            try {
                if (progressBar != null) {
                    progressBar.setProgress(0);
                }
                HttpGet request = new HttpGet(imgUrl);
                if (httpReferer != null)
                    request.addHeader("Referer", httpReferer);
                HttpResponse response = client.execute(request);
                int statusCode = response.getStatusLine().getStatusCode();
                if (statusCode == HttpStatus.SC_OK || statusCode == HttpStatus.SC_CREATED
                        || statusCode == HttpStatus.SC_ACCEPTED) {
                    HttpEntity resEntity = response.getEntity();
                    InputStream inputStream = resEntity.getContent();

                    byte[] imgBytes = retrieveImageData(inputStream, (int) (resEntity.getContentLength()),
                            progressBar);
                    if (imgBytes == null) {
                        SystemClock.sleep(DEFAULT_RETRY_SLEEP_TIME);
                        continue;
                    }

                    Bitmap bm = null;
                    try {
                        bm = ImageUtil.decodeSampledBitmapFromByteArray(imgBytes, 0, imgBytes.length, 682, 682);
                    } catch (OutOfMemoryError ooe) {
                        Log.e(TAG, ooe.toString(), ooe);
                        return null; // if oom, no need to retry.
                    }
                    if (bm == null) {
                        SystemClock.sleep(DEFAULT_RETRY_SLEEP_TIME);
                        continue;
                    }
                    return bm;
                } else {
                    HttpEntity resEntity = response.getEntity();
                    throw new AkServerStatusException(response.getStatusLine().getStatusCode(),
                            EntityUtils.toString(resEntity, CHARSET));
                }
            } catch (ClientProtocolException cpe) {
                Log.e(TAG, cpe.toString(), cpe);
                throw new AkInvokeException(AkInvokeException.CODE_HTTP_PROTOCOL_ERROR, cpe.toString(), cpe);
            } catch (IOException ioe) {
                Log.e(TAG, ioe.toString(), ioe);
                throw new AkInvokeException(AkInvokeException.CODE_CONNECTION_ERROR, ioe.toString(), ioe);
            } catch (IllegalStateException ise) {
                Log.e(TAG, ise.toString(), ise);
                throw new AkInvokeException(AkInvokeException.CODE_TARGET_HOST_OR_URL_ERROR, ise.toString(), ise);
            } catch (IllegalArgumentException iae) {
                throw new AkInvokeException(AkInvokeException.CODE_TARGET_HOST_OR_URL_ERROR, iae.toString(), iae);
            } catch (Exception e) {
                throw new AkInvokeException(AkInvokeException.CODE_UNKOWN_ERROR, e.toString(), e);
            }

        }

        return null;
    }

    /**
     * version 1 remoteimageview download impl, use InputStream to decode.
     * @param imgUrl
     * @param inSampleSize
     * @return
     * @throws AkServerStatusException
     * @throws AkInvokeException
     */
    public static Bitmap getImageFromUrl(String imgUrl, int inSampleSize)
            throws AkServerStatusException, AkInvokeException {
        Log.v(TAG, "getImageFromUrl:" + imgUrl);
        Bitmap bitmap = null;
        for (int cnt = 0; cnt < NUM_RETRIES; cnt++) {
            try {
                HttpGet request = new HttpGet(imgUrl);
                HttpResponse response = client.execute(request);
                int statusCode = response.getStatusLine().getStatusCode();
                if (statusCode == HttpStatus.SC_OK || statusCode == HttpStatus.SC_CREATED
                        || statusCode == HttpStatus.SC_ACCEPTED) {
                    HttpEntity resEntity = response.getEntity();
                    try {
                        BitmapFactory.Options options = new BitmapFactory.Options();
                        if (inSampleSize > 0 && inSampleSize < 10) {
                            options.inSampleSize = inSampleSize;
                        } else {
                            options.inSampleSize = 0;
                        }
                        InputStream inputStream = resEntity.getContent();

                        // return BitmapFactory.decodeStream(inputStream);
                        // Bug on slow connections, fixed in future release.
                        bitmap = BitmapFactory.decodeStream(new FlushedInputStream(inputStream), null, options);
                    } catch (Exception e) {
                        e.printStackTrace(); //TODO no op
                        // no op
                    }
                    break;
                } else {
                    HttpEntity resEntity = response.getEntity();
                    throw new AkServerStatusException(response.getStatusLine().getStatusCode(),
                            EntityUtils.toString(resEntity, CHARSET));
                }
            } catch (ClientProtocolException cpe) {
                Log.e(TAG, cpe.toString(), cpe);
                throw new AkInvokeException(AkInvokeException.CODE_HTTP_PROTOCOL_ERROR, cpe.toString(), cpe);
            } catch (IOException ioe) {
                Log.e(TAG, ioe.toString(), ioe);
                throw new AkInvokeException(AkInvokeException.CODE_CONNECTION_ERROR, ioe.toString(), ioe);
            }
        }
        return bitmap;
    }

    /*
     * An InputStream that skips the exact number of bytes provided, unless it
     * reaches EOF.
     */
    private static class FlushedInputStream extends FilterInputStream {
        public FlushedInputStream(InputStream inputStream) {
            super(inputStream);
        }

        @Override
        public long skip(long n) throws IOException {
            long totalBytesSkipped = 0L;
            while (totalBytesSkipped < n) {
                long bytesSkipped = in.skip(n - totalBytesSkipped);
                if (bytesSkipped == 0L) {
                    int b = read();
                    if (b < 0) {
                        break; // we reached EOF
                    } else {
                        bytesSkipped = 1; // we read one byte
                    }
                }
                totalBytesSkipped += bytesSkipped;
            }
            return totalBytesSkipped;
        }
    }

    /**
     * post with files using URLConnection Impl
     * @param actionUrl URL to post
     * @param params params to post
     * @param files files to post, support multi-files
     * @return response in String format
     * @throws IOException
     */
    public static String postWithFilesUsingURLConnection(String actionUrl, ArrayList<NameValuePair> params,
            Map<String, File> files) throws AkInvokeException {
        try {
            Log.v(TAG, "post:" + actionUrl);
            if (params != null) {
                Log.v(TAG, "params:=====================");
                for (NameValuePair nvp : params) {
                    Log.v(TAG, nvp.getName() + "=" + nvp.getValue());
                }
                Log.v(TAG, "params end:=====================");
            }

            String BOUNDARY = java.util.UUID.randomUUID().toString();
            String PREFIX = "--", LINEND = "\r\n";
            String MULTIPART_FROM_DATA = "multipart/form-data";
            String CHARSET = "UTF-8";

            URL uri = new URL(actionUrl);
            HttpURLConnection conn = (HttpURLConnection) uri.openConnection();

            conn.setReadTimeout(60 * 1000);
            conn.setDoInput(true); // permit input
            conn.setDoOutput(true); // permit output
            conn.setUseCaches(false);
            conn.setRequestMethod("POST"); // Post Method
            conn.setRequestProperty("connection", "keep-alive");
            conn.setRequestProperty("Charsert", "UTF-8");
            conn.setRequestProperty("Content-Type", MULTIPART_FROM_DATA + ";boundary=" + BOUNDARY);

            // firstly string params to add
            StringBuilder sb = new StringBuilder();
            for (NameValuePair nameValuePair : params) {
                sb.append(PREFIX);
                sb.append(BOUNDARY);
                sb.append(LINEND);
                sb.append("Content-Disposition: form-data; name=\"" + nameValuePair.getName() + "\"" + LINEND);
                sb.append("Content-Type: text/plain; charset=" + CHARSET + LINEND);
                sb.append("Content-Transfer-Encoding: 8bit" + LINEND);
                sb.append(LINEND);
                sb.append(nameValuePair.getValue());
                sb.append(LINEND);
            }

            DataOutputStream outStream = new DataOutputStream(conn.getOutputStream());
            outStream.write(sb.toString().getBytes());
            // send files secondly
            if (files != null) {
                int num = 0;
                for (Map.Entry<String, File> file : files.entrySet()) {
                    num++;
                    if (file.getKey() == null || file.getValue() == null)
                        continue;
                    else {
                        if (!file.getValue().exists()) {
                            throw new AkInvokeException(AkInvokeException.CODE_FILE_NOT_FOUND,
                                    "The file to upload is not found.");
                        }
                    }
                    StringBuilder sb1 = new StringBuilder();
                    sb1.append(PREFIX);
                    sb1.append(BOUNDARY);
                    sb1.append(LINEND);
                    sb1.append("Content-Disposition: form-data; name=\"" + file.getKey() + "\"; filename=\""
                            + file.getKey() + "\"" + LINEND);
                    sb1.append("Content-Type: application/octet-stream; charset=" + CHARSET + LINEND);
                    sb1.append(LINEND);
                    outStream.write(sb1.toString().getBytes());

                    InputStream is = new FileInputStream(file.getValue());
                    byte[] buffer = new byte[1024];
                    int len = 0;
                    while ((len = is.read(buffer)) != -1) {
                        outStream.write(buffer, 0, len);
                    }

                    is.close();
                    outStream.write(LINEND.getBytes());
                }
            }

            // request end flag
            byte[] end_data = (PREFIX + BOUNDARY + PREFIX + LINEND).getBytes();
            outStream.write(end_data);
            outStream.flush();
            // get response code
            int res = conn.getResponseCode();
            InputStream in = conn.getInputStream();
            StringBuilder sb2 = new StringBuilder();
            if (res == 200) {
                BufferedReader reader = new BufferedReader(new InputStreamReader(in, "utf-8"), 8192);
                String line = null;
                while ((line = reader.readLine()) != null) {
                    sb2.append(line + "\n");
                }
                reader.close();
            }
            outStream.close();
            conn.disconnect();
            Log.v(TAG, "response:" + sb2.toString());
            return sb2.toString();
        } catch (IOException ioe) {
            throw new AkInvokeException(AkInvokeException.CODE_IO_EXCEPTION, "IO Exception", ioe);
        }
    }

}