com.alphabetbloc.accessmrs.utilities.NetworkUtils.java Source code

Java tutorial

Introduction

Here is the source code for com.alphabetbloc.accessmrs.utilities.NetworkUtils.java

Source

/*
 * Copyright (c) 2012 Louis Fazen
 * 
 * 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.alphabetbloc.accessmrs.utilities;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.params.HttpClientParams;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.params.ConnManagerParams;
import org.apache.http.conn.params.ConnPerRoute;
import org.apache.http.conn.params.ConnPerRouteBean;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.scheme.SocketFactory;
import org.apache.http.conn.ssl.BrowserCompatHostnameVerifier;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.entity.AbstractHttpEntity;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.FileBody;
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 android.accounts.Account;
import android.accounts.AccountManager;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.util.Log;

import com.alphabetbloc.accessmrs.R;

/**
 * 
 * @author Louis Fazen (louis.fazen@gmail.com)
 * 
 */
public class NetworkUtils {
    public static final String TAG = NetworkUtils.class.getSimpleName();
    // POST
    public static final String INSTANCE_UPLOAD_URL = "/moduleServlet/xformshelper/xfhFormUpload";

    // SECURE GET
    public static final String PATIENT_DOWNLOAD_URL = "/module/odkconnector/download/patients.form";

    // INSECURE GET
    public static final String FORMLIST_DOWNLOAD_URL = "/moduleServlet/xformshelper/xfhFormList?type=odk_clinic&program=";
    public static final String FORM_DOWNLOAD_URL = "/moduleServlet/xformshelper/xfhFormDownload?type=odk_clinic";

    private static final int CONNECTION_TIMEOUT = 60000;
    private static final int MAX_CONN_PER_ROUTE = 20;
    private static final int MAX_CONNECTIONS = 20;

    private static String mUsername;
    private static String mPassword;

    private static String getServerUrl() {
        SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(App.getApp());
        return settings.getString(App.getApp().getString(R.string.key_server),
                App.getApp().getString(R.string.default_server));
    }

    public static String getFormUploadUrl() {
        StringBuilder uploadUrl = new StringBuilder();
        uploadUrl.append(getServerUrl()).append(INSTANCE_UPLOAD_URL);
        uploadUrl.append("?uname=").append(getServerUsername());
        uploadUrl.append("&pw=").append(getServerPassword());
        return uploadUrl.toString();
    }

    public static String getPatientDownloadUrl() {
        StringBuilder patientUrl = new StringBuilder();
        patientUrl.append(getServerUrl()).append(PATIENT_DOWNLOAD_URL);
        return patientUrl.toString();
    }

    public static String getFormListDownloadUrl() {
        StringBuilder formlistUrl = new StringBuilder();
        formlistUrl.append(getServerUrl()).append(FORMLIST_DOWNLOAD_URL);
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(App.getApp());
        String program = prefs.getString(App.getApp().getString(R.string.key_program),
                App.getApp().getString(R.string.default_program));
        formlistUrl.append(program);
        return formlistUrl.toString();
    }

    public static String getFormDownloadUrl() {
        StringBuilder formUrl = new StringBuilder();
        formUrl.append(getServerUrl()).append(FORM_DOWNLOAD_URL);
        return formUrl.toString();
    }

    public static String getServerUsername() {
        if (mUsername == null)
            getServerCredentials();
        return mUsername;
    }

    public static String getServerPassword() {
        if (mPassword == null)
            getServerCredentials();
        return mPassword;
    }

    public static void resetServerCredentials() {
        mUsername = null;
        mPassword = null;
    }

    private static void getServerCredentials() {
        final AccountManager am = AccountManager.get(App.getApp());
        Account[] accounts = am.getAccountsByType(App.getApp().getString(R.string.app_account_type));

        if (App.DEBUG)
            Log.v(TAG, "accounts.length =" + accounts.length);
        if (accounts.length <= 0) {
            if (App.DEBUG)
                Log.v(TAG, "no accounts have been set up");

        } else {

            mUsername = accounts[0].name;
            String encPwd = am.getPassword(accounts[0]);
            mPassword = EncryptionUtil.decryptString(encPwd);
        }

    }

