All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.tcdng.jacklyn.common.controllers.BaseCrudController Maven / Gradle / Ivy

/*
 * Copyright 2018-2019 The Code Department.
 * 
 * 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.tcdng.jacklyn.common.controllers;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import com.tcdng.jacklyn.common.constants.JacklynApplicationAttributeConstants;
import com.tcdng.jacklyn.common.constants.CommonModuleNameConstants;
import com.tcdng.jacklyn.common.data.ManagedEntityPrivilegeNames;
import com.tcdng.jacklyn.common.data.ReportOptions;
import com.tcdng.jacklyn.common.entities.BaseEntity;
import com.tcdng.jacklyn.common.utils.PageControllerSessionUtils;
import com.tcdng.jacklyn.shared.organization.PrivilegeCategoryConstants;
import com.tcdng.unify.core.UnifyContainer;
import com.tcdng.unify.core.UnifyCorePropertyConstants;
import com.tcdng.unify.core.UnifyException;
import com.tcdng.unify.core.annotation.Configurable;
import com.tcdng.unify.core.annotation.UplBinding;
import com.tcdng.unify.core.data.Describable;
import com.tcdng.unify.core.database.Entity;
import com.tcdng.unify.core.logging.EventType;
import com.tcdng.unify.core.util.DataUtils;
import com.tcdng.unify.core.util.ReflectUtils;
import com.tcdng.unify.web.DocViewController;
import com.tcdng.unify.web.annotation.Action;
import com.tcdng.unify.web.annotation.ResultMapping;
import com.tcdng.unify.web.annotation.ResultMappings;
import com.tcdng.unify.web.ui.Panel;
import com.tcdng.unify.web.ui.container.Form;
import com.tcdng.unify.web.ui.control.Table;
import com.tcdng.unify.web.ui.data.Hint.MODE;

/**
 * Convenient abstract base class for page controllers that manage CRUD actions on
 * records.
 * 
 * @author Lateef Ojulari
 * @since 1.0
 */
@UplBinding("web/common/upl/managerecord.upl")
@ResultMappings({
        @ResultMapping(
                name = BaseCrudController.HIDEPOPUP_REFERESHMAIN,
                response = { "!hidepopupresponse", "!refreshpanelresponse panels:$l{manageRecordPanel}" }),
        @ResultMapping(name = "refreshmain", response = { "!refreshpanelresponse panels:$l{manageRecordPanel}" }),
        @ResultMapping(
                name = "refreshtable",
                response = { "!refreshpanelresponse panels:$l{searchPanel tablePanel actionPanel}" }),
        @ResultMapping(name = "refreshform", response = { "!refreshpanelresponse panels:$l{crudPanel}" }),
        @ResultMapping(
                name = "switchsearch",
                response = { "!switchpanelresponse panels:$l{manageBodyPanel.searchBodyPanel}",
                        "!refreshpanelresponse panels:$l{searchPanel}" }),
        @ResultMapping(
                name = "switchcrud",
                response = { "!switchpanelresponse panels:$l{manageBodyPanel.crudPanel}",
                        "!refreshpanelresponse panels:$l{searchPanel}" }),
        @ResultMapping(
                name = "switchsearch_io",
                response = { "!switchpanelresponse panels:$l{mainResultPanel.searchResultPanel}",
                        "!refreshpanelresponse panels:$l{searchPanel}" }),
        @ResultMapping(
                name = "switchcrud_io",
                response = { "!switchpanelresponse panels:$l{mainResultPanel.crudPanel}",
                        "!refreshpanelresponse panels:$l{searchPanel}" }),
        @ResultMapping(name = "documentView", response = { "!docviewresponse" }) })
