com.evolveum.midpoint.web.page.admin.users.component.AssociationValueChoicePanel.java Source code

Java tutorial

Introduction

Here is the source code for com.evolveum.midpoint.web.page.admin.users.component.AssociationValueChoicePanel.java

Source

/*
 * Copyright (c) 2010-2016 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.users.component;

import com.evolveum.midpoint.common.refinery.RefinedAttributeDefinition;
import com.evolveum.midpoint.common.refinery.RefinedObjectClassDefinition;
import com.evolveum.midpoint.gui.api.component.BasePanel;
import com.evolveum.midpoint.gui.api.util.WebComponentUtil;
import com.evolveum.midpoint.prism.*;
import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.prism.query.InOidFilter;
import com.evolveum.midpoint.prism.query.NotFilter;
import com.evolveum.midpoint.prism.query.ObjectFilter;
import com.evolveum.midpoint.prism.query.ObjectQuery;
import com.evolveum.midpoint.schema.GetOperationOptions;
import com.evolveum.midpoint.schema.SelectorOptions;
import com.evolveum.midpoint.schema.util.ObjectTypeUtil;
import com.evolveum.midpoint.util.exception.SchemaException;
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.prism.*;
import com.evolveum.midpoint.web.component.util.VisibleEnableBehaviour;
import com.evolveum.midpoint.web.page.admin.configuration.component.ObjectSelectionPage;
import com.evolveum.midpoint.web.page.admin.configuration.component.ObjectSelectionPanel;
import com.evolveum.midpoint.web.page.admin.dto.ObjectViewDto;
import com.evolveum.midpoint.web.page.admin.roles.component.UserOrgReferenceChoosePanel;
import com.evolveum.midpoint.xml.ns._public.common.common_3.*;

import org.apache.wicket.Component;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
import org.apache.wicket.feedback.ComponentFeedbackMessageFilter;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.markup.html.panel.FeedbackPanel;
import org.apache.wicket.model.AbstractReadOnlyModel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.PropertyModel;
import org.w3c.dom.Element;

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

/**
 * Created by Kate Honchar
 *
 */
//TODO the class is created as a copy of ValueChoosePanel but
//with the possibility to work with PrismPropertyValue objects
// (for now ValueChoosePanel works only with PrismReferenceValue);
//in future some super class is to be created to union the common
// functionality of these 2 classes

