com.evolveum.midpoint.web.page.admin.reports.component.RunReportPopupPanel.java Source code

Java tutorial

Introduction

Here is the source code for com.evolveum.midpoint.web.page.admin.reports.component.RunReportPopupPanel.java

Source

/*
 * Copyright (c) 2010-2017 Evolveum
 *
 * 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.reports.component;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import javax.xml.datatype.XMLGregorianCalendar;
import javax.xml.namespace.QName;

import org.apache.commons.lang3.StringUtils;
import org.apache.wicket.Component;
import org.apache.wicket.RestartResponseException;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.feedback.ComponentFeedbackMessageFilter;
import org.apache.wicket.feedback.FeedbackMessage;
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.form.FormComponent;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.model.StringResourceModel;

import com.evolveum.midpoint.audit.api.AuditEventStage;
import com.evolveum.midpoint.audit.api.AuditEventType;
import com.evolveum.midpoint.gui.api.component.BasePanel;
import com.evolveum.midpoint.gui.api.component.autocomplete.AutoCompleteTextPanel;
import com.evolveum.midpoint.gui.api.model.LoadableModel;
import com.evolveum.midpoint.gui.api.page.PageBase;
import com.evolveum.midpoint.gui.api.util.WebComponentUtil;
import com.evolveum.midpoint.prism.PrismContainer;
import com.evolveum.midpoint.prism.PrismContainerDefinition;
import com.evolveum.midpoint.prism.PrismContainerValue;
import com.evolveum.midpoint.prism.PrismContext;
import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.prism.PrismProperty;
import com.evolveum.midpoint.prism.PrismPropertyDefinitionImpl;
import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.prism.polystring.PolyString;
import com.evolveum.midpoint.prism.query.ObjectQuery;
import com.evolveum.midpoint.prism.query.builder.QueryBuilder;
import com.evolveum.midpoint.report.api.ReportConstants;
import com.evolveum.midpoint.schema.GetOperationOptions;
import com.evolveum.midpoint.schema.SelectorOptions;
import com.evolveum.midpoint.schema.constants.SchemaConstants;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.security.api.MidPointPrincipal;
import com.evolveum.midpoint.task.api.Task;
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.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
import com.evolveum.midpoint.web.component.AjaxSubmitButton;
import com.evolveum.midpoint.web.component.dialog.Popupable;
import com.evolveum.midpoint.web.component.input.DatePanel;
import com.evolveum.midpoint.web.component.input.TextPanel;
import com.evolveum.midpoint.web.component.message.FeedbackAlerts;
import com.evolveum.midpoint.web.component.prism.InputPanel;
import com.evolveum.midpoint.web.component.util.VisibleEnableBehaviour;
import com.evolveum.midpoint.web.model.LookupPropertyModel;
import com.evolveum.midpoint.web.page.admin.configuration.component.EmptyOnBlurAjaxFormUpdatingBehaviour;
import com.evolveum.midpoint.web.page.admin.reports.dto.JasperReportParameterDto;
import com.evolveum.midpoint.web.page.admin.reports.dto.JasperReportParameterPropertiesDto;
import com.evolveum.midpoint.web.page.admin.reports.dto.JasperReportValueDto;
import com.evolveum.midpoint.web.page.admin.reports.dto.ReportDto;
import com.evolveum.midpoint.web.security.SecurityUtils;
import com.evolveum.midpoint.xml.ns._public.common.audit_3.AuditEventStageType;
import com.evolveum.midpoint.xml.ns._public.common.audit_3.AuditEventTypeType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.LookupTableRowType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.LookupTableType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ReportParameterType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ReportType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType;
import com.evolveum.prism.xml.ns._public.types_3.PolyStringType;

public class RunReportPopupPanel extends BasePanel<ReportDto> implements Popupable {

    private static final long serialVersionUID = 1L;

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

    private static final String DOT_CLASS = RunReportPopupPanel.class.getName() + ".";
    private static final String OPERATION_LOAD_RESOURCES = DOT_CLASS + "createResourceList";

    private static final String ID_MAIN_FORM = "mainForm";

    private static final String ID_RUN = "runReport";
    private static final String ID_POPUP_FEEDBACK = "popupFeedback";

    private static final Integer AUTO_COMPLETE_BOX_SIZE = 10;

    private static final String ID_VALUE_LIST = "valueList";
    private static final String ID_ADD_BUTTON = "add";
    private static final String ID_REMOVE_BUTTON = "remove";

    private static final String ID_PARAMETERS = "paramTable";

    private IModel<ReportDto> reportModel;

    public RunReportPopupPanel(String id, final ReportType reportType) {
        super(id);

        reportModel = new LoadableModel<ReportDto>(false) {

            private static final long serialVersionUID = 1L;

            @Override
            protected ReportDto load() {
                return new ReportDto(reportType, true);
            }
        };

        initLayout();
    }

    protected void initLayout() {

        Form<?> mainForm = new com.evolveum.midpoint.web.component.form.Form<>(ID_MAIN_FORM);
        add(mainForm);

        ListView<JasperReportParameterDto> paramListView = new ListView<JasperReportParameterDto>(ID_PARAMETERS,
                new PropertyModel<>(reportModel, "jasperReportDto.parameters")) {

            private static final long serialVersionUID = 1L;

            @Override
            protected void populateItem(ListItem<JasperReportParameterDto> paramItem) {
                paramItem.add(createParameterPanel(paramItem.getModel()));

            }
        };
        paramListView.setOutputMarkupId(true);
        mainForm.add(paramListView);

        FeedbackAlerts feedback = new FeedbackAlerts(ID_POPUP_FEEDBACK);
        feedback.setFilter(new ComponentFeedbackMessageFilter(paramListView) {

            private static final long serialVersionUID = 1L;

            @Override
            public boolean accept(FeedbackMessage message) {
                return true;
            }
        });
        feedback.setOutputMarkupId(true);
        mainForm.add(feedback);

        AjaxSubmitButton addButton = new AjaxSubmitButton(ID_RUN,
                createStringResource("runReportPopupContent.button.run")) {
            private static final long serialVersionUID = 1L;

            @Override
            protected void onError(AjaxRequestTarget target, Form<?> form) {
                FeedbackAlerts feedback = (FeedbackAlerts) form.get(ID_POPUP_FEEDBACK);
                target.add(feedback);
            }

            @Override
            protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
                runConfirmPerformed(target, reportModel);
            }
        };
        mainForm.add(addButton);

    }

    private WebMarkupContainer createParameterPanel(final IModel<JasperReportParameterDto> parameterModel) {
        WebMarkupContainer paramPanel = new WebMarkupContainer("paramPanel");
        paramPanel.setOutputMarkupId(true);
        String paramValue = new PropertyModel<String>(parameterModel, "name").getObject();
        StringResourceModel paramDisplay = PageBase.createStringResourceStatic(RunReportPopupPanel.this,
                "runReportPopupContent.param.name." + paramValue, new Object[] {});

        paramPanel.add(new Label("name", paramDisplay)); // use display name rather than property name

        String paramClass = new PropertyModel<String>(parameterModel, "nestedTypeAsString").getObject();
        if (StringUtils.isBlank(paramClass)) {
            paramClass = new PropertyModel<String>(parameterModel, "typeAsString").getObject();
        }
        paramClass = paramClass == null ? "" : paramClass.substring(paramClass.lastIndexOf(".") + 1);
        paramPanel.add(new Label("type", paramClass));

        ListView<JasperReportValueDto> listView = new ListView<JasperReportValueDto>(ID_VALUE_LIST,
                new PropertyModel<>(parameterModel, "value")) {

            private static final long serialVersionUID = 1L;

            @Override
            protected void populateItem(ListItem<JasperReportValueDto> item) {
                item.add(createInputMarkup(item.getModel(), parameterModel.getObject()));

            }

        };
        listView.setOutputMarkupId(true);

        paramPanel.add(listView);
        return paramPanel;
    }

    private WebMarkupContainer createInputMarkup(final IModel<JasperReportValueDto> valueModel,
            JasperReportParameterDto param) {
        param.setEditing(true);
        WebMarkupContainer paramValueMarkup = new WebMarkupContainer("valueMarkup");
        paramValueMarkup.setOutputMarkupId(true);

        InputPanel input = createTypedInputPanel("inputValue", valueModel, "value", param);
        paramValueMarkup.add(input);

        //buttons
        AjaxLink<String> addButton = new AjaxLink<String>(ID_ADD_BUTTON) {
            private static final long serialVersionUID = 1L;

            @Override
            public void onClick(AjaxRequestTarget target) {
                addValue(paramValueMarkup, param, target);
            }
        };
        addButton.add(new VisibleEnableBehaviour() {
            private static final long serialVersionUID = 1L;

            @Override
            public boolean isVisible() {
                return isAddButtonVisible(param);
            }
        });
        paramValueMarkup.add(addButton);

        AjaxLink<String> removeButton = new AjaxLink<String>(ID_REMOVE_BUTTON) {
            private static final long serialVersionUID = 1L;

            @Override
            public void onClick(AjaxRequestTarget target) {
                removeValue(paramValueMarkup, param, valueModel.getObject(), target);
            }
        };
        removeButton.add(new VisibleEnableBehaviour() {
            private static final long serialVersionUID = 1L;

            @Override
            public boolean isVisible() {
                return isRemoveButtonVisible();
            }
        });
        paramValueMarkup.add(removeButton);
        return paramValueMarkup;
    }

    private InputPanel createTypedInputPanel(String componentId, IModel<JasperReportValueDto> model,
            String expression, JasperReportParameterDto param) {
        InputPanel panel;
        Class<?> type;
        try {
            if (param.isMultiValue()) {
                type = param.getNestedType();
            } else {
                type = param.getType();
            }
        } catch (ClassNotFoundException e) {
            getSession().error("Could not find parameter type definition. Check the configuration.");
            throw new RestartResponseException(getPageBase());
        }

        if (type.isEnum()) {
            panel = WebComponentUtil.createEnumPanel(type, componentId, new PropertyModel<>(model, expression),
                    this);
        } else if (XMLGregorianCalendar.class.isAssignableFrom(type)) {
            panel = new DatePanel(componentId, new PropertyModel<>(model, expression));
        } else if (param.getProperties() != null && param.getProperties().getTargetType() != null) { // render autocomplete box
            LookupTableType lookup = new LookupTableType();
            panel = new AutoCompleteTextPanel<String>(componentId,
                    new LookupReportPropertyModel(model, expression, lookup, true), String.class) {

                private static final long serialVersionUID = 1L;

                @Override
                public Iterator<String> getIterator(String input) {
                    return prepareAutoCompleteList(input, lookup, param).iterator();
                }
            };
        } else {
            panel = new TextPanel<>(componentId, new PropertyModel<>(model, expression), type);
        }
        List<FormComponent> components = panel.getFormComponents();
        for (FormComponent component : components) {
            component.add(new EmptyOnBlurAjaxFormUpdatingBehaviour());
        }

        panel.setOutputMarkupId(true);
        return panel;
    }

    private void addValue(WebMarkupContainer paramValueMarkup, JasperReportParameterDto valueModel,
            AjaxRequestTarget target) {
        valueModel.addValue();
        //reload just current parameter container panel
        target.add(paramValueMarkup.findParent(ListView.class).findParent(WebMarkupContainer.class));
    }

    private ListView getParametersView() {
        return (ListView) get(createComponentPath(ID_MAIN_FORM, ID_PARAMETERS));
    }

    private boolean isAddButtonVisible(JasperReportParameterDto valueDecs) {
        try {
            return valueDecs.isMultiValue();
        } catch (ClassNotFoundException e) {
            return false;
        }
    }

    private void removeValue(WebMarkupContainer paramValueMarkup, JasperReportParameterDto valueModel,
            JasperReportValueDto object, AjaxRequestTarget target) {
        valueModel.removeValue(object);
        //reload just current parameter container panel
        target.add(paramValueMarkup.findParent(ListView.class).findParent(WebMarkupContainer.class));
    }

    private boolean isRemoveButtonVisible() {
        return true;
    }

    private <O extends ObjectType> List<LookupTableRowType> createLookupTableRows(JasperReportParameterDto param,
            String input) {
        ItemPath label = null;
        ItemPath key = null;
        List<LookupTableRowType> rows = new ArrayList<>();

        JasperReportParameterPropertiesDto properties = param.getProperties();

        if (properties == null) {
            return null;
        }

        String pLabel = properties.getLabel();
        if (pLabel != null) {
            label = new ItemPath(pLabel);
        }
        String pKey = properties.getKey();
        if (pKey != null) {
            key = new ItemPath(pKey);
        }

        String pTargetType = properties.getTargetType();
        Class<O> targetType = null;
        if (pTargetType != null) {
            try {
                targetType = (Class<O>) Class.forName(pTargetType);
            } catch (ClassNotFoundException e) {
                error("Error while creating lookup table for input parameter: " + param.getName() + ", "
                        + e.getClass().getSimpleName() + " (" + e.getMessage() + ")");

            }
        }

        if (label != null && targetType != null && input != null) {
            OperationResult result = new OperationResult(OPERATION_LOAD_RESOURCES);
            Task task = createSimpleTask(OPERATION_LOAD_RESOURCES);

            Collection<PrismObject<O>> objects;
            ObjectQuery query = QueryBuilder.queryFor(targetType, getPrismContext())
                    .item(new QName(SchemaConstants.NS_C, pLabel)).startsWith(input)
                    .matching(new QName(SchemaConstants.NS_MATCHING_RULE, "origIgnoreCase"))
                    .maxSize(AUTO_COMPLETE_BOX_SIZE).build();
            try {
                objects = getPageBase().getModelService().searchObjects(targetType, query,
                        SelectorOptions.createCollection(GetOperationOptions.createNoFetch()), task, result);

                for (PrismObject<O> o : objects) {
                    Object realKeyValue = null;
                    PrismProperty<?> labelItem = o.findProperty(label);

                    //TODO: e.g. support not only for property, but also ref, container..
                    if (labelItem == null || labelItem.isEmpty()) {
                        continue;
                    }
                    PrismProperty<?> keyItem = o.findProperty(key);
                    if ("oid".equals(pKey)) {
                        realKeyValue = o.getOid();
                    }
                    if (realKeyValue == null && (keyItem == null || keyItem.isEmpty())) {
                        continue;
                    }

                    //TODO: support for single/multivalue value
                    if (!labelItem.isSingleValue()) {
                        continue;
                    }

                    Object realLabelValue = labelItem.getRealValue();
                    realKeyValue = (realKeyValue == null) ? keyItem.getRealValue() : realKeyValue;

                    // TODO: take definition into account
                    //                    QName typeName = labelItem.getDefinition().getTypeName();

                    LookupTableRowType row = new LookupTableRowType();

                    if (realKeyValue != null) {
                        row.setKey(convertObjectToPolyStringType(realKeyValue).getOrig());
                    } else {
                        throw new SchemaException(
                                "Cannot create lookup table with null key for label: " + realLabelValue);
                    }

                    row.setLabel(convertObjectToPolyStringType(realLabelValue));

                    rows.add(row);
                }

                return rows;
            } catch (SchemaException | ObjectNotFoundException | SecurityViolationException | CommunicationException
                    | ConfigurationException | ExpressionEvaluationException e) {
                error("Error while creating lookup table for input parameter: " + param.getName() + ", "
                        + e.getClass().getSimpleName() + " (" + e.getMessage() + ")");
            }

        }
        return rows;
    }

    private PolyStringType convertObjectToPolyStringType(Object o) {
        if (o instanceof PolyString) {
            return new PolyStringType((PolyString) o);
        } else if (o instanceof PolyStringType) {
            return (PolyStringType) o;
        } else if (o instanceof String) {
            return new PolyStringType((String) o);
        } else {
            return new PolyStringType(o.toString());
        }
    }

    private List<String> prepareAutoCompleteList(String input, LookupTableType lookupTable,
            JasperReportParameterDto param) {
        List<String> values = new ArrayList<>();

        if (lookupTable == null) {
            return values;
        }

        List<LookupTableRowType> rows = createLookupTableRows(param, input);

        if (rows == null) {
            return values;
        }
        if (lookupTable.getRow() != null) {
            lookupTable.getRow().addAll(rows);
        }

        for (LookupTableRowType row : rows) {
            values.add(WebComponentUtil.getOrigStringFromPoly(row.getLabel()));

            if (values.size() > AUTO_COMPLETE_BOX_SIZE) {
                break;
            }
        }

        return values;
    }

    public Task createSimpleTask(String operation, PrismObject<UserType> owner) {
        Task task = getPageBase().getTaskManager().createTaskInstance(operation);

        if (owner == null) {
            MidPointPrincipal user = SecurityUtils.getPrincipalUser();
            if (user == null) {
                return task;
            } else {
                owner = user.getUser().asPrismObject();
            }
        }

        task.setOwner(owner);
        task.setChannel(SchemaConstants.CHANNEL_GUI_USER_URI);

        return task;
    }

    public Task createSimpleTask(String operation) {
        MidPointPrincipal user = SecurityUtils.getPrincipalUser();
        return createSimpleTask(operation, user != null ? user.getUser().asPrismObject() : null);
    }

    private void runConfirmPerformed(AjaxRequestTarget target, IModel<ReportDto> model) {
        ReportDto reportDto = model.getObject();

        PrismContainerDefinition<ReportParameterType> paramContainerDef = getPrismContext().getSchemaRegistry()
                .findContainerDefinitionByElementName(ReportConstants.REPORT_PARAMS_PROPERTY_NAME);
        PrismContainer<ReportParameterType> paramContainer;
        try {
            paramContainer = paramContainerDef.instantiate();
            ReportParameterType reportParam = new ReportParameterType();
            PrismContainerValue<ReportParameterType> reportParamValue = reportParam.asPrismContainerValue();
            reportParamValue.revive(getPrismContext());
            paramContainer.add(reportParamValue);

            List<JasperReportParameterDto> params = getParametersView().getModelObject();
            for (JasperReportParameterDto paramDto : params) {
                if (paramDto.getValue() == null) {
                    continue;
                }
                List<JasperReportValueDto> values = paramDto.getValue();
                Class<?> paramClass = paramDto.getType();

                boolean multivalue = false;
                if (List.class.isAssignableFrom(paramClass)) {
                    paramClass = paramDto.getNestedType();
                    if (paramClass == null) {
                        getSession().error("Nested type for list must be defined!");
                        target.add(getPageBase().getFeedbackPanel());
                        return;
                    }
                }

                QName typeName = getPrismContext().getSchemaRegistry().determineTypeForClass(paramClass);
                PrismPropertyDefinitionImpl<?> def = new PrismPropertyDefinitionImpl<>(
                        new QName(ReportConstants.NS_EXTENSION, paramDto.getName()), typeName, getPrismContext());
                def.setDynamic(true);
                def.setRuntimeSchema(true);
                def.setMaxOccurs(multivalue ? -1 : 1); // TODO multivalue is always 'false' here ...

                PrismProperty prop = def.instantiate();
                for (JasperReportValueDto paramValue : values) {
                    Object realValue = paramValue.getValue();
                    if (realValue == null) {
                        continue;
                    }
                    if (AuditEventType.class.isAssignableFrom(paramClass)) {
                        paramClass = AuditEventTypeType.class;
                        realValue = AuditEventType.fromAuditEventType((AuditEventType) realValue);
                    } else if (AuditEventStage.class.isAssignableFrom(paramClass)) {
                        paramClass = AuditEventStageType.class;
                        realValue = AuditEventStage.fromAuditEventStage((AuditEventStage) realValue);
                    }

                    prop.addRealValue(realValue);
                }
                if (!prop.isEmpty()) {
                    reportParamValue.add(prop);
                }
            }
        } catch (SchemaException | ClassNotFoundException e) {
            OperationResult result = new OperationResult("Parameters serialization");
            result.recordFatalError("Could not serialize parameters");
            getPageBase().showResult(result);
            return;
        }

        runConfirmPerformed(target, reportDto.getObject().asObjectable(), paramContainer);
    }

    private PrismContext getPrismContext() {
        return getPageBase().getPrismContext();
    }

    protected void runConfirmPerformed(AjaxRequestTarget target, ReportType reportType2,
            PrismContainer<ReportParameterType> reportParam) {
    }

    @Override
    public int getWidth() {
        return 1150;
    }

    @Override
    public int getHeight() {
        return 560;
    }

    @Override
    public StringResourceModel getTitle() {
        return createStringResource("RunReportPopupPanel.title");
    }

    @Override
    public Component getComponent() {
        return this;
    }

    static class LookupReportPropertyModel extends LookupPropertyModel<String> {

        private static final long serialVersionUID = 1L;

        public LookupReportPropertyModel(IModel<JasperReportValueDto> modelObject, String expression,
                LookupTableType lookupTable, boolean isStrict) {
            super(modelObject, expression, lookupTable, isStrict);
        }

        @Override
        public boolean isSupportsDisplayName() {
            return true;
        }

    }

}