org.apache.syncope.client.console.panels.ResourceMappingPanel.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.syncope.client.console.panels.ResourceMappingPanel.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 org.apache.syncope.client.console.panels;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import org.apache.commons.collections4.IterableUtils;
import org.apache.commons.collections4.Predicate;
import org.apache.syncope.client.console.commons.Constants;
import org.apache.syncope.client.console.commons.JexlHelpUtils;
import org.apache.syncope.client.console.rest.ConnectorRestClient;
import org.apache.syncope.client.console.rest.SchemaRestClient;
import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
import org.apache.syncope.client.console.wicket.markup.html.form.ActionLinksPanel;
import org.apache.syncope.client.console.wicket.markup.html.form.AjaxCheckBoxPanel;
import org.apache.syncope.client.console.wicket.markup.html.form.AjaxDropDownChoicePanel;
import org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPanel;
import org.apache.syncope.client.console.wicket.markup.html.form.FieldPanel;
import org.apache.syncope.client.console.wicket.markup.html.form.MappingPurposePanel;
import org.apache.syncope.common.lib.to.ConnIdObjectClassTO;
import org.apache.syncope.common.lib.to.ConnInstanceTO;
import org.apache.syncope.common.lib.to.MappingItemTO;
import org.apache.syncope.common.lib.to.MappingTO;
import org.apache.syncope.common.lib.to.ProvisionTO;
import org.apache.syncope.common.lib.to.ResourceTO;
import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.common.lib.types.ConnConfProperty;
import org.apache.syncope.common.lib.types.IntMappingType;
import org.apache.syncope.common.lib.types.MappingPurpose;
import org.apache.syncope.common.lib.types.StandardEntitlement;
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.ajax.markup.html.form.AjaxButton;
import org.apache.wicket.extensions.ajax.markup.html.IndicatingAjaxButton;
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.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.model.ResourceModel;

/**
 * Resource mapping panel.
 */
public class ResourceMappingPanel extends Panel {

    private static final long serialVersionUID = -7982691107029848579L;

    /**
     * Mapping field style sheet.
     */
    private static final String DEF_FIELD_STYLE = "";

    /**
     * Schema rest client.
     */
    private final SchemaRestClient schemaRestClient = new SchemaRestClient();

    /**
     * ConnInstance rest client.
     */
    private final ConnectorRestClient connRestClient = new ConnectorRestClient();

    /**
     * Resource schema name.
     */
    private final List<String> schemaNames;

    /**
     * Add mapping button.
     */
    private final AjaxButton addMappingBtn;

    /**
     * All mappings.
     */
    private final ListView<MappingItemTO> mappings;

    /**
     * External resource to be updated.
     */
    private final ResourceTO resourceTO;

    /**
     * External resource provisioning configuration instance to be updated.
     */
    private final ProvisionTO provisionTO;

    /**
     * Mapping container.
     */
    private final WebMarkupContainer mappingContainer;

    private MappingTO getMapping() {
        if (provisionTO.getMapping() == null) {
            provisionTO.setMapping(new MappingTO());
        }

        return provisionTO.getMapping();
    }

