org.openremote.android.console.util.AsyncResourceLoader.java Source code

Java tutorial

Introduction

Here is the source code for org.openremote.android.console.util.AsyncResourceLoader.java

Source

/* OpenRemote, the Home of the Digital Home.
* Copyright 2008-2010, OpenRemote Inc.
*
* See the contributors.txt file in the distribution for a
* full listing of individual contributors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package org.openremote.android.console.util;

import java.util.Iterator;
import java.io.IOException;

import javax.net.ssl.SSLException;
import javax.net.ssl.SSLProtocolException;

import org.apache.http.HttpResponse;
import org.openremote.android.console.AppSettingsActivity;
import org.openremote.android.console.Constants;
import org.openremote.android.console.GroupActivity;
import org.openremote.android.console.LoginViewActivity;
import org.openremote.android.console.Main;
import org.openremote.android.console.R;
import org.openremote.android.console.model.AppSettingsModel;
import org.openremote.android.console.model.ControllerException;
import org.openremote.android.console.model.ViewHelper;
import org.openremote.android.console.model.XMLEntityDataBase;
import org.openremote.android.console.net.ORControllerServerSwitcher;
import org.openremote.android.console.net.ORNetworkCheck;
import org.openremote.android.console.ssl.ORKeyStore;

import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.text.TextUtils.TruncateAt;
import android.util.Log;
import android.widget.RelativeLayout;
import android.widget.TextView;

/**
 * It's responsible for downloading resources in backgroud and updte progress in text.
 * 
 * @author handy 2010-05-10
 * @author Dan Cong
 *
 */
public class AsyncResourceLoader extends AsyncTask<Void, String, AsyncResourceLoaderResult> {
    private static final int TO_LOGIN = 0xF00A;
    private static final int TO_SETTING_SSL_PROTOCOL_ERROR = 0xF00B;
    private static final int TO_SETTING_SSL_ERROR = 0xF00C;
    private static final int TO_GROUP = 0xF00D;
    private static final int SWITCH_TO_OTHER_CONTROLER = 0xF00E;

    public final static String LOG_CATEGORY = Constants.LOG_CATEGORY + AsyncResourceLoader.class.getName();
    private ORKeyStore orKeyStore;

    private Activity activity;
    private AsyncGroupLoader groupLoader;

    public AsyncResourceLoader(Activity activity) {
        this.activity = activity;

        /**
         * Start the retrieving our group from the ORB
         */
        this.groupLoader = new AsyncGroupLoader(activity.getApplicationContext());
        this.groupLoader.start();
        this.orKeyStore = ORKeyStore.getInstance(activity);
    }