    public static HttpClient getHttpClient() {
        HttpClient client = null;
        try {

            if (App.DEBUG)
                Log.v(TAG, "httpClient is null, download is creating a new client");

            SSLContext sslContext = createSslContext();
            MySSLSocketFactory socketFactory = new MySSLSocketFactory(sslContext,
                    new BrowserCompatHostnameVerifier());
            client = createHttpClient(socketFactory);

        } catch (GeneralSecurityException e) {
            Log.e(TAG, "Could not load the trust manager");
            e.printStackTrace();
        } catch (IOException e) {
            Log.e(TAG, "Could not load the trust manager. Ensure credential storage is available");
            e.printStackTrace();
        }

        return client;
    }

    public static SSLContext createSslContext() throws GeneralSecurityException, IOException {

        // TrustStore
        KeyStore trustStore = FileUtils.loadSslStore(FileUtils.MY_TRUSTSTORE);
        if (trustStore == null)
            throw new IOException("Access denied. Ensure credential storage is available.");
        MyTrustManager myTrustManager = new MyTrustManager(trustStore);
        TrustManager[] tms = new TrustManager[] { myTrustManager };

        // KeyStore
        KeyManager[] kms = null;
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(App.getApp());
        boolean useClientAuth = prefs.getBoolean(App.getApp().getString(R.string.key_client_auth), false);
        if (useClientAuth) {
            KeyStore keyStore = FileUtils.loadSslStore(FileUtils.MY_KEYSTORE);
            if (keyStore == null)
                throw new IOException("Access denied. Ensure credential storage is available.");
            KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            kmf.init(keyStore, EncryptionUtil.getPassword().toCharArray());
            kms = kmf.getKeyManagers();
        }

        SSLContext context = SSLContext.getInstance("TLS");
        context.init(kms, tms, null);
        return context;
    }

    public static HttpClient createHttpClient(SocketFactory socketFactory) {
        HttpParams params = new BasicHttpParams();
        HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
        HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
        HttpProtocolParams.setUseExpectContinue(params, false);
        HttpConnectionParams.setConnectionTimeout(params, CONNECTION_TIMEOUT);
        //      HttpConnectionParams.setSoTimeout(params, CONNECTION_TIMEOUT); // Times out Active Connection
        HttpClientParams.setRedirecting(params, false);

        ConnManagerParams.setTimeout(params, CONNECTION_TIMEOUT);
        ConnPerRoute connPerRoute = new ConnPerRouteBean(MAX_CONN_PER_ROUTE);
        ConnManagerParams.setMaxConnectionsPerRoute(params, connPerRoute);
        ConnManagerParams.setMaxTotalConnections(params, MAX_CONNECTIONS);
        SchemeRegistry schemeRegistry = new SchemeRegistry();

        SocketFactory sslSocketFactory = SSLSocketFactory.getSocketFactory();
        if (socketFactory != null) {
            sslSocketFactory = socketFactory;
        }
        try {
            schemeRegistry.register(new Scheme("http", sslSocketFactory, 80));
            schemeRegistry.register(new Scheme("https", sslSocketFactory, 443));
            schemeRegistry.register(new Scheme("https", sslSocketFactory, 8443));
        } catch (Exception e) {
            Log.e(TAG, "Caught an EXCEPTION. could not register the scheme?");
            e.printStackTrace();
        }
        ClientConnectionManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);
        DefaultHttpClient httpClient = new DefaultHttpClient(cm, params);