    /**
     * Attribute Mapping Panel.
     *
     * @param id panel id
     * @param resourceTO external resource to be updated.
     * @param provisionTO external resource provisioning configuration instance.
     */
    public ResourceMappingPanel(final String id, final ResourceTO resourceTO, final ProvisionTO provisionTO) {
        super(id);
        setOutputMarkupId(true);

        this.resourceTO = resourceTO;
        this.provisionTO = provisionTO == null ? new ProvisionTO() : provisionTO;

        this.mappingContainer = new WebMarkupContainer("mappingContainer");
        this.mappingContainer.setOutputMarkupId(true);
        add(this.mappingContainer);

        if (resourceTO.getConnector() != null && resourceTO.getConnector() > 0) {
            schemaNames = getSchemaNames(resourceTO.getConnector(), resourceTO.getConfOverride());
            setEnabled();
        } else {
            schemaNames = Collections.<String>emptyList();
        }

        final WebMarkupContainer jexlHelp = JexlHelpUtils.getJexlHelpWebContainer("jexlHelp");

        AjaxLink<Void> questionMarkJexlHelp = JexlHelpUtils.getAjaxLink(jexlHelp, "questionMarkJexlHelp");
        mappingContainer.add(questionMarkJexlHelp);
        questionMarkJexlHelp.add(jexlHelp);

        final Label passwordLabel = new Label("passwordLabel", new ResourceModel("password"));
        mappingContainer.add(passwordLabel);

        if (!AnyTypeKind.USER.name().equals(this.provisionTO.getAnyType())) {
            passwordLabel.setVisible(false);
        }

        Collections.sort(getMapping().getItems(), new Comparator<MappingItemTO>() {

            @Override
            public int compare(final MappingItemTO left, final MappingItemTO right) {
                int compared;
                if (left == null && right == null) {
                    compared = 0;
                } else if (left == null) {
                    compared = 1;
                } else if (right == null) {
                    compared = -1;
                } else if (left.getPurpose() == MappingPurpose.BOTH && right.getPurpose() != MappingPurpose.BOTH) {
                    compared = -1;
                } else if (left.getPurpose() != MappingPurpose.BOTH && right.getPurpose() == MappingPurpose.BOTH) {
                    compared = 1;
                } else if (left.getPurpose() == MappingPurpose.PROPAGATION
                        && (right.getPurpose() == MappingPurpose.SYNCHRONIZATION
                                || right.getPurpose() == MappingPurpose.NONE)) {
                    compared = -1;
                } else if (left.getPurpose() == MappingPurpose.SYNCHRONIZATION
                        && right.getPurpose() == MappingPurpose.PROPAGATION) {
                    compared = 1;
                } else if (left.getPurpose() == MappingPurpose.SYNCHRONIZATION
                        && right.getPurpose() == MappingPurpose.NONE) {
                    compared = -1;
                } else if (left.getPurpose() == MappingPurpose.NONE && right.getPurpose() != MappingPurpose.NONE) {
                    compared = 1;
                } else if (left.isConnObjectKey()) {
                    compared = -1;
                } else if (right.isConnObjectKey()) {
                    compared = 1;
                } else if (left.isPassword()) {
                    compared = -1;
                } else if (right.isPassword()) {
                    compared = 1;
                } else {
                    compared = left.getIntAttrName().compareTo(right.getIntAttrName());
                }
                return compared;
            }
        });

        mappings = new ListView<MappingItemTO>("mappings", getMapping().getItems()) {

            private static final long serialVersionUID = 4949588177564901031L;

            @Override
            protected void populateItem(final ListItem<MappingItemTO> item) {
                final MappingItemTO mapItem = item.getModelObject();
                if (mapItem.getPurpose() == null) {
                    mapItem.setPurpose(MappingPurpose.BOTH);
                }

                AnyTypeKind entity = null;
                if (mapItem.getIntMappingType() != null) {
                    entity = mapItem.getIntMappingType().getAnyTypeKind();
                }

                final ActionLinksPanel.Builder<Serializable> actions = ActionLinksPanel
                        .builder(getPage().getPageReference());

                actions.add(new ActionLink<Serializable>() {

                    private static final long serialVersionUID = -3722207913631435501L;

                    @Override
                    public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
                        int index = -1;
                        for (int i = 0; i < getMapping().getItems().size() && index == -1; i++) {
                            if (mapItem.equals(getMapping().getItems().get(i))) {
                                index = i;
                            }
                        }

                        if (index != -1) {
                            getMapping().getItems().remove(index);
                            item.getParent().removeAll();
                            target.add(ResourceMappingPanel.this);
                        }
                    }
                }, ActionLink.ActionType.DELETE, StandardEntitlement.RESOURCE_UPDATE);

                item.add(actions.build("toRemove"));

                final AjaxDropDownChoicePanel<String> intAttrNames = new AjaxDropDownChoicePanel<>("intAttrNames",
                        getString("intAttrNames"), new PropertyModel<String>(mapItem, "intAttrName"), false);
                intAttrNames.setChoices(schemaNames);
                intAttrNames.setRequired(true).hideLabel();

                intAttrNames.getField().add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {

                    private static final long serialVersionUID = -1107858522700306810L;

                    @Override
                    protected void onUpdate(final AjaxRequestTarget target) {
                    }
                });
                item.add(intAttrNames);

                final List<IntMappingType> attrTypes = new ArrayList<>(getAttributeTypes(entity));
                final AjaxDropDownChoicePanel<IntMappingType> intMappingTypes = new AjaxDropDownChoicePanel<>(
                        "intMappingTypes", new ResourceModel("intMappingTypes", "intMappingTypes").getObject(),
                        new PropertyModel<IntMappingType>(mapItem, "intMappingType"));
                intMappingTypes.setRequired(true).hideLabel();
                intMappingTypes.setChoices(attrTypes);
                item.add(intMappingTypes);

                final AjaxDropDownChoicePanel<AnyTypeKind> entitiesPanel = new AjaxDropDownChoicePanel<>("entities",
                        new ResourceModel("entities", "entities").getObject(), new Model<>(entity));

                entitiesPanel.hideLabel();
                entitiesPanel.setChoices(provisionTO.getAnyType().equals(AnyTypeKind.GROUP.name())
                        ? Collections.<AnyTypeKind>singletonList(AnyTypeKind.GROUP)
                        : Arrays.asList(AnyTypeKind.values()));

                entitiesPanel.setStyleSheet(false, DEF_FIELD_STYLE);

                entitiesPanel.getField().add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {

                    private static final long serialVersionUID = -1107858522700306810L;

                    @Override
                    protected void onUpdate(final AjaxRequestTarget target) {
                        attrTypes.clear();
                        attrTypes.addAll(getAttributeTypes(entitiesPanel.getModelObject()));
                        intMappingTypes.setChoices(attrTypes);

                        intAttrNames.setChoices(Collections.<String>emptyList());

                        target.add(intMappingTypes);
                        target.add(intAttrNames);
                    }
                });
                item.add(entitiesPanel);

