de.da_sense.moses.client.abstraction.apks.ExternalApplication.java Source code

Java tutorial

Introduction

Here is the source code for de.da_sense.moses.client.abstraction.apks.ExternalApplication.java

Source

/*******************************************************************************
 * Copyright 2013
 * Telecooperation (TK) Lab
 * Technische Universitt Darmstadt
 * 
 * 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 de.da_sense.moses.client.abstraction.apks;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.regex.Pattern;

import org.json.JSONException;
import org.json.JSONObject;

import android.os.Bundle;
import de.da_sense.moses.client.DetailFragment.AsyncGetSurvey;
import de.da_sense.moses.client.R;
import de.da_sense.moses.client.com.ConnectionParam;
import de.da_sense.moses.client.com.NetworkJSON.BackgroundException;
import de.da_sense.moses.client.com.ReqTaskExecutor;
import de.da_sense.moses.client.com.requests.RequestSurvey;
import de.da_sense.moses.client.service.MosesService;
import de.da_sense.moses.client.userstudy.Survey;
import de.da_sense.moses.client.util.Log;
import de.da_sense.moses.client.util.Toaster;

/**
 * Reference to an application on the server, referenced by it's MoSeS id
 * 
 * @author Simon L
 * @author Wladimir Schmidt
 * @author Zijad Maksuti
 * 
 */
public class ExternalApplication {
    /** tag for the version */
    private static final String TAG_NEWESTVERSION = "[newestversion]";
    /** tag for the description */
    private static final String TAG_DESCRIPTION = "[description]";
    /** tag for the name */
    private static final String TAG_NAME = "[name]";
    /** tag for start date */
    private static final String TAG_STARTDATE = "[startdate]";
    /** tag for end date */
    private static final String TAG_ENDDATE = "[enddate]";
    /** tag for apk version */
    private static final String TAG_APKVERSION = "[apkversion]";
    /** tag for questionnaire */
    private static final String TAG_QUESTIONNAIRE = "[questionnaire]";

    /** tag for the separator */
    private static final String SEPARATOR = "#EA#";

    private static final String LOG_TAG = ExternalApplication.class.getName();

    /**
     * Boolean if the enddate is reached
     */
    private Boolean endDateReached = false;

    public Boolean getEndDateReached() {
        return endDateReached;
    }

    public void setEndDateReached(Boolean endDateReached) {
        this.endDateReached = endDateReached;
    }

    /**
     * Boolean if this {@link ExternalApplication} contains a locally stored {@link Survey}.
     */
    private Boolean apkHasSurveyLocally = false;

    /** String containing the id */
    private String apkID;

    /**
     * A constant to be used when passing an id of an {@link ExternalApplication} through
     * a communication channel. For example, through a {@link Bundle}.
     */
    public static final String KEY_APK_ID = "keyApkID";

    // lazy loading variables for non-defining attributes
    /** the user study name */
    private String name;
    /** the user study description */
    private String description;
    /** the newest version of the user study / apk */
    private String newestVersion = "0";
    /** the start date of this user study */
    private Date startDate;
    /** the end date of this user study */
    private Date endDate;
    /** the apk version of this user study */
    private String apkVersion;
    /** the survey of this user study */
    private Survey mSurvey;

    private String mBadge = "";

    /**
     * Gets the ID
     * 
     * @return ID
     */
    public String getID() {
        return apkID;
    }

    public void setID(String id) {
        this.apkID = id;
    }

    /**
     * Creates a reference to an external application, specifying its ID
     * 
     * @param ID
     *            the id in the MoSeS database
     */
    public ExternalApplication(int ID) {
        //Log.d(LOG_TAG, "from ID");
        this.apkID = String.valueOf(ID);
    }

    public ExternalApplication() {
    }

    /**
     * sets the name of the application
     * 
     * @param name
     *            the name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * sets the description of the application
     * 
     * @param description
     *            the description
     */
    public void setDescription(String description) {
        this.description = description;
    }

    /**
     * Returns the name of this external application. If the name was not set,
     * or retrieved yet, this will be done now. In this case, this method should
     * not be called from the UI thread (method blocks).
     * 
     * @return
     */
    public String getName() {
        if (name != null) {
            return name;
        } else {
            return getGenericName();
        }
    }

    /**
     * retrieves the name of this application from the server in case it was not
     * set yet.
     * 
     * @return the name of the application
     */
    private String getGenericName() {
        return MosesService.getInstance().getApplicationContext().getString(R.string.loadingName, getID());
    }

    /**
     * Returns the description of this external application. If the description
     * was not set, or retrieved yet, this will be done now. In this case, this
     * method should not be called from the UI thread (method blocks).
     * 
     * @return
     */
    public String getDescription() {
        if (description != null) {
            return description;
        } else {
            return MosesService.getInstance().getApplicationContext().getString(R.string.loadingDescription);
        }
    }