        return httpClient;
    }

    public static MultipartEntity createMultipartEntity(String path) {

        // find all files in parent directory
        File file = new File(path);
        File[] files = file.getParentFile().listFiles();
        if (App.DEBUG)
            Log.v(TAG, file.getAbsolutePath());

        // mime post
        MultipartEntity entity = null;
        if (files != null) {
            entity = new MultipartEntity();
            for (int j = 0; j < files.length; j++) {
                File f = files[j];
                FileBody fb;
                if (f.getName().endsWith(".xml")) {
                    fb = new FileBody(f, "text/xml");
                    entity.addPart("xml_submission_file", fb);
                    if (App.DEBUG)
                        Log.v(TAG, "added xml file " + f.getName());
                } else if (f.getName().endsWith(".jpg")) {
                    fb = new FileBody(f, "image/jpeg");
                    entity.addPart(f.getName(), fb);
                    if (App.DEBUG)
                        Log.v(TAG, "added image file " + f.getName());
                } else if (f.getName().endsWith(".3gpp")) {
                    fb = new FileBody(f, "audio/3gpp");
                    entity.addPart(f.getName(), fb);
                    if (App.DEBUG)
                        Log.v(TAG, "added audio file " + f.getName());
                } else if (f.getName().endsWith(".3gp")) {
                    fb = new FileBody(f, "video/3gpp");
                    entity.addPart(f.getName(), fb);
                    if (App.DEBUG)
                        Log.v(TAG, "added video file " + f.getName());
                } else if (f.getName().endsWith(".mp4")) {
                    fb = new FileBody(f, "video/mp4");
                    entity.addPart(f.getName(), fb);
                    if (App.DEBUG)
                        Log.v(TAG, "added video file " + f.getName());
                } else {
                    Log.w(TAG, "unsupported file type, not adding file: " + f.getName());
                }
            }
        } else {
            if (App.DEBUG)
                Log.v(TAG, "no files to upload in instance");
        }

        return entity;
    }

    // TODO Performance: This should not have to check trusted at every single time...
    // (maybe need to go into MyTrustManager to fix this?)
    public static void postEntity(HttpClient client, String url, MultipartEntity entity) throws IOException {
        HttpPost httppost = new HttpPost(url);
        httppost.setEntity(entity);
        HttpResponse response = client.execute(httppost);
        // verify response is okay
        int responseCode = response.getStatusLine().getStatusCode();
        if (App.DEBUG)
            Log.v(TAG, "httppost response=" + responseCode);
        if (responseCode != HttpURLConnection.HTTP_OK)
            throw new IOException(App.getApp().getString(R.string.error_connection));
    }

    public static InputStream getStream(HttpClient client, String url) throws Exception {
        HttpResponse response = null;
        try {
            HttpGet get = new HttpGet(url);
            response = client.execute(get);
        } catch (Exception e) {
            Log.e(TAG, "Caught Error getStream from Server! ");
            e.printStackTrace();

        }
        // verify response is okay
        if (response.getStatusLine().getStatusCode() != 200) {
            Log.e(TAG, "Error: " + response.getStatusLine());
            throw new IOException(App.getApp().getString(R.string.error_connection));
        } else {
            if (App.DEBUG)
                Log.v(TAG, "NO Error!: " + response.getStatusLine());
        }

        // Get hold of the response entity
        HttpEntity entity = response.getEntity();

        if (entity != null) {
            InputStream is = entity.getContent();
            return is;
        }

        return null;

    }

    public static DataInputStream getOdkStream(HttpClient client, String url) throws Exception {

        // get prefs
        HttpPost request = new HttpPost(url);
        request.setEntity(new OdkAuthEntity());
        HttpResponse response = client.execute(request);
        response.getStatusLine().getStatusCode();
        HttpEntity responseEntity = response.getEntity();

        DataInputStream zdis = new DataInputStream(new GZIPInputStream(responseEntity.getContent()));

        int status = zdis.readInt();
        if (status == HttpURLConnection.HTTP_UNAUTHORIZED) {
            zdis.close();
            throw new IOException("Access denied. Check your username and password.");
        } else if (status <= 0 || status >= HttpURLConnection.HTTP_BAD_REQUEST) {
            zdis.close();
            throw new IOException(App.getApp().getString(R.string.error_connection));
        } else {
            assert (status == HttpURLConnection.HTTP_OK); // success
            return zdis;
        }
    }

    private static class OdkAuthEntity extends AbstractHttpEntity {

        public boolean isRepeatable() {
            return false;
        }

        public long getContentLength() {
            return -1;
        }

        public boolean isStreaming() {
            return false;
        }

        public InputStream getContent() throws IOException {
            // Should be implemented as well but is irrelevant for this case
            throw new UnsupportedOperationException();
        }

        public void writeTo(final OutputStream outstream) throws IOException {
            DataOutputStream dos = new DataOutputStream(new GZIPOutputStream(outstream));
            dos.writeUTF(getServerUsername());
            dos.writeUTF(getServerPassword());

            SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(App.getApp());
            Boolean savedSearch = settings.getBoolean(App.getApp().getString(R.string.key_use_saved_searches),
                    false);
            Integer cohort = Integer
                    .valueOf(settings.getString(App.getApp().getString(R.string.key_saved_search), "0"));
            Integer program = Integer
                    .valueOf(settings.getString(App.getApp().getString(R.string.key_program), "0"));

            if (App.DEBUG)
                Log.v(TAG, "Writing variables to stream \n  cohort=" + cohort + "\n  program=" + program
                        + "\n  savedSearch=" + savedSearch);
            dos.writeBoolean(savedSearch);
            if (cohort > 0)
                dos.writeInt(cohort);
            if (program > 0)
                dos.writeInt(program);
            dos.close();
        }

    }

}