                final FieldPanel<String> extAttrNames = new AjaxTextFieldPanel("extAttrName",
                        new ResourceModel("extAttrNames", "extAttrNames").getObject(),
                        new PropertyModel<String>(mapItem, "extAttrName"));
                ((AjaxTextFieldPanel) extAttrNames).setChoices(schemaNames);

                boolean required = false;
                if (mapItem.isPassword()) {
                    ((AjaxTextFieldPanel) extAttrNames).setModelObject(null);
                } else {
                    required = true;
                }
                extAttrNames.setRequired(required).hideLabel();
                extAttrNames.setEnabled(required);
                item.add(extAttrNames);

                final AjaxTextFieldPanel mandatory = new AjaxTextFieldPanel("mandatoryCondition",
                        new ResourceModel("mandatoryCondition", "mandatoryCondition").getObject(),
                        new PropertyModel<String>(mapItem, "mandatoryCondition"));
                mandatory.hideLabel();
                mandatory.setChoices(Arrays.asList(new String[] { "true", "false" }));
                item.add(mandatory);

                final AjaxCheckBoxPanel connObjectKey = new AjaxCheckBoxPanel("connObjectKey",
                        new ResourceModel("connObjectKey", "connObjectKey").getObject(),
                        new PropertyModel<Boolean>(mapItem, "connObjectKey"));