    /** 
     * Download resources in background.
     * 
     * @see android.os.AsyncTask#doInBackground(Params[])
     */
    @Override
    protected AsyncResourceLoaderResult doInBackground(Void... params) {
        AsyncResourceLoaderResult result = new AsyncResourceLoaderResult();
        boolean isDownloadSuccess = false;
        String panelName = AppSettingsModel.getCurrentPanelIdentity(activity);
        publishProgress("panel: " + panelName);

        Log.i("OpenRemote/DOWNLOAD", "Getting panel: " + panelName);

        String serverUrl = AppSettingsModel.getSecuredServer(activity);

        HttpResponse checkResponse = null;

        try {
            checkResponse = ORNetworkCheck.verifyControllerURL(activity,
                    AppSettingsModel.getCurrentServer(activity));
        } catch (SSLProtocolException e) {
            //Probably no access
            result.setAction(TO_SETTING_SSL_PROTOCOL_ERROR);
            Log.e(LOG_CATEGORY, "AsyncReSourceLoader: ", e);

            // Delete & create a new keystore
            orKeyStore.delete();
            orKeyStore.create();
            return result;
        } catch (SSLException e) {
            //Probably no access
            result.setAction(TO_SETTING_SSL_ERROR);
            Log.e(LOG_CATEGORY, "AsyncReSourceLoader: ", e);
            return result;
        } catch (IOException e) {
            // TODO :
            //   right now still not doing anything with this, user is still completely in the dark
            //   what went wrong, need to untangle the async loader mess before can propagate info
            //   back to user
            //
            //   So for now, an empty catch block, until I can build proper test cases for these
            //                                                                                    [JPL]
            //
            if (e != null) {
                Log.e(LOG_CATEGORY, "AsyncReSourceLoader: ", e);
                Log.e("OpenRemote/DOWNLOAD", e.getMessage());
            }
        }

        isDownloadSuccess = checkResponse != null
                && checkResponse.getStatusLine().getStatusCode() == Constants.HTTP_SUCCESS;

        if (isDownloadSuccess) {
            int downLoadPanelXMLStatusCode = HTTPUtil.downLoadPanelXml(activity, serverUrl, panelName);
            if (downLoadPanelXMLStatusCode != Constants.HTTP_SUCCESS) { // download panel xml fail.
                Log.i("OpenRemote/DOWNLOAD", "Download file panel.xml fail.");
                if (downLoadPanelXMLStatusCode == ControllerException.UNAUTHORIZED) {
                    result.setAction(TO_LOGIN);
                    result.setStatusCode(downLoadPanelXMLStatusCode);
                    return result;
                }

                if (activity.getFileStreamPath(Constants.PANEL_XML).exists()) {
                    Log.i("OpenRemote/DOWNLOAD", "Download file panel.xml fail, so use local cache.");
                    FileUtil.parsePanelXML(activity);
                    result.setCanUseLocalCache(true);
                    result.setStatusCode(downLoadPanelXMLStatusCode);
                    result.setAction(TO_GROUP);
                } else {
                    Log.i("OpenRemote/DOWNLOAD", "No local cache is available, ready to switch controller.");
                    result.setAction(SWITCH_TO_OTHER_CONTROLER);
                    return result;
                }
            } else { // download panel xml success.
                Log.i("OpenRemote/DOWNLOAD", "Download file panel.xml successfully.");
                if (activity.getFileStreamPath(Constants.PANEL_XML).exists()) {
                    FileUtil.parsePanelXML(activity);
                    result.setAction(TO_GROUP);
                } else {
                    Log.i("OpenRemote/DOWNLOAD",
                            "No local cache is available authouth downloaded file panel.xml successfully, ready to switch controller.");
                    result.setAction(SWITCH_TO_OTHER_CONTROLER);
                    return result;
                }

                Iterator<String> images = XMLEntityDataBase.imageSet.iterator();
                String imageName = "";
                while (images.hasNext()) {
                    imageName = images.next();
                    publishProgress(imageName);
                    HTTPUtil.downLoadImage(activity, AppSettingsModel.getSecuredServer(activity), imageName);
                }
            }
        } else { // Download failed.
            if (checkResponse != null
                    && checkResponse.getStatusLine().getStatusCode() == ControllerException.UNAUTHORIZED) {
                String html = "";

                try {
                    html = StringUtil.stringFromInputStream(checkResponse.getEntity().getContent());
                } catch (IllegalStateException e) {
                    Log.e(LOG_CATEGORY, e.getMessage());
                } catch (IOException e) {
                    Log.e(LOG_CATEGORY, e.getMessage());
                }

                if (AppSettingsModel.isSSLEnabled(activity) || html.contains("client certificate chain")) {
                    result.setAction(TO_SETTING_SSL_ERROR);
                } else {
                    result.setAction(TO_LOGIN);
                    result.setStatusCode(ControllerException.UNAUTHORIZED);
                }
                return result;
            }

            if (checkResponse != null && checkResponse.getStatusLine().getStatusCode() == 403) {
                result.setAction(TO_SETTING_SSL_ERROR);
                return result;
            }

            if (activity.getFileStreamPath(Constants.PANEL_XML).exists()) {
                Log.i("OpenRemote/DOWNLOAD", "Download failed, so use local cache.");
                FileUtil.parsePanelXML(activity);
                result.setCanUseLocalCache(true);
                result.setAction(TO_GROUP);
                if (checkResponse == null) {
                    result.setStatusCode(ControllerException.CONTROLLER_UNAVAILABLE);
                } else {
                    result.setStatusCode(checkResponse.getStatusLine().getStatusCode());
                }
            } else {
                Log.i("OpenRemote/DOWNLOAD", "No local cache is available, ready to switch controller.");
                result.setAction(SWITCH_TO_OTHER_CONTROLER);
                return result;
            }
        }

        new Thread(new Runnable() {
            public void run() {
                ORControllerServerSwitcher.detectGroupMembers(activity);
            }
        }).start();

        if (result.getAction() == TO_GROUP && !groupLoader.isDone()) {
            synchronized (groupLoader) {
                try {
                    groupLoader.wait();
                } catch (InterruptedException e) {
                    Log.e("OpenRemote/DOWNLOAD", "Waiting for groupLoader interrupted");
                }
            }
        }

        return result;
    }

