com.evolveum.midpoint.web.page.admin.cases.PageCaseWorkItems.java Source code

Java tutorial

Introduction

Here is the source code for com.evolveum.midpoint.web.page.admin.cases.PageCaseWorkItems.java

Source

/*
 * Copyright (c) 2010-2018 Evolveum et al.
 *
 * 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.evolveum.midpoint.web.page.admin.cases;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.function.Function;

import javax.xml.datatype.XMLGregorianCalendar;

import org.apache.wicket.AttributeModifier;
import org.apache.wicket.Component;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder;
import org.apache.wicket.extensions.markup.html.repeater.data.table.DataTable;
import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.panel.Fragment;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.markup.repeater.Item;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.request.mapper.parameter.PageParameters;

import com.evolveum.midpoint.gui.api.page.PageBase;
import com.evolveum.midpoint.gui.api.util.WebComponentUtil;
import com.evolveum.midpoint.model.api.ModelAuthorizationAction;
import com.evolveum.midpoint.prism.PrismConstants;
import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.prism.query.ObjectQuery;
import com.evolveum.midpoint.prism.query.builder.S_FilterEntryOrEmpty;
import com.evolveum.midpoint.schema.util.ObjectTypeUtil;
import com.evolveum.midpoint.util.exception.CommunicationException;
import com.evolveum.midpoint.util.exception.ConfigurationException;
import com.evolveum.midpoint.util.exception.ExpressionEvaluationException;
import com.evolveum.midpoint.util.exception.ObjectNotFoundException;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.util.exception.SecurityViolationException;
import com.evolveum.midpoint.util.exception.SystemException;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
import com.evolveum.midpoint.web.component.AjaxButton;
import com.evolveum.midpoint.web.component.DateLabelComponent;
import com.evolveum.midpoint.web.component.data.BoxedTablePanel;
import com.evolveum.midpoint.web.component.data.Table;
import com.evolveum.midpoint.web.component.data.column.IsolatedCheckBoxPanel;
import com.evolveum.midpoint.web.component.data.column.LinkColumn;
import com.evolveum.midpoint.web.component.form.multivalue.MultiValueChoosePanel;
import com.evolveum.midpoint.web.component.util.VisibleEnableBehaviour;
import com.evolveum.midpoint.web.page.admin.cases.dto.CaseWorkItemDto;
import com.evolveum.midpoint.web.page.admin.cases.dto.CaseWorkItemDtoProvider;
import com.evolveum.midpoint.web.page.admin.cases.dto.SearchingUtils;
import com.evolveum.midpoint.web.page.admin.dto.ObjectViewDto;
import com.evolveum.midpoint.web.page.admin.reports.component.SingleValueChoosePanel;
import com.evolveum.midpoint.web.security.SecurityUtils;
import com.evolveum.midpoint.web.session.UserProfileStorage;
import com.evolveum.midpoint.web.util.TooltipBehavior;
import com.evolveum.midpoint.wf.util.QueryUtils;
import com.evolveum.midpoint.xml.ns._public.common.common_3.CaseType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.CaseWorkItemType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.OtherPrivilegesLimitationType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType;

/**
 * @author bpowers
 */
public abstract class PageCaseWorkItems extends PageAdminCaseWorkItems {
    private static final long serialVersionUID = 1L;

    private static final Trace LOGGER = TraceManager.getTrace(PageCaseWorkItems.class);

    private static final String DOT_CLASS = PageCaseWorkItems.class.getName() + ".";
    private static final String PARAMETER_CASE_ID = "caseId";
    private static final String PARAMETER_CASE_WORK_ITEM_ID = "caseWorkItemId";

    // Search Form
    private static final String ID_SEARCH_FILTER_FORM = "searchFilterForm";
    private static final String ID_SEARCH_FILTER_RESOURCE = "filterResource";
    private static final String ID_SEARCH_FILTER_ASSIGNEE_CONTAINER = "filterAssigneeContainer";
    private static final String ID_SEARCH_FILTER_ASSIGNEE = "filterAssignee";
    private static final String ID_SEARCH_FILTER_INCLUDE_CLOSED_CASES = "filterIncludeClosedCases";
    // Data Table
    private static final String ID_CASE_WORK_ITEMS_TABLE = "caseWorkItemsTable";
    private static final String ID_BUTTON_BAR = "buttonBar";
    // Buttons
    private static final String ID_CREATE_CASE_BUTTON = "createCaseButton";