    /**
     * Returns the String newestVersion
     * 
     * @return newestVersion
     */
    public String getNewestVersion() {
        return newestVersion;
    }

    /**
     * Sets the newestVersion
     * 
     * @param newestVersion
     *            The version to set
     */
    public void setNewestVersion(String newestVersion) {
        this.newestVersion = newestVersion;
    }

    /**
     * Returns if newestVersion is not null
     * 
     * @return boolean - newestVersion != null
     */
    public boolean isNewestVersionSet() {
        return newestVersion != null;
    }

    /**
     * @return whether the description of the application was already
     *         retrieved/set
     */
    public boolean isDescriptionSet() {
        return description != null;
    }

    /**
     * @return whether the name of the application was already retrieved/set
     */
    public boolean isNameSet() {
        return name != null;
    }

    /**
     * To set the start date of this user study
     * 
     * @param startDate
     *            the date to set
     */
    public void setStartDate(String startDate) {
        this.startDate = convertStringDate(startDate);
    }

    /**
     * To set the start date of this user study
     * 
     * @param startDate
     *            the date to set
     */
    public void setStartDate(Date startDate) {
        this.startDate = startDate;
    }

    /**
     * @return the start date of this user study
     */

    public Date getStartDate() {
        return startDate;
    }

    /**
     * @return the date as a localized String
     */
    public String getStartDateAsString() {
        String date = null;
        if (startDate != null) {
            DateFormat format = SimpleDateFormat.getDateInstance();
            date = format.format(startDate);
        } else {
            date = "not set";
        }
        return date;
    }

    /**
     * @return the date as a standard String
     */
    public String getStartDateAsStandardString() {
        String date = null;
        if (startDate != null) {
            DateFormat format = new SimpleDateFormat("yyyy-MM-dd");
            date = format.format(startDate);
        } else {
            date = MosesService.getInstance().getApplicationContext().getString(R.string.not_set);
        }
        return date;
    }

    /**
     * whether the start date of this user study is set
     */
    public boolean isStartDateSet() {
        return startDate != null;
    }

    /**
     * To set the end date of this user study
     * 
     * @param endDate
     *            the date to set
     */
    public void setEndDate(String endDate) {
        this.endDate = convertStringDate(endDate);
    }

    /**
     * To set the end date of this user study
     * 
     * @param endDate
     *            the date to set
     */
    public void setEndDate(Date endDate) {
        this.endDate = endDate;
    }

    /**
     * @return the end date of this user study
     */
    public Date getEndDate() {
        return endDate;
    }

    /**
     * @return the date as a localized String
     */
    public String getEndDateAsString() {
        String date = null;
        if (startDate != null) {
            DateFormat format = SimpleDateFormat.getDateInstance();
            date = format.format(endDate);
        } else {
            date = MosesService.getInstance().getApplicationContext().getString(R.string.not_set);
        }
        return date;
    }

    /**
     * @return the date as a standard String
     */
    public String getEndDateAsStandardString() {
        String date = null;
        if (startDate != null) {
            DateFormat format = new SimpleDateFormat("yyyy-MM-dd");
            date = format.format(endDate);
        } else {
            date = MosesService.getInstance().getApplicationContext().getString(R.string.not_set);
        }
        return date;
    }

    /**
     * whether the end date of this user study is set
     */
    public boolean isEndDateSet() {
        return endDate != null;
    }

    /**
     * @return the apk version of this user study
     */
    public String getApkVersion() {
        return apkVersion;
    }

    /**
     * To set the apk version of this user study
     * 
     * @param apkVersion
     *            the apk version
     */
    public void setApkVersion(String apkVersion) {
        this.apkVersion = apkVersion;
    }

    /**
     * whether the apk version is set
     */
    public boolean isApkVersionSet() {
        return apkVersion != null;
    }

    /**
     * Set the questionnaire from a string.
     * 
     * @param questAsString
     */
    public void setQuestionnaire(String questAsString) {
        try {
            JSONObject questAsJson = new JSONObject(questAsString);
            setSurvey(new Survey(questAsJson));
            apkHasSurveyLocally = true;
        } catch (JSONException e) {
            Log.e(LOG_TAG, e.getMessage());
        }
    }

    /**
     * Getting questionnaire with string format
     * 
     * @return string that represents the questionnaire of this application
     *         (user study)
     */
    private String getStringQuestionnaire() {
        return mSurvey.toString();
    }

    /**
     * Getter for questionnaire
     * 
     * @return the questionnaire of this application (user study)
     */
    public Survey getSurvey() {
        return mSurvey;
    }

    /**
     * Sets a {@link Survey} instance to this {@link ExternalApplication}.
     * 
     * @param mSurvey the survey to set
     */
    public void setSurvey(Survey survey) {
        this.mSurvey = survey;
        apkHasSurveyLocally = true;
    }

    /**
     * Checks if the external application has a {@link Survey} stored locally.
     * 
     * @return true if the external app contains a locally stored survey
     */
    public boolean hasSurveyLocally() {
        return (apkHasSurveyLocally);
    }

    private static String LINEBREAK_SUBST = "#LINEBREAK";

    /**
     * Replaces all "\r\n" and "\n" in the String with the LINEBREAK_SUBST
     * 
     * @param s
     *            The original String
     * @return The String with the replacements
     */
    private static String toLinebreakSubst(String s) {
        return s.replaceAll(Pattern.quote("\r\n"), LINEBREAK_SUBST).replaceAll(Pattern.quote("\n"),
                LINEBREAK_SUBST);
    }

    /**
     * Replaces all LINEBREAK_SUBST with "\n"
     * 
     * @param s
     *            The original String
     * @return The String with replacements
     */
    private static String fromLinebreakSubst(String s) {
        return s.replaceAll(Pattern.quote(LINEBREAK_SUBST), "\n");
    }

    /**
     * writes this object into an one-line string
     * 
     * @return the encoded object
     */
    public String asOnelineString() { // ID-{name}-{description}
        String result = this.apkID;
        if (isNameSet()) {
            result += SEPARATOR + TAG_NAME + toLinebreakSubst(getName());
        }
        if (isDescriptionSet()) {
            result += SEPARATOR + TAG_DESCRIPTION + toLinebreakSubst(getDescription());
        }
        if (isNewestVersionSet()) {
            result += SEPARATOR + TAG_NEWESTVERSION + getNewestVersion().toString();
        }
        if (isStartDateSet()) {
            result += SEPARATOR + TAG_STARTDATE + getStartDateAsStandardString();
        }
        if (isEndDateSet()) {
            result += SEPARATOR + TAG_ENDDATE + getEndDateAsStandardString();
        }
        if (isApkVersionSet()) {
            result += SEPARATOR + TAG_APKVERSION + getApkVersion();
        }

        if (apkHasSurveyLocally) {
            result += SEPARATOR + TAG_QUESTIONNAIRE + getStringQuestionnaire();

        } else {
            Log.i("ExternalApplication", "no questionnaire for " + toLinebreakSubst(getName()) + " found");
        }
        Log.d(LOG_TAG, "asOnelineString = " + result);
        return result;
    }

    @Override
    public String toString() {
        return asOnelineString();
    }

    /**
     * creates an external application from a string (@see
     * {@link #asOnelineString()})
     * 
     * @param s
     *            the string-encoded external application
     * @return the decoded external application
     */
    public ExternalApplication(String s) {
        initializeFromString(s);
    }

    /**
     * Builds this {@link ExternalApplication} instance from consumed String.
     * @param s the String containing a serialized {@link ExternalApplication} instance.
     */
    protected void initializeFromString(String s) {
        Log.d(LOG_TAG, "fromOnelineString : " + s);
        String[] split = s.split(Pattern.quote(SEPARATOR));
        String ID = null;
        String name = null;
        String description = null;
        String newestVersion = null;
        String startDate = null;
        String endDate = null;
        String apkVersion = null;
        String questionnaireString = null;
        for (int i = 0; i < split.length; i++) {
            if (i == 0) {
                Log.d(LOG_TAG, "ID set to " + split[i].toString());
                ID = split[i];
            } else {
                if (split[i].startsWith(TAG_DESCRIPTION)) {
                    description = fromLinebreakSubst(split[i].substring(TAG_DESCRIPTION.length()));
                }
                if (split[i].startsWith(TAG_NAME)) {
                    name = fromLinebreakSubst(split[i].substring(TAG_NAME.length()));
                }
                if (split[i].startsWith(TAG_NEWESTVERSION)) {
                    newestVersion = split[i].substring(TAG_NEWESTVERSION.length());
                }

                if (split[i].startsWith(TAG_STARTDATE)) {
                    startDate = split[i].substring(TAG_STARTDATE.length());
                }
                if (split[i].startsWith(TAG_ENDDATE)) {
                    endDate = split[i].substring(TAG_ENDDATE.length());
                }
                if (split[i].startsWith(TAG_APKVERSION)) {
                    apkVersion = split[i].substring(TAG_APKVERSION.length());
                }
                if (split[i].startsWith(TAG_QUESTIONNAIRE)) {
                    questionnaireString = split[i].substring(TAG_QUESTIONNAIRE.length());
                }
            }
        }

        this.setID(ID);
        this.setName(name);
        this.setDescription(description);
        this.setNewestVersion(newestVersion);

        this.setStartDate(startDate);
        this.setEndDate(endDate);
        this.setApkVersion(apkVersion);
        Log.d(LOG_TAG, "questionnaire = " + questionnaireString);
        if (questionnaireString != null)
            if (questionnaireString.length() > 0) {
                Log.d(LOG_TAG, "has Local questionnaire " + questionnaireString);
                this.setQuestionnaire(questionnaireString);
                apkHasSurveyLocally = true;
            } else {
                apkHasSurveyLocally = false;
            }
    }

    /**
     * Convert a String to a Date.
     * 
     * @param date
     *            the date as String (yyyy-MM-dd)
     * @return date
     */
    private static Date convertStringDate(String date) {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        Date dateObject = null;
        try {
            if (date != null && date != "null") {
                dateObject = format.parse(date);
            }
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return dateObject;
    }

    /**
     * @return true if all data that could be retrieved for this object (name,
     *         description, ...) is held in this object
     */
    public boolean isDataComplete() {
        return isDescriptionSet() && isNameSet() && isNewestVersionSet() && isStartDateSet() && isEndDateSet()
                && isApkVersionSet();
    }

    /**
     * Gets the questionnaire for this app from the server
     * 
     * @param getSurveyTask the task that has to be notified about the arrived survey
     */
    public void getQuestionnaireFromServer() {
        Log.d(LOG_TAG, "Request survey from server");
        new RequestSurvey(new GetQuestionnaireExecutor(), apkID).send();
    }

    /**
     * Sets that this apk has neither an Questionnaire on the server nor locally
     */
    void hasNoQuestionnaire() {
        apkHasSurveyLocally = false;
    }

    /**
     * Implementation of ReqTaskExecutor to handle the return of the server
     * for a SetQuestionnaireRequest
     */
    private class GetQuestionnaireExecutor implements ReqTaskExecutor {

        private final String LOG_TAG = GetQuestionnaireExecutor.class.getName();

        @Override
        public void handleException(Exception e) {
            Log.d(LOG_TAG, "Failed because of an exception: " + e.getMessage());
            if (!MosesService.getInstance().isOnline())
                Toaster.showNoInternetConnectionToast();
            else
                Toaster.showBadServerResponseToast();
        }

        @Override
        public void postExecution(String s) {
            try {
                JSONObject j = new JSONObject(s);
                Log.d(LOG_TAG, "postExecution return was: " + s);
                String APKID = null;
                String Status = j.getString("STATUS");
                if (Status.equals("SUCCESS")) {
                    Log.d(LOG_TAG, "Successfully received the Multi_Questionnaire");
                    APKID = j.getString("APKID");
                    InstalledExternalApplicationsManager.getInstance().getAppForId(APKID).setQuestionnaire(s);
                    // notify the async task
                    if (AsyncGetSurvey.isRunning())
                        AsyncGetSurvey.surveyArrived(APKID, false);
                } else if (Status.equals("FAILURE_NO_QUESTIONNAIRE_FOUND")) {
                    Log.d(LOG_TAG,
                            "Failed to receive the Questionnare, because this ExternalApplication has no Questionnaire on the server");
                    APKID = j.getString("APKID");
                    if (AsyncGetSurvey.isRunning())
                        AsyncGetSurvey.surveyArrived(APKID, true);
                    InstalledExternalApplicationsManager.getInstance().getAppForId(APKID).hasNoQuestionnaire();
                } else if (Status.equals("FAILURE_INVALID_APKID")) {
                    Log.d(LOG_TAG, "Failed to receive the Questionnare, because of invalid APK");
                    if (AsyncGetSurvey.isRunning())
                        AsyncGetSurvey.surveyArrived(null, true);
                } else if (Status.equals("INVALID_SESSION")) {
                    Log.d(LOG_TAG,
                            "Failed to receive the Questionnare, because of invalid Session ID. Trying again");
                    MosesService.getInstance().login();
                    APKID = j.getString("APKID");
                    InstalledExternalApplicationsManager.getInstance().getAppForId(APKID)
                            .getQuestionnaireFromServer();
                }
            } catch (JSONException e) {
                this.handleException(e);
            }
        }

        @Override
        public void updateExecution(BackgroundException c) {
            if (c.c == ConnectionParam.EXCEPTION) {
                handleException(c.e);
            }
        }
    }

    /**
     * @return the mBadge
     */
    public String getBadge() {
        return mBadge;
    }

    /**
     * @param mBadge the mBadge to set
     */
    public void setBadge(String mBadge) {
        this.mBadge = mBadge;
    }

}