com.guster.skywebservice.library.webservice.SkyHttp.java Source code

Java tutorial

Introduction

Here is the source code for com.guster.skywebservice.library.webservice.SkyHttp.java

Source

/**
 * Copyright 2014 Gusterwoei
    
 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 com.guster.skywebservice.library.webservice;

import android.content.Context;
import android.graphics.Bitmap;
import android.os.AsyncTask;
import android.util.Log;
import android.webkit.URLUtil;

import com.guster.skywebservice.library.webservice.util.SkyHttpException;

import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.ByteArrayBody;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.InputStreamBody;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

/**
 * Created by Gusterwoei on 10/30/13.
 */
public class SkyHttp implements SkyHttpInterface {
    // global variables
    private static int CONNECTION_TIMEOUT = 30000;
    private static int SOCKET_TIMEOUT = 30000;
    private static List<HttpHeader> globalHeaders = new ArrayList<HttpHeader>();
    private static SSLSocketFactory sslSocketFactory;
    private static boolean trustAllCertificates = false;

    private Context context;

    public SkyHttp(Context context) {
        this.context = context.getApplicationContext();
    }

    protected Context getContext() {
        return context;
    }

    public static RequestBuilder newRequest() {
        RequestBuilder requestBuilder = new RequestBuilder();
        return requestBuilder;
    }

    public static void addGlobalHeader(String header, String value) {
        globalHeaders.add(new HttpHeader(header, value));
    }

    public static void setSocketTimeout(int duration) {
        CONNECTION_TIMEOUT = duration;
    }

    public static void setConnectionTimeout(int duration) {
        SOCKET_TIMEOUT = duration;
    }

    public static void setSSLSocketFactory(SSLSocketFactory factory) {
        sslSocketFactory = factory;
    }

    public static void setSSLCertificate(InputStream certificateFile) throws CertificateException, IOException,
            KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        Certificate cert = cf.generateCertificate(certificateFile);

        certificateFile.close();

        // create a keystore containing the certificate
        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
        keyStore.load(null, null);
        keyStore.setCertificateEntry("ca", cert);

        // create a trust manager for our certificate
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init(keyStore);

        // create a SSLContext that uses our trust manager
        SSLContext context = SSLContext.getInstance("TLS");
        context.init(null, tmf.getTrustManagers(), null);

        // set socket factory
        setSSLSocketFactory(context.getSocketFactory());
    }

    public static void trustAllCertificates(boolean yes) {
        trustAllCertificates = yes;
        if (yes) {
            TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }

                @Override
                public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
                    // Not implemented
                }

                @Override
                public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
                    // Not implemented
                }
            } };

            try {
                SSLContext sc = SSLContext.getInstance("TLS");
                sc.init(null, trustAllCerts, new java.security.SecureRandom());
                sslSocketFactory = sc.getSocketFactory();

            } catch (KeyManagementException e) {
                e.printStackTrace();
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
        }
    }

    /*****************************************************************************
     *
     * INNER CLASS --- RequestBuilder ---
     *
     *****************************************************************************/
    public static final class RequestBuilder implements RequestBuilderInterface {

        private static final String TAG = "SKYHTTP";

        // HTTP socket parameters
        private int connectionTimeout = CONNECTION_TIMEOUT;
        private int socketTimeout = SOCKET_TIMEOUT;
        private HttpAuthenticator httpAuthenticator;
        private SSLSocketFactory sslSocketFactory;
        private Callback callback;
        private List<HttpHeader> headers = new ArrayList<HttpHeader>(); // http headers
        private Executor asyncTaskExecutor = AsyncTask.SERIAL_EXECUTOR;
        private HttpURLConnection urlConnection;
        private String payload;
        private HttpEntity multiformEntity;
        private String urlEncodeCharset;

        public RequestBuilder() {
            init();
        }

        private void init() {
            for (HttpHeader header : globalHeaders) {
                addHeader(header.getName(), header.getValue());
            }
        }

        @Override
        public int getConnectionTimeout() {
            return connectionTimeout;
        }

        @Override
        public RequestBuilder setConnectionTimeout(int connectionTimeout) {
            this.connectionTimeout = connectionTimeout;
            return this;
        }

        @Override
        public int getSocketTimeout() {
            return socketTimeout;
        }

        @Override
        public RequestBuilder setSocketTimeout(int socketTimeout) {
            this.socketTimeout = socketTimeout;
            return this;
        }

        @Override
        public Callback getCallback() {
            return callback;
        }

        private void setRequest(HttpURLConnection urlConnection, String payload, HttpEntity multiformEntity) {
            this.urlConnection = urlConnection;
            this.payload = payload;
            this.multiformEntity = multiformEntity;

            // set ssl certificate, if any
            if (urlConnection != null && (urlConnection instanceof HttpsURLConnection)) {
                if (sslSocketFactory != null && !trustAllCertificates) {
                    ((HttpsURLConnection) this.urlConnection).setSSLSocketFactory(sslSocketFactory);
                } else if (SkyHttp.sslSocketFactory != null) {
                    ((HttpsURLConnection) this.urlConnection).setSSLSocketFactory(SkyHttp.sslSocketFactory);
                }
            }
        }

        @Override
        public RequestBuilder addHeader(String name, String value) {
            HttpHeader h = findHeader(name);
            if (h != null && h.getName().equals(name) && h.getValue().equals(value))
                return this;
            else {
                removeHeader(name);
                headers.add(new HttpHeader(name, value));
            }
            return this;
        }

        @Override
        public void removeHeader(String name) {
            int x = findHeaderIndex(name);
            if (x != -1) {
                headers.remove(x);
            }
        }

        @Override
        public HttpHeader findHeader(String name) {
            int x = findHeaderIndex(name);
            return (x != -1) ? headers.get(x) : null;
        }

        private int findHeaderIndex(String name) {
            int x = -1;
            for (int i = 0; i < headers.size(); i++) {
                HttpHeader header = headers.get(i);
                if (header.getName().equals(name)) {
                    x = i;
                    break;
                }
            }
            return x;
        }

        @Override
        public void removeAllHeaders() {
            headers.clear();
        }

        @Override
        public List<HttpHeader> getHeaders() {
            return headers;
        }

        /**
         * Set Authentication credentials
         *
         * @param username credential username
         * @param pwd     credential password
         * @return
         */
        @Override
        public RequestBuilder setAuthentication(String username, String pwd) {
            httpAuthenticator = new HttpAuthenticator();
            httpAuthenticator.setUsername(username);
            httpAuthenticator.setPassword(pwd);
            return this;
        }

        @Override
        public RequestBuilder setAsyncTaskExecutor(Executor asyncTaskExecutor) {
            this.asyncTaskExecutor = asyncTaskExecutor;
            return this;
        }

        @Override
        public RequestBuilder setSSLSocketFactory(SSLSocketFactory sslSocketFactory) {
            this.sslSocketFactory = sslSocketFactory;
            return this;
        }

        @Override
        public RequestBuilder setSSLCertificate(InputStream certificateFile) throws CertificateException,
                IOException, KeyStoreException, NoSuchAlgorithmException, KeyManagementException {

            SkyHttp.setSSLCertificate(certificateFile);

            return this;
        }

        /**
         * HTTP GET
         *
         * @param link
         * @return
         */
        @Override
        public RequestBuilder get(String link) {
            /*HttpGet get = new HttpGet(link);
            setRequest(get);*/

            return get(link, null);
        }

        @Override
        public RequestBuilder get(String link, Params params) {

            try {
                String paramStr = buildParams(params);

                URL url = new URL(link + paramStr);
                HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
                urlConnection.setRequestMethod("GET");
                urlConnection.setDoInput(true);
                setRequest(urlConnection, null, null);
            } catch (IOException e) {
                handleRequestSetupException("GET", e);
            }

            return this;
        }

        /**
         * HTTP POST
         *
         * @param link
         * @param payload a content payload, could be string, json, xml, etc
         * @return
         */
        @Override
        public RequestBuilder post(String link, String payload) {
            /*HttpPost post = new HttpPost(link);
            StringEntity entity;
            try {
            entity = new StringEntity(payload);
            post.setEntity(entity);
            } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            }
                
            setRequest(post);*/
            try {
                URL url = new URL(link);
                HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
                urlConnection.setRequestMethod("POST");
                urlConnection.setDoInput(true);
                urlConnection.setDoOutput(true);
                setRequest(urlConnection, payload, null);
            } catch (IOException e) {
                handleRequestSetupException("POST", e);
            }

            return this;
        }

        @Override
        public RequestBuilder post(String url, FormContent formContent) {
            uploadFileToServer(url, formContent);
            return this;
        }

        private RequestBuilder uploadFileToServer(String link, FormContent formContent) {
            String boundary = "-------------" + System.currentTimeMillis();
            String contentType = "multipart/form-data; boundary=" + boundary;

            MultipartEntityBuilder builder = MultipartEntityBuilder.create()
                    .setMode(HttpMultipartMode.BROWSER_COMPATIBLE).setBoundary(boundary);

            // get all contents
            HashMap<String, Object> map = formContent.getContent();
            HashMap<String, String> filenameMap = formContent.getMap();
            Iterator<Map.Entry<String, Object>> iterator = map.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry<String, Object> entry = iterator.next();
                String key = entry.getKey();
                Object value = entry.getValue();

                if (value instanceof String) {
                    builder.addTextBody(key, (String) value);

                } else if (value instanceof Bitmap) {
                    String filename = filenameMap.get(key);
                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
                    ((Bitmap) value).compress(Bitmap.CompressFormat.PNG, 0, baos);
                    builder.addPart(key, new ByteArrayBody(baos.toByteArray(), filename));

                } else if (value instanceof File) {
                    builder.addPart(key, new FileBody((File) value));

                } else if (value instanceof InputStream) {
                    String filename = filenameMap.get(key);
                    builder.addPart(key, new InputStreamBody((InputStream) value, filename));

                } else {
                    // byte array
                    String filename = filenameMap.get(key);
                    builder.addPart(key, new ByteArrayBody((byte[]) value, filename));
                }
            }

            HttpEntity entity = builder.build();

            /*HttpEntity entity = MultipartEntityBuilder.create()
                .setMode(HttpMultipartMode.BROWSER_COMPATIBLE)
                .setBoundary(boundary)
                .addPart(fileName, contentBody)
                .build();*/

            /*HttpPost post = new HttpPost(url);
            post.setHeader("Content-type", contentType);
            post.setEntity(entity);
            setRequest(post);*/

            try {
                URL url = new URL(link);
                HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
                urlConnection.setRequestMethod("POST");
                urlConnection.setDoInput(true);
                urlConnection.setDoOutput(true);
                //urlConnection.setRequestProperty("Connection", "Keep-Alive");
                //urlConnection.setRequestProperty("Content-type", contentType);
                addHeader("Connection", "Keep-Alive");
                addHeader("Content-Type", contentType);
                urlConnection.addRequestProperty(entity.getContentType().getName(),
                        entity.getContentType().getValue());

                setRequest(urlConnection, null, entity);

            } catch (IOException e) {
                handleRequestSetupException("UPLOAD", e);
            }

            return this;
        }

        /**
         * HTTP PUT
         *
         * @param link
         * @param payload a content payload, could be string, json, xml, etc
         * @return
         */
        @Override
        public RequestBuilder put(String link, String payload) {
            try {
                URL url = new URL(link);
                HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
                urlConnection.setRequestMethod("PUT");
                urlConnection.setDoInput(true);
                urlConnection.setDoOutput(true);
                setRequest(urlConnection, payload, null);
                return this;
            } catch (IOException e) {
                handleRequestSetupException("PUT", e);
            }

            return this;
        }

        /**
         * HTTP DELETE
         *
         * @param link
         * @return
         */
        @Override
        public RequestBuilder delete(String link) {
            try {
                URL url = new URL(link);
                HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
                urlConnection.setRequestMethod("DELETE");
                urlConnection.setDoInput(true);
                setRequest(urlConnection, null, null);
            } catch (IOException e) {
                handleRequestSetupException("DELETE", e);
            }

            return this;
        }

        /**
         * HTTP HEAD
         *
         * @param link
         * @return
         */
        @Override
        public RequestBuilder head(String link) {
            try {
                URL url = new URL(link);
                HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
                urlConnection.setRequestMethod("HEAD");
                urlConnection.setDoInput(true);
                setRequest(urlConnection, null, null);
            } catch (IOException e) {
                handleRequestSetupException("HEAD", e);
            }

            return this;
        }

        private void handleRequestSetupException(String tag, Exception e) {
            e.printStackTrace();
            Log.e(TAG, tag + ": " + e.getMessage());

            String error = e.getMessage() + ". Is your target url in valid format? Eg. http:// or https://";
            throw new SkyHttpException(error);
        }

        @Override
        public RequestBuilder encode() {
            urlEncodeCharset = "UTF-8";
            return this;
        }

        @Override
        public RequestBuilder encode(String charset) {
            urlEncodeCharset = charset;
            return this;
        }

        /**
         * Send Request to the server with callback
         */
        @Override
        public void send(Callback callback) {
            this.callback = callback;
            send();
        }

        /**
         * Send Request to the server
         */
        @Override
        public void send() {
            // Initializing parameters
            urlConnection.setConnectTimeout(connectionTimeout);
            urlConnection.setReadTimeout(socketTimeout);

            // check if there is any http authentication
            if (httpAuthenticator != null) {
                urlConnection.setRequestProperty("Authorization", httpAuthenticator.getPasswordAuthentication());
            }

            // add the user defined http headers accordingly
            for (HttpHeader h : headers) {
                urlConnection.setRequestProperty(h.getName(), h.getValue());
            }

            // send the request to server
            new AsyncTask<Void, Void, Response>() {
                @Override
                protected void onPreExecute() {
                    if (callback != null)
                        callback.onPrepare();
                }

                @Override
                protected Response doInBackground(Void... voids) {
                    Response response = null;
                    try {
                        response = send(urlConnection);
                        if (callback != null)
                            callback.onReceiveInBackground(response, (response != null && response.success()));
                    } catch (IOException e) {
                        e.printStackTrace();
                        Log.e(TAG, "do in background: " + e.getMessage());

                        // validate if the response is due to timeout
                        response = validateResponse(response);

                        // read error stream from remote server
                        InputStream is = new BufferedInputStream(urlConnection.getErrorStream());
                        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
                        String line;
                        StringBuffer sb = new StringBuffer();
                        try {
                            while ((line = reader.readLine()) != null) {
                                sb.append(line);
                            }
                        } catch (IOException e1) {
                            e1.printStackTrace();
                        }

                        response.setResponse(sb.toString());
                    }
                    return response;
                }

                @Override
                protected void onPostExecute(Response response) {
                    if (callback != null)
                        callback.onResponse(response, (response != null && response.success()));
                }
            }.executeOnExecutor(asyncTaskExecutor);

            // Initializing parameters
            /*HttpParams httpParams = new BasicHttpParams();
            HttpConnectionParams.setConnectionTimeout(httpParams, connectionTimeout);
            HttpConnectionParams.setSoTimeout(httpParams, socketTimeout);
            httpClient = new DefaultHttpClient(httpParams);
                
            // check if there is any http authentication
            if (httpAuthenticator != null) {
            request.setHeader("Authorization", httpAuthenticator.getPasswordAuthentication());
            }
                
            // add the user defined http headers accordingly
            for (HttpHeader h : headers) {
            request.addGlobalHeader(h.getName(), h.getValue());
            }*/
        }

        private Response send(HttpURLConnection urlConnection) throws IOException {
            // connect to the server
            urlConnection.connect();

            if (urlConnection.getDoOutput()) {
                DataOutputStream dos = new DataOutputStream(urlConnection.getOutputStream());

                if (payload != null) {
                    if (urlEncodeCharset == null)
                        dos.writeBytes(payload);
                    else
                        dos.writeBytes(URLEncoder.encode(payload, urlEncodeCharset));
                }

                if (multiformEntity != null) {
                    multiformEntity.writeTo(dos);
                }

                dos.flush();
                dos.close();
            }

            // variables to be put into Response
            InputStream rawInputStream = new BufferedInputStream(urlConnection.getInputStream());
            String contentEncoding = urlConnection.getContentEncoding();
            String contentType = urlConnection.getContentType();
            String response = "";

            // store as string if the response is not binary file
            if (contentType != null && isResponseStringParsable(contentType)) {
                InputStream stream = new BufferedInputStream(urlConnection.getInputStream());
                BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
                String line;
                StringBuilder stringBuilder = new StringBuilder();
                while ((line = reader.readLine()) != null) {
                    stringBuilder.append(line);
                }

                stream.close();
                response = stringBuilder.toString();
                /*try {
                StringBuilder stringBuilder = new StringBuilder();
                while ((line = reader.readLine()) != null) {
                    stringBuilder.append(line);
                }
                    
                stream.close();
                response = stringBuilder.toString();
                } catch (IOException e) {
                Log.e(TAG, "Response getResponse() Exception: " + e.getMessage());
                e.printStackTrace();
                }*/
            }

            // onPrepare the response
            Response responseObject = new Response();
            responseObject.setStatusCode(urlConnection.getResponseCode());
            responseObject.setStatusDesc(urlConnection.getResponseMessage());
            responseObject.setContentLength(urlConnection.getContentLength());
            responseObject.setRawResponse(rawInputStream);
            responseObject.setResponse(response);
            responseObject.setContentEncoding(contentEncoding);
            responseObject.setContentType(contentType);
            responseObject.setUrl(urlConnection.getURL().toString());
            responseObject.setHeaders(urlConnection.getHeaderFields());

            return responseObject;
        }
        /*private Response send(HttpRequestBase rq) throws IOException {
        HttpResponse httpResponse = httpClient.execute(rq);
        HttpEntity entity = httpResponse.getEntity();
        BufferedHttpEntity bufHttpEntity = new BufferedHttpEntity(entity);
        InputStream rawInputStream = bufHttpEntity.getContent();
            
        // variables to be put into Response
        int statusCode = httpResponse.getStatusLine().getStatusCode();
        String statusDesc = httpResponse.getStatusLine().getReasonPhrase();
        long contentLength = entity.getContentLength();
            
        // onPrepare the response
        Response responseObject = new Response();
        responseObject.setStatusCode(statusCode);
        responseObject.setStatusDesc(statusDesc);
        responseObject.setContentLength(contentLength);
        responseObject.setRawResponse(rawInputStream);
        responseObject.setContentEncoding(entity.getContentEncoding());
        responseObject.setContentType(entity.getContentType());
        responseObject.setUrl(rq.getURI().toString());
            
        return responseObject;
        }*/

        private String buildParams(Params params) throws UnsupportedEncodingException {
            String str = "";
            if (params != null && !params.getParams().isEmpty()) {
                str += "?";
                str += params.getEncodedParams(urlEncodeCharset);
            }

            return str;
        }

        private boolean isResponseStringParsable(String contentType) {
            return !contentType.matches("image/.*") && !contentType.matches("audio/.*")
                    && !contentType.matches("application/octet-stream") && !contentType.matches("application/pdf")
                    && !contentType.matches("application/ogg") && !contentType.matches("application/zip");
        }

        private Response validateResponse(Response response) {
            if (response == null) {
                response = new Response();
                response.setStatusCode(HttpStatus.SC_REQUEST_TIMEOUT);
            }

            return response;
        }
    }

    /*****************************************************************************
     *
     * INNER CLASS --- Callback ---
     *  callback function for the Http Client
     *
     * *****************************************************************************/
    public static abstract class Callback {
        public void onPrepare() {
        }

        public Object[] onReceiveInBackground(Response response, boolean success) {
            return null;
        }

        public abstract void onResponse(Response response, boolean success, Object... args);
    }
}