    private boolean all;

    public PageCaseWorkItems(boolean all) {
        this.all = all;
        initLayout();
    }

    //region Data
    private CaseWorkItemDtoProvider createProvider() {
        CaseWorkItemDtoProvider provider = new CaseWorkItemDtoProvider(PageCaseWorkItems.this);
        try {
            provider.setQuery(createQuery());
        } catch (SchemaException | ObjectNotFoundException | ExpressionEvaluationException | CommunicationException
                | ConfigurationException | SecurityViolationException e) {
            // TODO handle more cleanly
            throw new SystemException("Couldn't create case work item query", e);
        }
        provider.setSort(SearchingUtils.WORK_ITEM_DEADLINE, SortOrder.ASCENDING);// default sorting
        return provider;
    }

    private ObjectQuery createQuery()
            throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException,
            ConfigurationException, SecurityViolationException {
        ObjectQuery query;
        boolean authorizedToSeeAll = isAuthorized(ModelAuthorizationAction.READ_ALL_WORK_ITEMS.getUrl());
        S_FilterEntryOrEmpty q = getPrismContext().queryFor(CaseWorkItemType.class);
        //        S_AtomicFilterExit query = queryStart.asc(PrismConstants.T_PARENT, CaseType.F_METADATA, MetadataType.F_CREATE_TIMESTAMP).;
        if (all && authorizedToSeeAll) {
            query = q.build();
        } else {
            // not authorized to see all => sees only allocated to him (not quite what is expected, but sufficient for the time being)
            query = QueryUtils
                    .filterForAssignees(q, SecurityUtils.getPrincipalUser(),
                            OtherPrivilegesLimitationType.F_APPROVAL_WORK_ITEMS, getRelationRegistry())
                    .and().item(CaseWorkItemType.F_CLOSE_TIMESTAMP).isNull().build();
        }
        IsolatedCheckBoxPanel includeClosedCases = (IsolatedCheckBoxPanel) getCaseWorkItemsSearchField(
                ID_SEARCH_FILTER_INCLUDE_CLOSED_CASES);
        if (includeClosedCases == null || !includeClosedCases.getValue()) {
            query.addFilter(getPrismContext().queryFor(CaseWorkItemType.class)
                    .item(PrismConstants.T_PARENT, CaseType.F_STATE).eq("open").build().getFilter());
        }

        // Resource Filter
        SingleValueChoosePanel<ObjectReferenceType, ObjectType> resourceChoice = (SingleValueChoosePanel) getCaseWorkItemsSearchField(
                ID_SEARCH_FILTER_RESOURCE);
        if (resourceChoice != null) {
            List<ObjectType> resources = resourceChoice.getModelObject();
            if (resources != null && resources.size() > 0) {
                ObjectType resource = resources.get(0);
                if (resource != null) {
                    query.addFilter(
                            // TODO MID-3581
                            getPrismContext().queryFor(CaseWorkItemType.class)
                                    .item(PrismConstants.T_PARENT, CaseType.F_OBJECT_REF).ref(ObjectTypeUtil
                                            .createObjectRef(resource, getPrismContext()).asReferenceValue())
                                    .buildFilter());
                }
            }
        }

        // Assignee Filter
        SingleValueChoosePanel<ObjectReferenceType, ObjectType> assigneeChoice = (SingleValueChoosePanel) getCaseWorkItemsSearchField(
                createComponentPath(ID_SEARCH_FILTER_ASSIGNEE_CONTAINER, ID_SEARCH_FILTER_ASSIGNEE));
        if (assigneeChoice != null) {
            List<ObjectType> assignees = assigneeChoice.getModelObject();
            if (assignees != null && assignees.size() > 0) {
                ObjectType assignee = assignees.get(0);
                if (assignee != null) {
                    // TODO MID-3581
                    query.addFilter(getPrismContext().queryFor(CaseWorkItemType.class)
                            .item(CaseWorkItemType.F_ASSIGNEE_REF)
                            .ref(ObjectTypeUtil.createObjectRef(assignee, getPrismContext()).asReferenceValue())
                            .buildFilter());
                }
            }
        }

        return query;
    }