    /**
     * Update progress message in text.
     * 
     * @see android.os.AsyncTask#onProgressUpdate(Progress[])
     */
    @Override
    protected void onProgressUpdate(String... values) {
        RelativeLayout loadingView = (RelativeLayout) (activity.findViewById(R.id.welcome_view));
        if (loadingView == null) {
            return;
        }

        TextView loadingText = (TextView) (activity.findViewById(R.id.loading_text));
        loadingText.setText("loading " + values[0] + "...");
        loadingText.setEllipsize(TruncateAt.MIDDLE);
        loadingText.setSingleLine(true);
    }

    /**
     * Finish downloading and forward to different view by result.
     * 
     * @see android.os.AsyncTask#onPostExecute(java.lang.Object)
     */
    @Override
    protected void onPostExecute(AsyncResourceLoaderResult result) {
        publishProgress("groups & screens");
        Intent intent = new Intent();
        switch (result.getAction()) {
        case TO_GROUP:
            intent.setClass(activity, GroupActivity.class);
            if (result.isCanUseLocalCache()) {
                intent.setData(Uri.parse(ControllerException.exceptionMessageOfCode(result.getStatusCode())));
            }
            break;
        case TO_LOGIN:
            intent.setClass(activity, LoginViewActivity.class);
            intent.setData(Uri.parse(Main.LOAD_RESOURCE));
            break;
        case TO_SETTING_SSL_PROTOCOL_ERROR:
            //If the host is in the keystore, delete it. It is obviously invalid.
            orKeyStore.deleteHost(AppSettingsModel.getCurrentServer(activity));

            intent.setClass(activity, AppSettingsActivity.class);
            intent.putExtra("SSL_CLIENT_PROTOCOL", true);
            break;
        case TO_SETTING_SSL_ERROR:
            //If the host is in the keystore, delete it. It is obviously invalid.
            orKeyStore.deleteHost(AppSettingsModel.getCurrentServer(activity));

            intent.setClass(activity, AppSettingsActivity.class);
            intent.putExtra("SSL_CLIENT", true);
            break;
        case SWITCH_TO_OTHER_CONTROLER:

            ORControllerServerSwitcher.doSwitch(activity);
            return;

        default:
            ViewHelper.showAlertViewWithTitle(activity, "Send Request Error",
                    ControllerException.exceptionMessageOfCode(result.getStatusCode()));
            return;
        }

        activity.startActivity(intent);
        activity.finish();
    }
}

/**
 * To express the downloading result state.
 */
class AsyncResourceLoaderResult {

    /** The action after downloading. */
    private int action;

    /** Download resources status code. */
    private int statusCode;

    /** If download failed, can use local cache or not. */
    private boolean canUseLocalCache;

    public AsyncResourceLoaderResult() {
        action = -1;
        statusCode = -1;
        canUseLocalCache = false;
    }

    public int getAction() {
        return action;
    }

    public void setAction(int action) {
        this.action = action;
    }

    public int getStatusCode() {
        return statusCode;
    }

    public void setStatusCode(int statusCode) {
        this.statusCode = statusCode;
    }

    public boolean isCanUseLocalCache() {
        return canUseLocalCache;
    }

    public void setCanUseLocalCache(boolean canUseLocalCache) {
        this.canUseLocalCache = canUseLocalCache;
    }

}