public class AssociationValueChoicePanel<C extends ObjectType>
        extends BasePanel<PrismContainerValue<ShadowAssociationType>> {
    private static final long serialVersionUID = 1L;

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

    private static final String ID_TEXT_WRAPPER = "textWrapper";
    private static final String ID_TEXT = "text";
    private static final String ID_FEEDBACK = "feedback";
    private static final String ID_EDIT = "edit";
    protected static final String MODAL_ID_OBJECT_SELECTION_POPUP = "objectSelectionPopup";

    private IModel<ValueWrapper<PrismContainerValue<ShadowAssociationType>>> model;
    private ObjectQuery query = null;
    private RefinedObjectClassDefinition assocTargetDef;

    public AssociationValueChoicePanel(String id,
            IModel<ValueWrapper<PrismContainerValue<ShadowAssociationType>>> model, List<PrismPropertyValue> values,
            boolean required, Class<C> type, ObjectQuery query, RefinedObjectClassDefinition assocTargetDef) {
        super(id, (IModel) new PropertyModel<>(model, "value"));
        this.model = model;
        this.query = query;
        this.assocTargetDef = assocTargetDef;
        setOutputMarkupId(true);
        initLayout((IModel) new PropertyModel<>(model, "value"), values, required, type);
    }

    private void initLayout(final IModel<PrismContainerValue<ShadowAssociationType>> value,
            final List<PrismPropertyValue> values, final boolean required, Class<C> type) {

        WebMarkupContainer textWrapper = new WebMarkupContainer(ID_TEXT_WRAPPER);

        textWrapper.setOutputMarkupId(true);

        TextField<String> text = new TextField<>(ID_TEXT, createTextModel(value));
        text.add(new AjaxFormComponentUpdatingBehavior("blur") {
            private static final long serialVersionUID = 1L;

            @Override
            protected void onUpdate(AjaxRequestTarget ajaxRequestTarget) {
            }
        });
        text.setRequired(required);
        text.setEnabled(false);
        textWrapper.add(text);

        FeedbackPanel feedback = new FeedbackPanel(ID_FEEDBACK, new ComponentFeedbackMessageFilter(text));
        feedback.setFilter(new ComponentFeedbackMessageFilter(text));
        textWrapper.add(feedback);

        AjaxLink edit = new AjaxLink(ID_EDIT) {
            private static final long serialVersionUID = 1L;

            @Override
            public void onClick(AjaxRequestTarget target) {
                editValuePerformed(target);
            }
        };
        edit.add(new VisibleEnableBehaviour() {
            private static final long serialVersionUID = 1L;

            @Override
            public boolean isVisible() {
                return model.getObject().isEmpty();
            }
        });
        textWrapper.add(edit);
        add(textWrapper);

        initDialog(type, values);

    }

    protected void replace(Object object) {
        //TODO  be careful , non systematic hack
        ShadowType shadowType = (ShadowType) object;
        ValueWrapper<PrismContainerValue<ShadowAssociationType>> oldCValueWrapper = model.getObject();
        AssociationWrapper associationWrapper = (AssociationWrapper) oldCValueWrapper.getItem();
        PrismContainer<ShadowAssociationType> container = (PrismContainer<ShadowAssociationType>) associationWrapper
                .getItem();
        container.remove((PrismContainerValue) oldCValueWrapper.getValue());
        PrismContainerValue<ShadowAssociationType> newValue = container.createNewValue();
        ShadowAssociationType assocType = newValue.asContainerable();
        ObjectReferenceType shadowRef = new ObjectReferenceType();
        shadowRef.setOid(shadowType.getOid());
        shadowRef.asReferenceValue().setObject(shadowType.asPrismObject());
        assocType.setShadowRef(shadowRef);
        assocType.setName(model.getObject().getItem().getName());
        getModel().setObject(newValue);
        LOGGER.trace("Replaced value of {} with {} ({})", this, newValue, assocType);
    }

    protected void initDialog(final Class<C> type, List<PrismPropertyValue> values) {
        LOGGER.debug("Initializing dialog for type {}", type);
        if (FocusType.class.equals(type)) {
            initUserOrgDialog();
        } else {
            initGenericDialog(type, values);
        }
    }

    // for ModalWindow treatment see comments in ChooseTypePanel
    private void initGenericDialog(final Class<C> type, final List<PrismPropertyValue> values) {
        final ModalWindow dialog = new ModalWindow(MODAL_ID_OBJECT_SELECTION_POPUP);

        ObjectSelectionPanel.Context context = new ObjectSelectionPanel.Context(this) {
            private static final long serialVersionUID = 1L;

            // See analogous discussion in ChooseTypePanel
            public AssociationValueChoicePanel getRealParent() {
                return WebComponentUtil.theSameForPage(AssociationValueChoicePanel.this, getCallingPageReference());
            }

            @Override
            public void chooseOperationPerformed(AjaxRequestTarget target, ObjectType object) {
                getRealParent().choosePerformed(target, object);
            }

            @Override
            public Collection<SelectorOptions<GetOperationOptions>> getDataProviderOptions() {
                return getAssociationsSearchOptions();
            }

            @Override
            public ObjectQuery getDataProviderQuery() {
                return query;
            }

            @Override
            public boolean isSearchEnabled() {
                //TODO don't commit
                return false;
            }

            @Override
            public Class<? extends ObjectType> getObjectTypeClass() {
                return type;
            }

        };

        ObjectSelectionPage.prepareDialog(dialog, context, this, "chooseTypeDialog.title", ID_TEXT_WRAPPER);
        add(dialog);
    }

    private void initUserOrgDialog() {
        final ModalWindow dialog = new ModalWindow(MODAL_ID_OBJECT_SELECTION_POPUP);
        ObjectSelectionPanel.Context context = new ObjectSelectionPanel.Context(this) {
            private static final long serialVersionUID = 1L;

            // See analogous discussion in ChooseTypePanel
            public AssociationValueChoicePanel getRealParent() {
                return WebComponentUtil.theSameForPage(AssociationValueChoicePanel.this, getCallingPageReference());
            }

            @Override
            public void chooseOperationPerformed(AjaxRequestTarget target, ObjectType object) {
                getRealParent().choosePerformed(target, object);
            }

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

            @Override
            public Class<? extends ObjectType> getObjectTypeClass() {
                return UserType.class;
            }

            @Override
            protected WebMarkupContainer createExtraContentContainer(String extraContentId,
                    final ObjectSelectionPanel objectSelectionPanel) {
                return new UserOrgReferenceChoosePanel(extraContentId, Boolean.FALSE) {
                    @Override
                    protected void onReferenceTypeChangePerformed(AjaxRequestTarget target, Boolean newValue) {
                        objectSelectionPanel.updateTableByTypePerformed(target,
                                Boolean.FALSE.equals(newValue) ? UserType.class : OrgType.class);
                    }
                };
            }
        };

        ObjectSelectionPage.prepareDialog(dialog, context, this, "chooseTypeDialog.title", ID_TEXT_WRAPPER);
        add(dialog);
    }

    protected ObjectQuery createChooseQuery(List<PrismPropertyValue> values) {
        ArrayList<String> oidList = new ArrayList<>();
        ObjectQuery query = new ObjectQuery();
        //TODO we should add to filter currently displayed value
        //not to be displayed on ObjectSelectionPanel instead of saved value
        //      for (PrismReferenceValue ref : values) {
        //         if (ref != null) {
        //            if (ref.getOid() != null && !ref.getOid().isEmpty()) {
        //               oidList.add(ref.getOid());
        //            }
        //         }
        //      }

        //      if (isediting) {
        //         oidList.add(orgModel.getObject().getObject().asObjectable().getOid());
        //      }

        if (oidList.isEmpty()) {
            return null;
        }

        ObjectFilter oidFilter = InOidFilter.createInOid(oidList);
        query.setFilter(NotFilter.createNot(oidFilter));

        return query;
    }

    /**
     * @return css class for off-setting other values (not first, left to the
     *         first there is a label)
     */
    protected String getOffsetClass() {
        return "col-md-offset-4";
    }

    protected IModel<String> createTextModel(final IModel<PrismContainerValue<ShadowAssociationType>> model) {
        return new AbstractReadOnlyModel<String>() {
            private static final long serialVersionUID = 1L;

            @Override
            public String getObject() {
                PrismContainerValue<ShadowAssociationType> cval = model.getObject();
                if (cval == null || cval.isEmpty()) {
                    return "";
                }
                PrismReferenceValue shadowRef = cval.findReference(ShadowAssociationType.F_SHADOW_REF).getValue();
                if (shadowRef.getObject() == null) {
                    PrismContainer<Containerable> identifiersContainer = cval
                            .findContainer(ShadowAssociationType.F_IDENTIFIERS);

                    List<PrismProperty<String>> identifiers = (List) identifiersContainer.getValue().getItems();
                    Collection<? extends RefinedAttributeDefinition<?>> secondaryIdentifierDefs = assocTargetDef
                            .getSecondaryIdentifiers();

                    for (RefinedAttributeDefinition<?> secondaryIdentifierDef : secondaryIdentifierDefs) {
                        for (PrismProperty<String> identifier : identifiers) {
                            if (identifier.getElementName().equals(secondaryIdentifierDef.getName())) {
                                return identifier.getRealValue();
                            }
                        }
                    }

                    // fallback
                    PrismProperty<String> identifierProp = identifiers.get(0);
                    return identifierProp.getRealValue();

                } else {
                    return shadowRef.getObject().getName().toString();
                }

            }
        };
    }

    public void editValuePerformed(AjaxRequestTarget target) {
        ModalWindow window = (ModalWindow) get(MODAL_ID_OBJECT_SELECTION_POPUP);
        window.show(target);
    }

    protected void choosePerformed(AjaxRequestTarget target, C object) {
        ModalWindow window = (ModalWindow) get(MODAL_ID_OBJECT_SELECTION_POPUP);
        window.close(target);

        replace(object);

        if (LOGGER.isTraceEnabled()) {
            LOGGER.trace("New object instance has been added to the model.");
        }
    }

    protected boolean isObjectUnique(C object) {

        PrismContainerValue<ShadowAssociationType> old = getModelObject();
        if (old == null || old.isEmpty()) {
            return true;
        }
        if (old.asContainerable().getShadowRef().getOid().equals(object.getOid())) {
            return false;
        }

        return true;
    }

    public Component getTextComponent() {
        return get(ID_TEXT_WRAPPER).get(ID_TEXT);
    }

    /**
     * A custom code in form of hook that can be run on event of choosing new
     * object with this chooser component
     * */
    protected void choosePerformedHook(AjaxRequestTarget target, C object) {
    }

    private Collection<SelectorOptions<GetOperationOptions>> getAssociationsSearchOptions() {
        Collection<SelectorOptions<GetOperationOptions>> options = new ArrayList<SelectorOptions<GetOperationOptions>>();
        // HACK: raw shoudl not be here. noFetch should be enough. But it does not work
        options.add(SelectorOptions.create(ItemPath.EMPTY_PATH, GetOperationOptions.createRaw()));
        options.add(SelectorOptions.create(ItemPath.EMPTY_PATH, GetOperationOptions.createNoFetch()));
        return options;
    }

    //TODO move query creating code from PrismValuePanel
    private ObjectQuery getAssociationsSearchQuery() {
        return new ObjectQuery();
    }

}