    private String getCurrentUserOid() {
        try {
            return getSecurityContextManager().getPrincipal().getOid();
        } catch (SecurityViolationException e) {
            // TODO handle more cleanly
            throw new SystemException("Couldn't get currently logged user OID", e);
        }
    }
    //endregion

    //region Layout
    private void initLayout() {
        CaseWorkItemDtoProvider provider = createProvider();
        int itemsPerPage = (int) getItemsPerPage(UserProfileStorage.TableId.PAGE_CASE_WORK_ITEMS_PANEL);
        BoxedTablePanel<CaseWorkItemDto> table = new BoxedTablePanel<CaseWorkItemDto>(ID_CASE_WORK_ITEMS_TABLE,
                provider, initColumns(), UserProfileStorage.TableId.PAGE_CASE_WORK_ITEMS_PANEL, itemsPerPage) {

            @Override
            protected WebMarkupContainer createButtonToolbar(String id) {
                return new ButtonBar(id, ID_BUTTON_BAR, PageCaseWorkItems.this);
            }
        };
        table.setShowPaging(true);
        table.setOutputMarkupId(true);
        table.setItemsPerPage(itemsPerPage); // really don't know why this is necessary, as e.g. in PageRoles the size setting works without it
        add(table);
        initSearch();
    }

    private List<IColumn<CaseWorkItemDto, String>> initColumns() {
        List<IColumn<CaseWorkItemDto, String>> columns = new ArrayList<>();

        IColumn<CaseWorkItemDto, String> column;

        column = new LinkColumn<CaseWorkItemDto>(createStringResource("PageCaseWorkItems.table.description"),
                CaseWorkItemDto.F_DESCRIPTION) {
            @Override
            public void onClick(AjaxRequestTarget target, IModel<CaseWorkItemDto> rowModel) {
                PageParameters parameters = new PageParameters();
                parameters.add(PARAMETER_CASE_ID, rowModel.getObject().getCase().getOid());
                parameters.add(PARAMETER_CASE_WORK_ITEM_ID, rowModel.getObject().getWorkItemId());
                navigateToNext(PageCaseWorkItem.class, parameters);
            }
        };
        columns.add(column);

        column = new PropertyColumn<>(createStringResource("PageCaseWorkItems.table.objectName"),
                SearchingUtils.CASE_OBJECT_NAME, CaseWorkItemDto.F_OBJECT_NAME);
        columns.add(column);

        column = new PropertyColumn<>(createStringResource("PageCaseWorkItems.table.actor"),
                CaseWorkItemDto.F_ASSIGNEES);
        columns.add(column);

        column = new PropertyColumn<CaseWorkItemDto, String>(
                createStringResource("PageCaseWorkItems.table.openTimestamp"), SearchingUtils.CASE_OPEN_TIMESTAMP,
                CaseWorkItemDto.F_OPEN_TIMESTAMP) {
            @Override
            public void populateItem(Item<ICellPopulator<CaseWorkItemDto>> item, String componentId,
                    IModel<CaseWorkItemDto> rowModel) {
                CaseWorkItemDto dto = rowModel.getObject();
                XMLGregorianCalendar createdCal = dto.getOpenTimestamp();
                final Date created;
                if (createdCal != null) {
                    created = createdCal.toGregorianCalendar().getTime();
                    item.add(AttributeModifier.replace("title",
                            WebComponentUtil.getLocalizedDate(created, DateLabelComponent.LONG_MEDIUM_STYLE)));
                    item.add(new TooltipBehavior());
                } else {
                    created = null;
                }
                item.add(new Label(componentId, new IModel<String>() {
                    @Override
                    public String getObject() {
                        return WebComponentUtil.getLocalizedDate(created, DateLabelComponent.LONG_MEDIUM_STYLE);
                    }
                }));
            }
        };
        columns.add(column);

        column = new PropertyColumn<CaseWorkItemDto, String>(
                createStringResource("PageCaseWorkItems.table.deadline"), SearchingUtils.WORK_ITEM_DEADLINE,
                CaseWorkItemDto.F_DEADLINE) {
            @Override
            public void populateItem(Item<ICellPopulator<CaseWorkItemDto>> item, String componentId,
                    IModel<CaseWorkItemDto> rowModel) {
                CaseWorkItemDto dto = rowModel.getObject();
                XMLGregorianCalendar deadlineCal = dto.getDeadline();
                final Date deadline;
                if (deadlineCal != null) {
                    deadline = deadlineCal.toGregorianCalendar().getTime();
                    item.add(AttributeModifier.replace("title",
                            WebComponentUtil.getLocalizedDate(deadline, DateLabelComponent.LONG_MEDIUM_STYLE)));
                    item.add(new TooltipBehavior());
                } else {
                    deadline = null;
                }
                item.add(new Label(componentId, new IModel<String>() {
                    @Override
                    public String getObject() {
                        return WebComponentUtil.getLocalizedDate(deadline, DateLabelComponent.LONG_MEDIUM_STYLE);
                    }
                }));
            }
        };
        columns.add(column);

        column = new PropertyColumn<CaseWorkItemDto, String>(
                createStringResource("PageCaseWorkItems.table.closeTimestamp"),
                SearchingUtils.WORK_ITEM_CLOSE_TIMESTAMP, CaseWorkItemDto.F_CLOSE_TIMESTAMP) {
            @Override
            public void populateItem(Item<ICellPopulator<CaseWorkItemDto>> item, String componentId,
                    IModel<CaseWorkItemDto> rowModel) {
                CaseWorkItemDto dto = rowModel.getObject();
                XMLGregorianCalendar closedCal = dto.getCloseTimestamp();
                final Date closed;
                if (closedCal != null) {
                    closed = closedCal.toGregorianCalendar().getTime();
                    item.add(AttributeModifier.replace("title",
                            WebComponentUtil.getLocalizedDate(closed, DateLabelComponent.LONG_MEDIUM_STYLE)));
                    item.add(new TooltipBehavior());
                } else {
                    closed = null;
                }
                item.add(new Label(componentId, new IModel<String>() {
                    @Override
                    public String getObject() {
                        return WebComponentUtil.getLocalizedDate(closed, DateLabelComponent.LONG_MEDIUM_STYLE);
                    }
                }));
            }
        };
        columns.add(column);

        column = new PropertyColumn<>(createStringResource("PageCaseWorkItems.table.state"),
                CaseWorkItemDto.F_STATE);
        columns.add(column);

        return columns;
    }

    private Table getCaseWorkItemsTable() {
        return (Table) get(createComponentPath(ID_CASE_WORK_ITEMS_TABLE));
    }

    private Panel getCaseWorkItemsSearchField(String itemPath) {
        return (Panel) get(createComponentPath(ID_SEARCH_FILTER_FORM, itemPath));
    }

    private void initSearch() {
        final Form searchFilterForm = new Form(ID_SEARCH_FILTER_FORM);
        add(searchFilterForm);
        searchFilterForm.setOutputMarkupId(true);

        List<Class<? extends ObjectType>> allowedClasses = new ArrayList<>();
        allowedClasses.add(ResourceType.class);
        MultiValueChoosePanel<ObjectType> resource = new SingleValueChoosePanel<ObjectReferenceType, ObjectType>(
                ID_SEARCH_FILTER_RESOURCE, allowedClasses, objectReferenceTransformer,
                new PropertyModel<ObjectReferenceType>(Model.of(new ObjectViewDto()), ObjectViewDto.F_NAME)) {

            @Override
            protected void choosePerformedHook(AjaxRequestTarget target, List<ObjectType> selected) {
                super.choosePerformedHook(target, selected);
                searchFilterPerformed(target);
            }

            @Override
            protected void removePerformedHook(AjaxRequestTarget target, ObjectType value) {
                super.removePerformedHook(target, value);
                searchFilterPerformed(target);
            }
        };
        searchFilterForm.add(resource);

        allowedClasses = new ArrayList<>();
        allowedClasses.add(UserType.class);
        WebMarkupContainer assigneeContainer = new WebMarkupContainer(ID_SEARCH_FILTER_ASSIGNEE_CONTAINER);
        MultiValueChoosePanel<ObjectType> assignee = new SingleValueChoosePanel<ObjectReferenceType, ObjectType>(
                ID_SEARCH_FILTER_ASSIGNEE, allowedClasses, objectReferenceTransformer,
                new PropertyModel<ObjectReferenceType>(Model.of(new ObjectViewDto()), ObjectViewDto.F_NAME)) {

            @Override
            protected void choosePerformedHook(AjaxRequestTarget target, List<ObjectType> selected) {
                super.choosePerformedHook(target, selected);
                searchFilterPerformed(target);
            }

            @Override
            protected void removePerformedHook(AjaxRequestTarget target, ObjectType value) {
                super.removePerformedHook(target, value);
                searchFilterPerformed(target);
            }
        };
        assigneeContainer.add(assignee);
        assigneeContainer.add(new VisibleEnableBehaviour() {

            private static final long serialVersionUID = 1L;

            @Override
            public boolean isVisible() {
                return isAuthorizedToSeeAllCases();
            }
        });
        searchFilterForm.add(assigneeContainer);

        IsolatedCheckBoxPanel includeClosedCases = new IsolatedCheckBoxPanel(ID_SEARCH_FILTER_INCLUDE_CLOSED_CASES,
                new Model<Boolean>(false)) {
            private static final long serialVersionUID = 1L;

            public void onUpdate(AjaxRequestTarget target) {
                searchFilterPerformed(target);
            }
        };
        searchFilterForm.add(includeClosedCases);
    }