public abstract class BaseCrudController extends BasePageController
        implements DocViewController {

    public static final String HIDEPOPUP_REFERESHMAIN = "hidepopuprefreshmain";

    @Configurable("$m{common.report.norecordintable}")
    private String noRecordMessage;

    private Class entityClass;

    private int modifier;

    private int mode;

    private String itemCountLabel;

    private String modeDescription;

    private String modeStyle;

    private String reportType;

    private List recordList;

    private T record;

    private T clipRecord;

    private T oldRecord;

    private Table table;

    private String recordHintName;

    private boolean describable;

    public BaseCrudController(Class entityClass, String hint, int modifier) {
        super(ManageRecordModifier.isSecure(modifier), false);
        this.entityClass = entityClass;
        this.modifier = modifier;
        recordHintName = hint;
        describable = Describable.class.isAssignableFrom(entityClass);
    }

    @Action
    public String findRecords() throws UnifyException {
        record = null;
        recordList = find();
        table.reset();
        logUserEvent(EventType.SEARCH, entityClass);

        if (recordList != null && recordList.size() >= getContainerSetting(int.class,
                UnifyCorePropertyConstants.APPLICATION_QUERY_LIMIT, UnifyContainer.DEFAULT_APPLICATION_QUERY_LIMIT)) {
            hintUser(MODE.WARNING, "managerecord.hint.applicationquerylimit.reached");
        }

        updateSearch();
        return "refreshtable";
    }

    @Action
    public String prepareCreateRecord() throws UnifyException {
        record = prepareCreate();
        loadSessionOnCreate();
        updateForm(ManageRecordModifier.ADD);
        return "switchcrud";
    }

    @Action
    public String createAndNextRecord() throws UnifyException {
        doCreate();
        return prepareCreateRecord();
    }

    @Action
    public String createAndCloseRecord() throws UnifyException {
        doCreate();
        return done();
    }

    @Action
    public String prepareViewRecord() throws UnifyException {
        prepareView();
        logUserEvent(EventType.VIEW, record, false);
        if (ManageRecordModifier.isActivatable(modifier)) {
            oldRecord = ReflectUtils.shallowBeanCopy(record);
        }
        updateForm(ManageRecordModifier.VIEW);
        return "switchcrud";
    }

    @Action
    public String prepareUpdateRecord() throws UnifyException {
        prepareView();
        oldRecord = ReflectUtils.shallowBeanCopy(record);
        updateForm(ManageRecordModifier.MODIFY);
        return "switchcrud";
    }

    @SuppressWarnings("unchecked")
    @Action
    public String updateAndNextRecord() throws UnifyException {
        doUpdate();

        record = find((U) record.getId());
        recordList.set(table.getViewIndex(), record);

        if (table.isViewIndexAtLast()) {
            return done();
        }

        return nextRecord();
    }

    @Action
    public String updateAndCloseRecord() throws UnifyException {
        doUpdate();
        return done();
    }

    @Action
    public String prepareDeleteRecord() throws UnifyException {
        prepareView();
        updateForm(ManageRecordModifier.DELETE);
        return "switchcrud";
    }

    @Action
    public String deleteRecord() throws UnifyException {
        delete(record);
        logUserEvent(EventType.DELETE, record, false);
        hintUser("hint.record.delete.success", recordHintName);
        recordList.remove(table.getViewIndex());

        if (recordList.isEmpty()) {
            return done();
        }

        int size = recordList.size();
        if (table.getViewIndex() >= size) {
            table.setViewIndex(size - 1);
        }
        return done();
    }

    @Action
    public String activateRecord() throws UnifyException {
        activate(record);
        logUserEvent(EventType.UPDATE, oldRecord, record);
        return prepareViewRecord();
    }

    @Action
    public String deactivateRecord() throws UnifyException {
        deactivate(record);
        logUserEvent(EventType.UPDATE, oldRecord, record);
        return prepareViewRecord();
    }

    @Action
    public String copyRecord() throws UnifyException {
        clipRecord = ReflectUtils.shallowBeanCopy(record);
        if (ManageRecordModifier.isCopyToAdd(modifier)) {
            return prepareCreateRecord();
        }

        setPageAttribute("copyresponse", DataUtils.ZEROLEN_STRING_ARRAY);
        return noResult();
    }

    @Action
    public String pasteRecord() throws UnifyException {
        ReflectUtils.shallowBeanCopy(record, clipRecord);
        if (record instanceof BaseEntity) {
            ((BaseEntity) record).setId(null);
        }

        onPrepareView(record, true);
        loadSessionOnRefresh();
        return "switchcrud";
    }

    @Action
    public String firstRecord() throws UnifyException {
        onLoseView(record);
        table.setViewIndex(0);
        return performModeAction();
    }

    @Action
    public String previousRecord() throws UnifyException {
        onLoseView(record);
        table.setViewIndex(table.getViewIndex() - 1);
        return performModeAction();
    }

    @Action
    public String nextRecord() throws UnifyException {
        onLoseView(record);
        table.setViewIndex(table.getViewIndex() + 1);
        return performModeAction();
    }

    @Action
    public String lastRecord() throws UnifyException {
        onLoseView(record);
        table.setViewIndex(recordList.size() - 1);
        return performModeAction();
    }

    @Action
    public String done() throws UnifyException {
        onLoseView(record);
        findRecords();
        return "switchsearch";
    }

    @Action
    public String cancel() throws UnifyException {
        return done();
    }

    @Action
    public String refreshSearch() throws UnifyException {
        onRefreshSearch();
        return findRecords();
    }

    @Action
    public String refreshForm() throws UnifyException {
        onRefreshForm();
        loadSessionOnRefresh();
        return "refreshform";
    }

    @Action
    public String prepareGenerateReport() throws UnifyException {
        List contentList = null;
        if (mode == ManageRecordModifier.SEARCH) {
            if (recordList == null || recordList.isEmpty()) {
                return showMessageBox(noRecordMessage);
            }
            contentList = recordList;
        } else {
            if (record == null) {
                return showMessageBox(noRecordMessage);
            }
            contentList = new ArrayList();
            contentList.add(record);
        }

        ReportOptions reportOptions = getCommonReportProvider().getDynamicReportOptions(entityClass.getName(),
                table.getColumnPropertyList());
        reportOptions.setReportResourcePath("/common/resource/report");
        reportOptions.setReportFormat(reportType);
        reportOptions.setColumnarLayout(mode != ManageRecordModifier.SEARCH);
        reportOptions.setContent(contentList);
        return showReportOptionsBox(reportOptions);
    }

    @Action
    public String getRemoteDoc() throws UnifyException {
        openPage();
        return "documentView";
    }

    @Override
    public Panel getDocViewPanel() throws UnifyException {
        return getPanelByShortName("manageRecordPanel");
    }

    public List getRecordList() {
        return recordList;
    }

    public void setRecordList(List recordList) {
        this.recordList = recordList;
    }

    public T getRecord() {
        return record;
    }

    public void setRecord(T record) {
        this.record = record;
    }

    public String getItemCountLabel() {
        return itemCountLabel;
    }

    public String getModeDescription() {
        return modeDescription;
    }

    public void setModeDescription(String modeDescription) {
        this.modeDescription = modeDescription;
    }

    public String getModeStyle() {
        return modeStyle;
    }

    public String getReportType() {
        return reportType;
    }

    public void setReportType(String reportType) {
        this.reportType = reportType;
    }

    public int getModifier() {
        return modifier;
    }

    @Override
    protected void onInitialize() throws UnifyException {
        mode = ManageRecordModifier.SEARCH;
        noRecordMessage = resolveSessionMessage(noRecordMessage);
        recordHintName = resolveSessionMessage(recordHintName);
    }

    @Override
    protected void onSetPage() throws UnifyException {
        // Get reference to UPL table
        table = getPageWidgetByShortName(Table.class, "tablePanel.contentTbl");

        // Set validation page attributes
        getPage().setAttribute("validationClass", entityClass);
        getPage().setAttribute("validationIdClass", Long.class);

        manageReportable();
    }

    @Override
    protected void onIndexPage() throws UnifyException {
        super.onIndexPage();
        updateSearch();
    }

    @Override
    protected void onOpenPage() throws UnifyException {
        if (mode == ManageRecordModifier.SEARCH) {
            if ((ManageRecordModifier.SEARCH_ON_OPEN & modifier) > 0) {
                findRecords();
            }
            updateSearch();
        }
    }

    @Override
    protected void onClosePage() throws UnifyException {
        table = null;
        recordList = null;
        oldRecord = null;
        record = null;
        clipRecord = null;
    }

    protected void onLoseView(T record) throws UnifyException {
        onloadSessionOnLoseView();
    }

    protected boolean isEditable(T record) throws UnifyException {
        return true;
    }

    protected boolean isActivatable(T record) throws UnifyException {
        return false;
    }

    protected boolean isDeactivatable(T record) throws UnifyException {
        return false;
    }

    protected int activate(T record) throws UnifyException {
        return 0;
    }

    protected int deactivate(T record) throws UnifyException {
        return 0;
    }

    protected PageControllerSessionUtils getPageControllerSessionUtils() throws UnifyException {
        return (PageControllerSessionUtils) getComponent(CommonModuleNameConstants.PAGECONTROLLERSESSIONUTILS);
    }

    protected abstract List find() throws UnifyException;

    protected abstract T find(U id) throws UnifyException;

    protected abstract T prepareCreate() throws UnifyException;

    protected abstract Object create(T record) throws UnifyException;

    protected abstract int update(T record) throws UnifyException;

    protected abstract int delete(T record) throws UnifyException;

    /**
     * Returns the currently selected record from table list.
     * 
     * @throws UnifyException
     *             if an error occurs
     */
    protected T getSelectedRecord() throws UnifyException {
        return recordList.get(table.getViewIndex());
    }

    /**
     * Returns the ids of selected items in search result table.
     * 
     * @throws UnifyException
     *             if an error occurs
     */
    protected List getSelectedIds() throws UnifyException {
        if (table.getSelectedRows() > 0) {
            Integer[] selectedIndexes = table.getSelectedRowIndexes();
            List selectedIds = new ArrayList();
            for (int i = 0; i < selectedIndexes.length; i++) {
                selectedIds.add((Long) recordList.get(selectedIndexes[i]).getId());
            }
            return selectedIds;
        }
        return Collections.emptyList();
    }

    /**
     * Returns the descriptions of selected items in search result table.
     * 
     * @throws UnifyException
     *             if an error occurs
     */
    protected String[] getSelectedDescription() throws UnifyException {
        String[] selectedDescriptions = DataUtils.ZEROLEN_STRING_ARRAY;
        if (table.getSelectedRows() > 0) {
            Integer[] selectedIndexes = table.getSelectedRowIndexes();
            selectedDescriptions = new String[selectedIndexes.length];
            if (describable) {
                for (int i = 0; i < selectedIndexes.length; i++) {
                    selectedDescriptions[i] = ((Describable) recordList.get(selectedIndexes[i])).getDescription();
                }
            }
        }
        return selectedDescriptions;
    }

    protected void updateSearch() throws UnifyException {
        mode = ManageRecordModifier.SEARCH;

        // Search
        setVisible("addTblBtn", ManageRecordModifier.isAddable(modifier));
        setVisible("editTblBtn", ManageRecordModifier.isEditable(modifier));
        setVisible("viewTblBtn", ManageRecordModifier.isViewable(modifier));
        setVisible("deleteTblBtn", ManageRecordModifier.isDeletable(modifier));

        manageReportable();

        setDisabled("searchPanel", false);
        updateModeDescription();
    }

    protected void onPrepareView(T record, boolean onPaste) throws UnifyException {

    }

    protected void onPrepareForm(int mode) throws UnifyException {

    }

    protected void onRefreshSearch() throws UnifyException {

    }

    protected void onRefreshForm() throws UnifyException {

    }

    protected Table getTable() {
        return table;
    }

    protected Form getForm() throws UnifyException {
        return getPageWidgetByShortName(Form.class, "crudFormPanel.form");
    }

    protected int getMode() {
        return mode;
    }

    protected boolean isEditableMode() {
        return mode == ManageRecordModifier.ADD || mode == ManageRecordModifier.MODIFY;
    }

    @SuppressWarnings("unchecked")
    private void manageReportable() throws UnifyException {
        boolean isReportable = ManageRecordModifier.isReportable(modifier)
                && !getCommonReportProvider().isReportable(entityClass.getName());
        if (isReportable) {
            // Hide report button base on role privilege if necessary
            ManagedEntityPrivilegeNames managedPrivilegeNames =
                ((Map, ManagedEntityPrivilegeNames>) getApplicationAttribute(
                JacklynApplicationAttributeConstants.MANAGED_PRIVILEGES)).get(entityClass);
            if (managedPrivilegeNames != null) {
                isReportable = isRolePrivilege(PrivilegeCategoryConstants.REPORTABLE,
                        managedPrivilegeNames.getReportableName());
            }
        }

        setVisible("reportBtn", isReportable);
    }

    private void loadSessionOnCreate() throws UnifyException {
        getPageControllerSessionUtils().loadSession(this);
    }

    private void loadSessionOnRefresh() throws UnifyException {
        getPageControllerSessionUtils().loadSession(this);
    }

    private void onloadSessionOnLoseView() throws UnifyException {
        getPageControllerSessionUtils().unloadSession(this);
    }

    private void doCreate() throws UnifyException {
        Object id = create(record);
        if (id != null) {
            logUserEvent(EventType.CREATE, record, true);
            hintUser("hint.record.create.success", recordHintName);
        } else {
            hintUser("hint.record.createtoworkflow.success", recordHintName);
        }
    }

    private void doUpdate() throws UnifyException {
        int result = update(record);
        if (result > 0) {
            logUserEvent(EventType.UPDATE, oldRecord, record);
            hintUser("hint.record.update.success", recordHintName);
        } else {
            hintUser("hint.record.updatetoworkflow.success", recordHintName);
        }
    }

    @SuppressWarnings("unchecked")
    private void prepareView() throws UnifyException {
        int index = table.getViewIndex();
        record = find((U) recordList.get(index).getId());
        recordList.set(index, record);
        onPrepareView(record, false);
        loadSessionOnRefresh();
    }

    private void updateForm(int mode) throws UnifyException {
        this.mode = mode;

        // FormImpl Navigation buttons
        int viewIndex = table.getViewIndex();
        boolean isCreateMode = mode == ManageRecordModifier.ADD;
        setVisible("pasteFrmBtn", isCreateMode);
        setVisible("firstFrmBtn", !isCreateMode);
        setVisible("prevFrmBtn", !isCreateMode);
        setVisible("nextFrmBtn", !isCreateMode);
        setVisible("lastFrmBtn", !isCreateMode);
        setVisible("copyFrmBtn", !isCreateMode);
        setVisible("itemOfLabel", !isCreateMode);
        if (isCreateMode) {
            // FormImpl Enable/disable paste button
            setDisabled("pasteFrmBtn", clipRecord == null);
            setVisible("pasteFrmBtn", ManageRecordModifier.isPastable(modifier));
        } else {
            setDisabled("firstFrmBtn", recordList == null || viewIndex <= 0);
            setDisabled("prevFrmBtn", recordList == null || viewIndex <= 0);
            setDisabled("nextFrmBtn", recordList == null || viewIndex >= (recordList.size() - 1));
            setDisabled("lastFrmBtn", recordList == null || viewIndex >= (recordList.size() - 1));

            // For clipboard buttons
            setVisible("copyFrmBtn", ManageRecordModifier.isCopyable(modifier));
        }

        // Other buttons
        setVisible("createNextFrmBtn", false);
        setVisible("createCloseFrmBtn", false);
        setVisible("saveNextFrmBtn", false);
        setVisible("saveCloseFrmBtn", false);
        setVisible("deleteFrmBtn", false);
        setVisible("activateFrmBtn", false);
        setVisible("deactivateFrmBtn", false);
        setVisible("cancelFrmBtn", false);
        setVisible("doneFrmBtn", false);
        setPageValidationEnabled(false);

        setDisabled("searchPanel", true);

        switch (mode) {
        case ManageRecordModifier.ADD:
            setEditable("crudFormPanel.mainBodyPanel", true);
            setVisible("createNextFrmBtn", true);
            setVisible("createCloseFrmBtn", true);
            setVisible("cancelFrmBtn", true);
            setPageValidationEnabled(true);
            break;
        case ManageRecordModifier.MODIFY:
            if (ManageRecordModifier.isEditable(modifier) && record != null && !record.isReserved()
                    && isEditable(record)) {
                if (!ManageRecordModifier.isAlternateSave(modifier)) {
                    setVisible("saveNextFrmBtn", true);
                    setVisible("saveCloseFrmBtn", true);
                }
                setEditable("crudFormPanel.mainBodyPanel", true);
                setPageValidationEnabled(true);
            } else {
                setEditable("crudFormPanel.mainBodyPanel", false);
            }
            setVisible("cancelFrmBtn", true);
            break;
        case ManageRecordModifier.VIEW:
            setEditable("crudFormPanel.mainBodyPanel", false);
            setVisible("doneFrmBtn", true);
            if (ManageRecordModifier.isActivatable(modifier)) {
                setVisible("activateFrmBtn", isActivatable(record));
                setVisible("deactivateFrmBtn", isDeactivatable(record));
            }
            break;

        case ManageRecordModifier.DELETE:
            setEditable("crudFormPanel.mainBodyPanel", false);
            setVisible("deleteFrmBtn", true);
            setVisible("cancelFrmBtn", true);
            break;

        default:
            setDisabled("searchPanel", false);
            break;
        }

        // Index description
        if (recordList != null) {
            itemCountLabel = getSessionMessage("label.itemcount", viewIndex + 1, recordList.size());
        }

        updateModeDescription();
        onPrepareForm(mode);
    }

    private void updateModeDescription() throws UnifyException {
        modeDescription = null;
        switch (mode) {
        case ManageRecordModifier.ADD:
            modeDescription = "managerecord.mode.add";
            modeStyle = EventType.CREATE.colorMode();
            break;
        case ManageRecordModifier.DELETE:
            modeDescription = "managerecord.mode.delete";
            modeStyle = EventType.DELETE.colorMode();
            break;
        case ManageRecordModifier.MODIFY:
            modeDescription = "managerecord.mode.modify";
            modeStyle = EventType.UPDATE.colorMode();
            break;
        case ManageRecordModifier.VIEW:
            modeDescription = "managerecord.mode.view";
            modeStyle = EventType.VIEW.colorMode();
            break;
        case ManageRecordModifier.SEARCH:
        default:
            modeDescription = "managerecord.mode.search";
            modeStyle = EventType.SEARCH.colorMode();
            break;
        }

        modeDescription = getSessionMessage(modeDescription, recordHintName);
    }

    private String performModeAction() throws UnifyException {
        String result = null;
        switch (mode) {
        case ManageRecordModifier.ADD:
            return prepareCreateRecord();
        case ManageRecordModifier.DELETE:
            return prepareDeleteRecord();
        case ManageRecordModifier.MODIFY:
            return prepareUpdateRecord();
        case ManageRecordModifier.VIEW:
            return prepareViewRecord();
        case ManageRecordModifier.SEARCH:
            break;
        default:
            break;
        }
        return result;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy