com.jaspersoft.android.jaspermobile.activities.profile.ServerProfileActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.jaspersoft.android.jaspermobile.activities.profile.ServerProfileActivity.java

Source

/*
 * Copyright  2014 TIBCO Software, Inc. All rights reserved.
 *  http://community.jaspersoft.com/project/jaspermobile-android
 *
 *  Unless you have purchased a commercial license agreement from Jaspersoft,
 *  the following license terms apply:
 *
 *  This program is part of Jaspersoft Mobile for Android.
 *
 *  Jaspersoft Mobile is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  Jaspersoft Mobile 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 Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with Jaspersoft Mobile for Android. If not, see
 *  <http://www.gnu.org/licenses/lgpl>.
 */

package com.jaspersoft.android.jaspermobile.activities.profile;

import android.app.ActionBar;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.res.TypedArray;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.MenuItem;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.webkit.URLUtil;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.Toast;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.inject.Inject;
import com.jaspersoft.android.jaspermobile.JasperMobileApplication;
import com.jaspersoft.android.jaspermobile.R;
import com.jaspersoft.android.jaspermobile.activities.profile.fragment.ServersFragment;
import com.jaspersoft.android.jaspermobile.activities.robospice.RoboSpiceFragmentActivity;
import com.jaspersoft.android.jaspermobile.db.database.table.ServerProfilesTable;
import com.jaspersoft.android.jaspermobile.db.model.ServerProfiles;
import com.jaspersoft.android.jaspermobile.db.provider.JasperMobileDbProvider;
import com.jaspersoft.android.jaspermobile.dialog.AlertDialogFragment;
import com.jaspersoft.android.jaspermobile.network.CommonRequestListener;
import com.jaspersoft.android.jaspermobile.network.ExceptionRule;
import com.jaspersoft.android.jaspermobile.info.ServerInfoManager;
import com.jaspersoft.android.sdk.client.JsRestClient;
import com.jaspersoft.android.sdk.client.JsServerProfile;
import com.jaspersoft.android.sdk.client.async.request.cacheable.GetServerInfoRequest;
import com.jaspersoft.android.sdk.client.oxm.server.ServerInfo;
import com.octo.android.robospice.persistence.exception.SpiceException;

import org.androidannotations.annotations.Bean;
import org.androidannotations.annotations.CheckedChange;
import org.androidannotations.annotations.EActivity;
import org.androidannotations.annotations.Extra;
import org.androidannotations.annotations.InstanceState;
import org.androidannotations.annotations.OptionsItem;
import org.androidannotations.annotations.OptionsMenu;
import org.androidannotations.annotations.OptionsMenuItem;
import org.androidannotations.annotations.SystemService;
import org.androidannotations.annotations.TextChange;
import org.androidannotations.annotations.UiThread;
import org.androidannotations.annotations.ViewById;
import org.springframework.http.HttpStatus;

import java.util.List;
import java.util.Map;

/**
 * @author Tom Koptel
 * @author Ivan Gadzhega
 * @since 1.0
 */