    private boolean isAuthorizedToSeeAllCases() {
        boolean authorizedToSeeAll;
        try {
            authorizedToSeeAll = isAuthorized(ModelAuthorizationAction.READ_ALL_WORK_ITEMS.getUrl());
            return all && authorizedToSeeAll;
        } catch (SchemaException | ObjectNotFoundException | ExpressionEvaluationException | CommunicationException
                | ConfigurationException | SecurityViolationException e) {
            // TODO handle more cleanly
            throw new SystemException("Couldn't evaluate authoriztion: " + e.getMessage(), e);
        }
    }
    //endregion

    //region Actions
    private void searchFilterPerformed(AjaxRequestTarget target) {
        ObjectQuery query;
        try {
            query = createQuery();
        } catch (SchemaException | ObjectNotFoundException | ExpressionEvaluationException | CommunicationException
                | ConfigurationException | SecurityViolationException e) {
            // TODO handle more cleanly
            throw new SystemException("Couldn't create case work item query", e);
        }

        Table panel = getCaseWorkItemsTable();
        DataTable table = panel.getDataTable();
        CaseWorkItemDtoProvider provider = (CaseWorkItemDtoProvider) table.getDataProvider();
        provider.setQuery(query);
        table.setCurrentPage(0);

        target.add(getFeedbackPanel());
        target.add((Component) getCaseWorkItemsTable());
    }
    //endregion

    private Function<ObjectType, ObjectReferenceType> objectReferenceTransformer = (Function<ObjectType, ObjectReferenceType> & Serializable) (
            ObjectType o) -> ObjectTypeUtil.createObjectRef(o, getPrismContext());

    private static class ButtonBar extends Fragment {

        private static final long serialVersionUID = 1L;

        public <O extends ObjectType> ButtonBar(String id, String markupId, PageCaseWorkItems page) {
            super(id, markupId, page);

            initLayout(page);
        }

        private <O extends ObjectType> void initLayout(final PageCaseWorkItems page) {

            AjaxButton createCase = new AjaxButton(ID_CREATE_CASE_BUTTON,
                    page.createStringResource("PageCaseWorkItems.button.createCase")) {
                @Override
                public void onClick(AjaxRequestTarget target) {
                    page.navigateToNext(PageCase.class);
                }

            };
            createCase.add(new VisibleEnableBehaviour() {
                private static final long serialVersionUID = 1L;

                @Override
                public boolean isVisible() {

                    boolean isVisible = false;
                    try {
                        PrismObject<CaseType> objectToCreate = new CaseType().asPrismObject();
                        if (objectToCreate != null) {
                            page.getMidpointApplication().getPrismContext().adopt(objectToCreate);
                        }
                        isVisible = ((PageBase) getPage()).isAuthorized(ModelAuthorizationAction.ADD.getUrl(), null,
                                objectToCreate, null, null, null);
                    } catch (SchemaException | ObjectNotFoundException | ExpressionEvaluationException
                            | CommunicationException | ConfigurationException | SecurityViolationException ex) {
                        LOGGER.error("Failed to check authorization for ADD action on new object of "
                                + CaseType.class.getSimpleName() + " type, ", ex);
                    }
                    return isVisible;
                }
            });
            createCase.add(new VisibleEnableBehaviour() {

                private static final long serialVersionUID = 1L;

                @Override
                public boolean isVisible() {
                    return page.isAuthorizedToSeeAllCases();
                }
            });
            add(createCase);
        }
    }
}