                connObjectKey.hideLabel();
                connObjectKey.getField().add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {

                    private static final long serialVersionUID = -1107858522700306810L;

                    @Override
                    protected void onUpdate(final AjaxRequestTarget target) {
                        if (connObjectKey.getModelObject()) {
                            mapItem.setMandatoryCondition("true");
                            mandatory.setEnabled(false);
                        } else {
                            mapItem.setMandatoryCondition("false");
                            mandatory.setEnabled(true);
                        }
                        target.add(mandatory);
                    }
                });
                item.add(connObjectKey);

                final AjaxCheckBoxPanel password = new AjaxCheckBoxPanel("password",
                        new ResourceModel("password", "password").getObject(),
                        new PropertyModel<Boolean>(mapItem, "password"));

                password.hideLabel();
                password.getField().add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {

                    private static final long serialVersionUID = -1107858522700306810L;

                    @Override
                    protected void onUpdate(final AjaxRequestTarget target) {
                        extAttrNames.setEnabled(!mapItem.isConnObjectKey() && !password.getModelObject());
                        extAttrNames.setModelObject(null);
                        extAttrNames.setRequired(!password.getModelObject());
                        target.add(extAttrNames);

                        setConnObjectKey(intMappingTypes.getModelObject(), connObjectKey, password);
                        target.add(connObjectKey);
                    }
                });
                item.add(password);
                if (!AnyTypeKind.USER.name().equals(provisionTO.getAnyType())) {
                    password.setVisible(false);
                }

                final WebMarkupContainer purpose = new WebMarkupContainer("purpose");
                purpose.setOutputMarkupId(Boolean.TRUE);

                final MappingPurposePanel panel = new MappingPurposePanel("purposeActions",
                        new PropertyModel<MappingPurpose>(mapItem, "purpose"), purpose);

                purpose.add(panel.setRenderBodyOnly(true));

                item.add(purpose);

                intMappingTypes.getField().add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {

                    private static final long serialVersionUID = -1107858522700306810L;

                    @Override
                    protected void onUpdate(final AjaxRequestTarget target) {
                        setAttrNames(intMappingTypes.getModelObject(), intAttrNames);
                        target.add(intAttrNames);

                        setConnObjectKey(intMappingTypes.getModelObject(), connObjectKey, password);
                        target.add(connObjectKey);
                    }
                });

                setAttrNames(mapItem.getIntMappingType(), intAttrNames);
                setConnObjectKey(mapItem.getIntMappingType(), connObjectKey, password);
            }
        };

        mappings.setReuseItems(true);
        mappingContainer.add(mappings);

        addMappingBtn = new IndicatingAjaxButton("addMappingBtn", new ResourceModel("add")) {

            private static final long serialVersionUID = -4804368561204623354L;

            @Override
            protected void onSubmit(final AjaxRequestTarget target, final Form<?> form) {
                getMapping().getItems().add(new MappingItemTO());
                target.add(ResourceMappingPanel.this);
            }
        };
        addMappingBtn.setDefaultFormProcessing(false);
        addMappingBtn.setEnabled(resourceTO.getConnector() != null && resourceTO.getConnector() > 0);
        mappingContainer.add(addMappingBtn);
    }

    private List<String> getSchemaNames(final Long connectorId, final Set<ConnConfProperty> conf) {
        final ConnInstanceTO connInstanceTO = new ConnInstanceTO();
        connInstanceTO.setKey(connectorId);
        connInstanceTO.getConf().addAll(conf);

        // SYNCOPE-156: use provided info to give schema names (and type!) by ObjectClass
        ConnIdObjectClassTO clazz = IterableUtils.find(connRestClient.buildObjectClassInfo(connInstanceTO, true),
                new Predicate<ConnIdObjectClassTO>() {

                    @Override
                    public boolean evaluate(final ConnIdObjectClassTO object) {
                        return object.getType()
                                .equalsIgnoreCase(ResourceMappingPanel.this.provisionTO.getObjectClass());
                    }
                });

        return clazz == null ? new ArrayList<String>()
                : IterableUtils
                        .toList(IterableUtils.filteredIterable(clazz.getAttributes(), new Predicate<String>() {

                            @Override
                            public boolean evaluate(final String object) {
                                return !("__NAME__".equals(object) || "__ENABLE__".equals(object)
                                        || "__PASSWORD__".equals(object));
                            }
                        }));
    }

    private void setEnabled() {
        ConnInstanceTO connInstanceTO = new ConnInstanceTO();
        connInstanceTO.setKey(resourceTO.getConnector());
        connInstanceTO.getConf().addAll(resourceTO.getConfOverride());

        boolean enabled = provisionTO != null;

        this.mappingContainer.setEnabled(enabled);
        this.mappingContainer.setVisible(enabled);

        if (!enabled) {
            getMapping().getItems().clear();
            getMapping().setConnObjectLink(null);
        }
    }

    /**
     * Set attribute names for a drop down choice list.
     *
     * @param type attribute type.
     * @param toBeUpdated drop down choice to be updated.
     */
    private void setAttrNames(final IntMappingType type, final AjaxDropDownChoicePanel<String> toBeUpdated) {
        toBeUpdated.setRequired(true);
        toBeUpdated.setEnabled(true);

        if (type == null || type.getAnyTypeKind() == null) {
            toBeUpdated.setChoices(Collections.<String>emptyList());
        } else {
            switch (type) {
            // user attribute names
            case UserPlainSchema:
            case GroupPlainSchema:
            case AnyObjectPlainSchema:
                toBeUpdated.setChoices(schemaRestClient.getPlainSchemaNames());
                break;

            case UserDerivedSchema:
            case GroupDerivedSchema:
            case AnyObjectDerivedSchema:
                toBeUpdated.setChoices(schemaRestClient.getDerSchemaNames());
                break;

            case UserVirtualSchema:
            case GroupVirtualSchema:
            case AnyObjectVirtualSchema:
                toBeUpdated.setChoices(schemaRestClient.getVirSchemaNames());
                break;

            case UserKey:
            case Password:
            case Username:
            case GroupKey:
            case GroupName:
            case AnyObjectKey:
            default:
                toBeUpdated.setRequired(false);
                toBeUpdated.setEnabled(false);
                toBeUpdated.setChoices(Collections.<String>emptyList());
            }
        }
    }

    /**
     * Enable/Disable connObjectKey checkbox.
     *
     * @param type attribute type.
     * @param connObjectKey connObjectKey checkbox.
     * @param password password checkbox.
     */
    private void setConnObjectKey(final IntMappingType type, final AjaxCheckBoxPanel connObjectKey,
            final AjaxCheckBoxPanel password) {

        if (type != null && type.getAnyTypeKind() != null) {
            switch (type) {
            case UserVirtualSchema:
            case GroupVirtualSchema:
            case AnyObjectVirtualSchema:
                // Virtual connObjectKey is not permitted
            case Password:
                // connObjectKey cannot be derived from password.
                connObjectKey.setReadOnly(true);
                connObjectKey.setModelObject(false);
                break;

            default:
                if (password.getModelObject()) {
                    connObjectKey.setReadOnly(true);
                    connObjectKey.setModelObject(false);
                } else {
                    connObjectKey.setReadOnly(false);
                }
            }
        }
    }

    /**
     * Get all attribute types from a selected attribute type.
     *
     * @param entity entity.
     * @return all attribute types.
     */
    private List<IntMappingType> getAttributeTypes(final AnyTypeKind entity) {
        final List<IntMappingType> res = new ArrayList<>();

        if (entity != null) {
            res.addAll(IntMappingType.getAttributeTypes(entity));
        }

        return res;
    }
}