@EActivity(R.layout.server_create_form)
@OptionsMenu(R.menu.profile_menu)
public class ServerProfileActivity extends RoboSpiceFragmentActivity
        implements LoaderManager.LoaderCallbacks<Cursor> {
    private static final int LOAD_PROFILE = 100;
    private static final int QUERY_UNIQUENESS = 110;

    @Extra
    long profileId;

    @ViewById
    EditText aliasEdit;
    @ViewById
    EditText serverUrlEdit;
    @ViewById
    EditText organizationEdit;
    @ViewById
    EditText usernameEdit;
    @ViewById
    EditText passwordEdit;
    @ViewById
    CheckBox askPasswordCheckBox;

    @OptionsMenuItem
    MenuItem saveAction;

    @InstanceState
    String alias;
    @InstanceState
    String serverUrl;
    @InstanceState
    String organization;
    @InstanceState
    String username;
    @InstanceState
    String password;

    @SystemService
    InputMethodManager inputMethodManager;

    @Inject
    JsRestClient jsRestClient;
    @Bean
    ServerInfoManager infoManager;

    private ServerProfiles mServerProfile;
    private ServerProfiles mLoadedProfile;
    private int mActionBarSize;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        final TypedArray styledAttributes = getTheme()
                .obtainStyledAttributes(new int[] { android.R.attr.actionBarSize });
        mActionBarSize = (int) styledAttributes.getDimension(0, 0);
        styledAttributes.recycle();

        ActionBar actionBar = getActionBar();
        if (actionBar != null) {
            actionBar.setDisplayHomeAsUpEnabled(true);
        }

        invalidateOptionsMenu();

        if (profileId != 0 && savedInstanceState == null) {
            getSupportLoaderManager().initLoader(LOAD_PROFILE, null, this);
        }
    }

    @OptionsItem(android.R.id.home)
    final void showHome() {
        super.onBackPressed();
    }

    @OptionsItem
    final void saveAction() {
        if (isFormValid()) {
            if (mServerProfile == null) {
                mServerProfile = new ServerProfiles();
            }
            mServerProfile.setAlias(alias);
            mServerProfile.setServerUrl(serverUrl);
            mServerProfile.setOrganization(organization);
            mServerProfile.setUsername(username);
            mServerProfile.setPassword(password);

            getSupportLoaderManager().initLoader(QUERY_UNIQUENESS, null, this);
        }
    }

    @TextChange(R.id.aliasEdit)
    void onAliasTextChanges(CharSequence text) {
        alias = text.toString();
        aliasEdit.setError(null);
        setSubmitActionState();
    }

    @TextChange(R.id.serverUrlEdit)
    void onServerUrlTextChanges(CharSequence text) {
        serverUrl = text.toString();
        serverUrlEdit.setError(null);
        setSubmitActionState();
    }

    @TextChange(R.id.organizationEdit)
    void onOrganizationTextChanges(CharSequence text) {
        organization = text.toString();
    }

    @TextChange(R.id.usernameEdit)
    void onUsernameUrlTextChanges(CharSequence text) {
        username = text.toString();
        usernameEdit.setError(null);
        setSubmitActionState();
    }

    @TextChange(R.id.passwordEdit)
    void onPasswordUrlTextChanges(CharSequence text) {
        password = text.toString();
        passwordEdit.setError(null);
        setSubmitActionState();
    }

    @CheckedChange(R.id.askPasswordCheckBox)
    void checkedChangedOnAskPassword(boolean checked) {
        passwordEdit.setEnabled(!checked);
        passwordEdit.setFocusable(!checked);
        passwordEdit.setFocusableInTouchMode(!checked);
        passwordEdit.setError(null);
        passwordEdit.setText("");
        setSubmitActionState();
    }

    //---------------------------------------------------------------------
    // Implements LoaderManager.LoaderCallbacks<Cursor>
    //---------------------------------------------------------------------

    @Override
    public void onLoaderReset(Loader<Cursor> cursorLoader) {
    }

    @Override
    public Loader<Cursor> onCreateLoader(int code, Bundle bundle) {
        String selection;
        String[] selectionArgs;

        switch (code) {
        case LOAD_PROFILE:
            selection = ServerProfilesTable._ID + " =?";
            selectionArgs = new String[] { String.valueOf(profileId) };
            return new CursorLoader(this, JasperMobileDbProvider.SERVER_PROFILES_CONTENT_URI,
                    ServerProfilesTable.ALL_COLUMNS, selection, selectionArgs, null);
        case QUERY_UNIQUENESS:
            selection = ServerProfilesTable.ALIAS + " =?";
            selectionArgs = new String[] { alias };
            if (profileId != 0) {
                selection += " AND " + ServerProfilesTable._ID + " !=?";
                selectionArgs = new String[] { alias, String.valueOf(profileId) };
            }
            return new CursorLoader(this, JasperMobileDbProvider.SERVER_PROFILES_CONTENT_URI,
                    new String[] { ServerProfilesTable._ID }, selection, selectionArgs, null);
        default:
            throw new UnsupportedOperationException();
        }
    }

    @Override
    public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
        switch (cursorLoader.getId()) {
        case LOAD_PROFILE:
            if (cursor.getCount() > 0) {
                cursor.moveToFirst();
                updateProfileFields(cursor);
            }
            break;
        case QUERY_UNIQUENESS:
            checkUniqueConstraintFulfilled(cursor);
            break;
        }
    }

    //---------------------------------------------------------------------
    // Helper methods
    //---------------------------------------------------------------------

    private boolean isFormValid() {
        Map<EditText, String> valueMap = Maps.newHashMap();
        valueMap.put(aliasEdit, alias);
        valueMap.put(serverUrlEdit, serverUrl);
        valueMap.put(usernameEdit, username);

        if (!askPasswordCheckBox.isChecked()) {
            valueMap.put(passwordEdit, password);
        }

        boolean isFieldValid;
        boolean formValid = true;
        for (Map.Entry<EditText, String> entry : valueMap.entrySet()) {
            isFieldValid = !TextUtils.isEmpty(entry.getValue()) && !TextUtils.isEmpty(entry.getValue().trim());
            if (!isFieldValid) {
                entry.getKey().setError(getString(R.string.sp_error_field_required));
                entry.getKey().requestFocus();
            }
            formValid &= isFieldValid;
        }

        if (!TextUtils.isEmpty(serverUrl)) {
            String url = trimUrl(serverUrl);
            if (!URLUtil.isNetworkUrl(url)) {
                serverUrlEdit.setError(getString(R.string.sp_error_url_not_valid));
                serverUrlEdit.requestFocus();
                formValid &= false;
            }
        }

        return formValid;
    }

    private void setSubmitActionState() {
        List<String> values = Lists.newArrayList(alias, serverUrl, username);
        if (!askPasswordCheckBox.isChecked()) {
            values.add(password);
        }
        boolean enabled = true;
        for (String value : values) {
            enabled &= !TextUtils.isEmpty(value) && !TextUtils.isEmpty(value.trim());
        }

        if (!TextUtils.isEmpty(serverUrl)) {
            String url = trimUrl(serverUrl);
            enabled &= URLUtil.isNetworkUrl(url);
        }

        if (saveAction != null) {
            saveAction.setIcon(enabled ? R.drawable.ic_action_submit : R.drawable.ic_action_submit_disabled);
        }
    }

    private String trimUrl(String url) {
        if (!TextUtils.isEmpty(url) && url.endsWith("/")) {
            url = url.substring(0, url.length() - 1);
        }
        return url;
    }

    @UiThread
    protected void updateProfileFields(Cursor cursor) {
        mServerProfile = new ServerProfiles(cursor);
        mLoadedProfile = new ServerProfiles(cursor);

        if (getActionBar() != null) {
            getActionBar().setTitle(getString(R.string.sp_bc_edit_profile));
            getActionBar().setSubtitle(mServerProfile.getAlias());
        }

        aliasEdit.setText(mServerProfile.getAlias());
        serverUrlEdit.setText(mServerProfile.getServerUrl());
        organizationEdit.setText(mServerProfile.getOrganization());
        usernameEdit.setText(mServerProfile.getUsername());

        String password = mServerProfile.getPassword();
        boolean hasPassword = !TextUtils.isEmpty(password);
        passwordEdit.setEnabled(hasPassword);
        passwordEdit.setFocusable(hasPassword);
        passwordEdit.setFocusableInTouchMode(hasPassword);
        passwordEdit.setText(password);

        askPasswordCheckBox.setChecked(!hasPassword);
    }

    // TODO: Dirty way to check unique value. Need provide pull request to RoboCop.
    @UiThread
    protected void checkUniqueConstraintFulfilled(Cursor cursor) {
        boolean entryExists = cursor.getCount() > 0;
        getSupportLoaderManager().destroyLoader(QUERY_UNIQUENESS);

        if (entryExists) {
            aliasEdit.setError(getString(R.string.sp_error_duplicate_alias));
            aliasEdit.requestFocus();

            Toast toast = Toast.makeText(this, getString(R.string.sp_error_unique_alias, alias),
                    Toast.LENGTH_SHORT);
            toast.setGravity(Gravity.TOP | Gravity.CENTER, 0, mActionBarSize + (mActionBarSize / 2));
            toast.show();
        } else {
            JsServerProfile oldProfile = jsRestClient.getServerProfile();
            if (oldProfile != null && oldProfile.getId() == profileId) {
                updateServerProfile(oldProfile);
            } else {
                persistProfileData();
                setOkResult();
                finish();
            }

            hideKeyboard();
        }
    }

    private void updateServerProfile(JsServerProfile oldProfile) {
        saveAction.setActionView(R.layout.actionbar_indeterminate_progress);
        JasperMobileApplication.removeAllCookies();

        JsServerProfile newProfile = new JsServerProfile();
        newProfile.setId(profileId);
        newProfile.setAlias(alias);
        newProfile.setServerUrl(serverUrl);
        newProfile.setOrganization(organization);
        newProfile.setUsername(username);
        newProfile.setPassword(password);

        if (needUpdateProfile()) {
            if (askPasswordCheckBox.isChecked()) {
                // We can`t validate profile on server side without password
                // so we are explicitly saving it!
                jsRestClient.setServerProfile(newProfile);
                persistProfileData();
                setOkResult();
                finish();
            } else {
                // Alter update only for changes
                jsRestClient.setServerProfile(newProfile);

                getSpiceManager().execute(new GetServerInfoRequest(jsRestClient),
                        new ValidateServerInfoListener(oldProfile));
            }
        } else {
            // Otherwise close the instance
            profileId = oldProfile.getId();
            setOkResult();
            finish();
        }
    }

    private boolean needUpdateProfile() {
        ServerProfiles newProfile = mServerProfile;
        ServerProfiles oldProfile = mLoadedProfile;
        return !oldProfile.getContentValues().equals(newProfile.getContentValues());
    }

    private void persistProfileData() {
        if (profileId == 0) {
            Uri uri = getContentResolver().insert(JasperMobileDbProvider.SERVER_PROFILES_CONTENT_URI,
                    mServerProfile.getContentValues());
            profileId = Long.valueOf(uri.getLastPathSegment());
            Toast.makeText(this, getString(R.string.spm_profile_created_toast, alias), Toast.LENGTH_LONG).show();
        } else {
            String selection = ServerProfilesTable._ID + " =?";
            String[] selectionArgs = { String.valueOf(profileId) };
            getContentResolver().update(JasperMobileDbProvider.SERVER_PROFILES_CONTENT_URI,
                    mServerProfile.getContentValues(), selection, selectionArgs);
            Toast.makeText(this, getString(R.string.spm_profile_updated_toast, alias), Toast.LENGTH_LONG).show();
        }
        getContentResolver().notifyChange(JasperMobileDbProvider.SERVER_PROFILES_CONTENT_URI, null);
    }

    private void setOkResult() {
        Intent resultIntent = new Intent();
        resultIntent.putExtra(ServersFragment.EXTRA_SERVER_PROFILE_ID, profileId);
        setResult(Activity.RESULT_OK, resultIntent);
    }

    private void hideKeyboard() {
        View view = getCurrentFocus();
        if (view != null) {
            inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
        }
    }

    //---------------------------------------------------------------------
    // Nested Classes
    //---------------------------------------------------------------------

    private class ValidateServerInfoListener extends CommonRequestListener<ServerInfo> {
        private final JsServerProfile mOldProfile;

        ValidateServerInfoListener(JsServerProfile oldProfile) {
            super();
            // We will handle this rule manually
            removeRule(ExceptionRule.UNAUTHORIZED);
            mOldProfile = oldProfile;
        }

        @Override
        public void onSemanticFailure(SpiceException spiceException) {
            // Reset back to old profile
            jsRestClient.setServerProfile(mOldProfile);
            saveAction.setActionView(null);

            HttpStatus statusCode = extractStatusCode(spiceException);
            if (statusCode != null && statusCode == HttpStatus.UNAUTHORIZED) {
                AlertDialogFragment.createBuilder(ServerProfileActivity.this, getSupportFragmentManager())
                        .setIcon(android.R.drawable.ic_dialog_alert).setTitle(R.string.error_msg)
                        .setMessage(ExceptionRule.UNAUTHORIZED.getMessage())
                        .setNegativeButtonText(android.R.string.ok).show();
            }
        }

        @Override
        public void onSemanticSuccess(ServerInfo serverInfo) {
            saveAction.setActionView(null);

            Context context = ServerProfileActivity.this;
            double currentVersion = serverInfo.getVersionCode();
            if (currentVersion < ServerInfo.VERSION_CODES.EMERALD_TWO) {
                // Reset back to old profile
                jsRestClient.setServerProfile(mOldProfile);

                AlertDialogFragment.createBuilder(context, getSupportFragmentManager())
                        .setIcon(android.R.drawable.ic_dialog_alert).setTitle(R.string.error_msg)
                        .setMessage(R.string.r_error_server_not_supported).show();
            } else {
                // Lets update current profile instance in database with ServerInfo
                mServerProfile.setVersioncode(serverInfo.getVersionCode());
                mServerProfile.setEdition(serverInfo.getEdition());

                persistProfileData();
                setOkResult();
                finish();
            }
        }

        @Override
        public Activity getCurrentActivity() {
            return ServerProfileActivity.this;
        }
    }

}