org.apache.syncope.console.pages.ConnectorModalPage.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.syncope.console.pages.ConnectorModalPage.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.console.pages;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.apache.syncope.common.SyncopeClientException;
import org.apache.syncope.common.to.ConnBundleTO;
import org.apache.syncope.common.to.ConnInstanceTO;
import org.apache.syncope.common.to.ConnPoolConfTO;
import org.apache.syncope.common.types.ConnConfPropSchema;
import org.apache.syncope.common.types.ConnConfProperty;
import org.apache.syncope.common.types.ConnectorCapability;
import org.apache.syncope.console.commons.Constants;
import org.apache.syncope.console.markup.html.list.AltListView;
import org.apache.syncope.console.rest.ConnectorRestClient;
import org.apache.syncope.console.wicket.markup.html.form.AjaxCheckBoxPanel;
import org.apache.syncope.console.wicket.markup.html.form.AjaxDropDownChoicePanel;
import org.apache.syncope.console.wicket.markup.html.form.AjaxPasswordFieldPanel;
import org.apache.syncope.console.wicket.markup.html.form.AjaxTextFieldPanel;
import org.apache.syncope.console.wicket.markup.html.form.FieldPanel;
import org.apache.syncope.console.wicket.markup.html.form.MultiFieldPanel;
import org.apache.syncope.console.wicket.markup.html.form.SpinnerFieldPanel;
import org.apache.wicket.PageReference;
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.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy;
import org.apache.wicket.extensions.ajax.markup.html.IndicatingAjaxButton;
import org.apache.wicket.extensions.ajax.markup.html.IndicatingAjaxLink;
import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.CheckBoxMultipleChoice;
import org.apache.wicket.markup.html.form.DropDownChoice;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.PasswordTextField;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.model.CompoundPropertyModel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.LoadableDetachableModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.model.ResourceModel;
import org.apache.wicket.spring.injection.annot.SpringBean;
import org.apache.wicket.validation.validator.RangeValidator;
import org.springframework.util.ClassUtils;

/**
 * Modal window with Connector form.
 */
public class ConnectorModalPage extends BaseModalPage {

    private static final long serialVersionUID = -2025535531121434050L;

    @SpringBean
    private ConnectorRestClient restClient;

    private final Map<String, Map<String, Map<String, ConnBundleTO>>> mapConnBundleTOs;

    private final List<ConnectorCapability> selectedCapabilities;

    private ConnBundleTO bundleTO;

    private List<ConnConfProperty> properties;

    private final WebMarkupContainer propertiesContainer;

    public ConnectorModalPage(final PageReference pageRef, final ModalWindow window,
            final ConnInstanceTO connInstanceTO) {

        super();

        // general data setup
        selectedCapabilities = new ArrayList<ConnectorCapability>(
                connInstanceTO.getId() == 0 ? EnumSet.noneOf(ConnectorCapability.class)
                        : connInstanceTO.getCapabilities());

        mapConnBundleTOs = new HashMap<String, Map<String, Map<String, ConnBundleTO>>>();
        for (ConnBundleTO connBundleTO : restClient.getAllBundles()) {
            // by location
            if (!mapConnBundleTOs.containsKey(connBundleTO.getLocation())) {
                mapConnBundleTOs.put(connBundleTO.getLocation(), new HashMap<String, Map<String, ConnBundleTO>>());
            }
            final Map<String, Map<String, ConnBundleTO>> byLocation = mapConnBundleTOs
                    .get(connBundleTO.getLocation());

            // by name
            if (!byLocation.containsKey(connBundleTO.getBundleName())) {
                byLocation.put(connBundleTO.getBundleName(), new HashMap<String, ConnBundleTO>());
            }
            final Map<String, ConnBundleTO> byName = byLocation.get(connBundleTO.getBundleName());

            // by version
            if (!byName.containsKey(connBundleTO.getVersion())) {
                byName.put(connBundleTO.getVersion(), connBundleTO);
            }
        }

        bundleTO = getSelectedBundleTO(connInstanceTO);
        properties = fillProperties(bundleTO, connInstanceTO);

        // form - first tab
        final Form<ConnInstanceTO> connectorForm = new Form<ConnInstanceTO>(FORM);
        connectorForm.setModel(new CompoundPropertyModel<ConnInstanceTO>(connInstanceTO));
        connectorForm.setOutputMarkupId(true);
        add(connectorForm);

        propertiesContainer = new WebMarkupContainer("container");
        propertiesContainer.setOutputMarkupId(true);
        connectorForm.add(propertiesContainer);

        final Form<ConnInstanceTO> connectorPropForm = new Form<ConnInstanceTO>("connectorPropForm");
        connectorPropForm.setModel(new CompoundPropertyModel<ConnInstanceTO>(connInstanceTO));
        connectorPropForm.setOutputMarkupId(true);
        propertiesContainer.add(connectorPropForm);

        final AjaxTextFieldPanel displayName = new AjaxTextFieldPanel("displayName", "display name",
                new PropertyModel<String>(connInstanceTO, "displayName"));
        displayName.setOutputMarkupId(true);
        displayName.addRequiredLabel();
        connectorForm.add(displayName);

        final AjaxDropDownChoicePanel<String> location = new AjaxDropDownChoicePanel<String>("location", "location",
                new Model<String>(bundleTO == null ? null : bundleTO.getLocation()));
        ((DropDownChoice<String>) location.getField()).setNullValid(true);
        location.setStyleSheet("long_dynamicsize");
        location.setChoices(new ArrayList<String>(mapConnBundleTOs.keySet()));
        location.setRequired(true);
        location.addRequiredLabel();
        location.setOutputMarkupId(true);
        location.setEnabled(connInstanceTO.getId() == 0);
        location.getField().setOutputMarkupId(true);
        connectorForm.add(location);

        final AjaxDropDownChoicePanel<String> connectorName = new AjaxDropDownChoicePanel<String>("connectorName",
                "connectorName", new Model<String>(bundleTO == null ? null : bundleTO.getBundleName()));
        ((DropDownChoice<String>) connectorName.getField()).setNullValid(true);
        connectorName.setStyleSheet("long_dynamicsize");
        connectorName.setChoices(bundleTO == null ? new ArrayList<String>()
                : new ArrayList<String>(mapConnBundleTOs.get(connInstanceTO.getLocation()).keySet()));
        connectorName.setRequired(true);
        connectorName.addRequiredLabel();
        connectorName.setEnabled(connInstanceTO.getLocation() != null);
        connectorName.setOutputMarkupId(true);
        connectorName.setEnabled(connInstanceTO.getId() == 0);
        connectorName.getField().setOutputMarkupId(true);
        connectorForm.add(connectorName);

        final AjaxDropDownChoicePanel<String> version = new AjaxDropDownChoicePanel<String>("version", "version",
                new Model<String>(bundleTO == null ? null : bundleTO.getVersion()));
        version.setStyleSheet("long_dynamicsize");
        version.setChoices(bundleTO == null ? new ArrayList<String>()
                : new ArrayList<String>(mapConnBundleTOs.get(connInstanceTO.getLocation())
                        .get(connInstanceTO.getBundleName()).keySet()));
        version.setRequired(true);
        version.addRequiredLabel();
        version.setEnabled(connInstanceTO.getBundleName() != null);
        version.setOutputMarkupId(true);
        version.addRequiredLabel();
        version.getField().setOutputMarkupId(true);
        connectorForm.add(version);

        final SpinnerFieldPanel<Integer> connRequestTimeout = new SpinnerFieldPanel<Integer>("connRequestTimeout",
                "connRequestTimeout", Integer.class,
                new PropertyModel<Integer>(connInstanceTO, "connRequestTimeout"), 0, null);
        connRequestTimeout.getField().add(new RangeValidator<Integer>(0, Integer.MAX_VALUE));
        connectorForm.add(connRequestTimeout);

        if (connInstanceTO.getPoolConf() == null) {
            connInstanceTO.setPoolConf(new ConnPoolConfTO());
        }
        final SpinnerFieldPanel<Integer> poolMaxObjects = new SpinnerFieldPanel<Integer>("poolMaxObjects",
                "poolMaxObjects", Integer.class,
                new PropertyModel<Integer>(connInstanceTO.getPoolConf(), "maxObjects"), 0, null);
        poolMaxObjects.getField().add(new RangeValidator<Integer>(0, Integer.MAX_VALUE));
        connectorForm.add(poolMaxObjects);
        final SpinnerFieldPanel<Integer> poolMinIdle = new SpinnerFieldPanel<Integer>("poolMinIdle", "poolMinIdle",
                Integer.class, new PropertyModel<Integer>(connInstanceTO.getPoolConf(), "minIdle"), 0, null);
        poolMinIdle.getField().add(new RangeValidator<Integer>(0, Integer.MAX_VALUE));
        connectorForm.add(poolMinIdle);
        final SpinnerFieldPanel<Integer> poolMaxIdle = new SpinnerFieldPanel<Integer>("poolMaxIdle", "poolMaxIdle",
                Integer.class, new PropertyModel<Integer>(connInstanceTO.getPoolConf(), "maxIdle"), 0, null);
        poolMaxIdle.getField().add(new RangeValidator<Integer>(0, Integer.MAX_VALUE));
        connectorForm.add(poolMaxIdle);
        final SpinnerFieldPanel<Long> poolMaxWait = new SpinnerFieldPanel<Long>("poolMaxWait", "poolMaxWait",
                Long.class, new PropertyModel<Long>(connInstanceTO.getPoolConf(), "maxWait"), 0L, null);
        poolMaxWait.getField().add(new RangeValidator<Long>(0L, Long.MAX_VALUE));
        connectorForm.add(poolMaxWait);
        final SpinnerFieldPanel<Long> poolMinEvictableIdleTime = new SpinnerFieldPanel<Long>(
                "poolMinEvictableIdleTime", "poolMinEvictableIdleTime", Long.class,
                new PropertyModel<Long>(connInstanceTO.getPoolConf(), "minEvictableIdleTimeMillis"), 0L, null);
        poolMinEvictableIdleTime.getField().add(new RangeValidator<Long>(0L, Long.MAX_VALUE));
        connectorForm.add(poolMinEvictableIdleTime);

        // form - first tab - onchange()
        location.getField().add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {

            private static final long serialVersionUID = -1107858522700306810L;

            @Override
            protected void onUpdate(final AjaxRequestTarget target) {
                ((DropDownChoice<String>) location.getField()).setNullValid(false);
                connInstanceTO.setLocation(location.getModelObject());
                target.add(location);

                connectorName.setChoices(
                        new ArrayList<String>(mapConnBundleTOs.get(location.getModelObject()).keySet()));
                connectorName.setEnabled(true);
                connectorName.getField().setModelValue(null);
                target.add(connectorName);

                version.setChoices(new ArrayList<String>());
                version.getField().setModelValue(null);
                version.setEnabled(false);
                target.add(version);

                properties.clear();
                target.add(propertiesContainer);
            }
        });
        connectorName.getField().add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {

            private static final long serialVersionUID = -1107858522700306810L;

            @Override
            protected void onUpdate(final AjaxRequestTarget target) {
                ((DropDownChoice<String>) connectorName.getField()).setNullValid(false);
                connInstanceTO.setBundleName(connectorName.getModelObject());
                target.add(connectorName);

                List<String> versions = new ArrayList<String>(mapConnBundleTOs.get(location.getModelObject())
                        .get(connectorName.getModelObject()).keySet());
                version.setChoices(versions);
                version.setEnabled(true);
                if (versions.size() == 1) {
                    selectVersion(target, connInstanceTO, version, versions.get(0));
                    version.getField().setModelObject(versions.get(0));
                } else {
                    version.getField().setModelValue(null);
                    properties.clear();
                    target.add(propertiesContainer);
                }
                target.add(version);
            }
        });
        version.getField().add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {

            private static final long serialVersionUID = -1107858522700306810L;

            @Override
            protected void onUpdate(final AjaxRequestTarget target) {
                selectVersion(target, connInstanceTO, version, version.getModelObject());
            }
        });

        // form - second tab (properties)
        final ListView<ConnConfProperty> connPropView = new AltListView<ConnConfProperty>("connectorProperties",
                new PropertyModel<List<ConnConfProperty>>(this, "properties")) {

            private static final long serialVersionUID = 9101744072914090143L;

            @Override
            @SuppressWarnings({ "unchecked", "rawtypes" })
            protected void populateItem(final ListItem<ConnConfProperty> item) {
                final ConnConfProperty property = item.getModelObject();

                final Label label = new Label("connPropAttrSchema",
                        StringUtils.isBlank(property.getSchema().getDisplayName()) ? property.getSchema().getName()
                                : property.getSchema().getDisplayName());
                item.add(label);

                final FieldPanel field;
                boolean required = false;
                boolean isArray = false;
                if (property.getSchema().isConfidential()
                        || Constants.GUARDED_STRING.equalsIgnoreCase(property.getSchema().getType())
                        || Constants.GUARDED_BYTE_ARRAY.equalsIgnoreCase(property.getSchema().getType())) {

                    field = new AjaxPasswordFieldPanel("panel", label.getDefaultModelObjectAsString(),
                            new Model<String>());

                    ((PasswordTextField) field.getField()).setResetPassword(false);

                    required = property.getSchema().isRequired();
                } else {
                    Class<?> propertySchemaClass;

                    try {
                        propertySchemaClass = ClassUtils.forName(property.getSchema().getType(),
                                ClassUtils.getDefaultClassLoader());
                        if (ClassUtils.isPrimitiveOrWrapper(propertySchemaClass)) {
                            propertySchemaClass = org.apache.commons.lang3.ClassUtils
                                    .primitiveToWrapper(propertySchemaClass);
                        }
                    } catch (Exception e) {
                        LOG.error("Error parsing attribute type", e);
                        propertySchemaClass = String.class;
                    }
                    if (ClassUtils.isAssignable(Number.class, propertySchemaClass)) {
                        field = new SpinnerFieldPanel<Number>("panel", label.getDefaultModelObjectAsString(),
                                (Class<Number>) propertySchemaClass, new Model<Number>(), null, null);

                        required = property.getSchema().isRequired();
                    } else if (ClassUtils.isAssignable(Boolean.class, propertySchemaClass)) {
                        field = new AjaxCheckBoxPanel("panel", label.getDefaultModelObjectAsString(),
                                new Model<Boolean>());
                    } else {
                        field = new AjaxTextFieldPanel("panel", label.getDefaultModelObjectAsString(),
                                new Model<String>());

                        required = property.getSchema().isRequired();
                    }

                    if (propertySchemaClass.isArray()) {
                        isArray = true;
                    }
                }

                field.setTitle(property.getSchema().getHelpMessage());

                if (required) {
                    field.addRequiredLabel();
                }

                if (isArray) {
                    if (property.getValues().isEmpty()) {
                        property.getValues().add(null);
                    }

                    item.add(new MultiFieldPanel<String>("panel",
                            new PropertyModel<List<String>>(property, "values"), field));
                } else {
                    field.setNewModel(property.getValues());
                    item.add(field);
                }

                final AjaxCheckBoxPanel overridable = new AjaxCheckBoxPanel("connPropAttrOverridable",
                        "connPropAttrOverridable", new PropertyModel<Boolean>(property, "overridable"));

                item.add(overridable);
                connInstanceTO.getConfiguration().add(property);
            }
        };
        connPropView.setOutputMarkupId(true);
        connectorPropForm.add(connPropView);

        final AjaxLink<String> check = new IndicatingAjaxLink<String>("check", new ResourceModel("check")) {

            private static final long serialVersionUID = -7978723352517770644L;

            @Override
            public void onClick(final AjaxRequestTarget target) {
                connInstanceTO.setBundleName(bundleTO.getBundleName());
                connInstanceTO.setVersion(bundleTO.getVersion());
                connInstanceTO.setConnectorName(bundleTO.getConnectorName());

                if (restClient.check(connInstanceTO)) {
                    info(getString("success_connection"));
                } else {
                    error(getString("error_connection"));
                }

                feedbackPanel.refresh(target);
            }
        };
        connectorPropForm.add(check);

        // form - third tab (capabilities)
        final IModel<List<ConnectorCapability>> capabilities = new LoadableDetachableModel<List<ConnectorCapability>>() {

            private static final long serialVersionUID = 5275935387613157437L;

            @Override
            protected List<ConnectorCapability> load() {
                return Arrays.asList(ConnectorCapability.values());
            }
        };
        CheckBoxMultipleChoice<ConnectorCapability> capabilitiesPalette = new CheckBoxMultipleChoice<ConnectorCapability>(
                "capabilitiesPalette", new PropertyModel<List<ConnectorCapability>>(this, "selectedCapabilities"),
                capabilities);
        connectorForm.add(capabilitiesPalette);

        // form - submit / cancel buttons
        final AjaxButton submit = new IndicatingAjaxButton(APPLY, new Model<String>(getString(SUBMIT))) {

            private static final long serialVersionUID = -958724007591692537L;

            @Override
            protected void onSubmit(final AjaxRequestTarget target, final Form<?> form) {
                final ConnInstanceTO conn = (ConnInstanceTO) form.getModelObject();

                conn.setConnectorName(bundleTO.getConnectorName());
                conn.setBundleName(bundleTO.getBundleName());
                conn.setVersion(bundleTO.getVersion());
                conn.getConfiguration().clear();
                conn.getConfiguration().addAll(connPropView.getModelObject());

                // Set the model object's capabilities to capabilitiesPalette's converted Set
                conn.getCapabilities()
                        .addAll(selectedCapabilities.isEmpty() ? EnumSet.noneOf(ConnectorCapability.class)
                                : EnumSet.copyOf(selectedCapabilities));

                // Reset pool configuration if all fields are null
                if (conn.getPoolConf() != null && conn.getPoolConf().getMaxIdle() == null
                        && conn.getPoolConf().getMaxObjects() == null && conn.getPoolConf().getMaxWait() == null
                        && conn.getPoolConf().getMinEvictableIdleTimeMillis() == null
                        && conn.getPoolConf().getMinIdle() == null) {

                    conn.setPoolConf(null);
                }

                try {
                    if (connInstanceTO.getId() == 0) {
                        restClient.create(conn);
                    } else {
                        restClient.update(conn);
                    }

                    ((Resources) pageRef.getPage()).setModalResult(true);
                    window.close(target);
                } catch (SyncopeClientException e) {
                    error(getString(Constants.ERROR) + ": " + e.getMessage());
                    feedbackPanel.refresh(target);
                    ((Resources) pageRef.getPage()).setModalResult(false);
                    LOG.error("While creating or updating connector {}", conn, e);
                }
            }

            @Override
            protected void onError(final AjaxRequestTarget target, final Form<?> form) {

                feedbackPanel.refresh(target);
            }
        };
        String roles = connInstanceTO.getId() == 0 ? xmlRolesReader.getAllAllowedRoles("Connectors", "create")
                : xmlRolesReader.getAllAllowedRoles("Connectors", "update");
        MetaDataRoleAuthorizationStrategy.authorize(submit, ENABLE, roles);
        connectorForm.add(submit);

        final IndicatingAjaxButton cancel = new IndicatingAjaxButton(CANCEL, new ResourceModel(CANCEL)) {

            private static final long serialVersionUID = -958724007591692537L;

            @Override
            protected void onSubmit(final AjaxRequestTarget target, final Form<?> form) {
                window.close(target);
            }
        };
        cancel.setDefaultFormProcessing(false);
        connectorForm.add(cancel);
    }

    private ConnBundleTO getSelectedBundleTO(final ConnInstanceTO connInstanceTO) {
        ConnBundleTO result = null;
        if (connInstanceTO != null && StringUtils.isNotBlank(connInstanceTO.getLocation())
                && StringUtils.isNotBlank(connInstanceTO.getBundleName())
                && StringUtils.isNotBlank(connInstanceTO.getVersion())
                && mapConnBundleTOs.containsKey(connInstanceTO.getLocation())) {

            Map<String, Map<String, ConnBundleTO>> byLocation = mapConnBundleTOs.get(connInstanceTO.getLocation());
            if (byLocation.containsKey(connInstanceTO.getBundleName())) {
                Map<String, ConnBundleTO> byName = byLocation.get(connInstanceTO.getBundleName());
                if (byName.containsKey(connInstanceTO.getVersion())) {
                    result = byName.get(connInstanceTO.getVersion());
                }
            }
        }
        return result;
    }

    private List<ConnConfProperty> fillProperties(final ConnBundleTO bundleTO,
            final ConnInstanceTO connInstanceTO) {
        final List<ConnConfProperty> props = new ArrayList<ConnConfProperty>();

        if (bundleTO != null) {
            for (ConnConfPropSchema key : bundleTO.getProperties()) {
                final ConnConfProperty property = new ConnConfProperty();
                property.setSchema(key);
                if (connInstanceTO.getId() != 0 && connInstanceTO.getConfigurationMap().containsKey(key.getName())
                        && connInstanceTO.getConfigurationMap().get(key.getName()).getValues() != null) {

                    property.getValues()
                            .addAll(connInstanceTO.getConfigurationMap().get(key.getName()).getValues());
                    property.setOverridable(
                            connInstanceTO.getConfigurationMap().get(key.getName()).isOverridable());
                }

                if (property.getValues().isEmpty() && !key.getDefaultValues().isEmpty()) {
                    property.getValues().addAll(key.getDefaultValues());
                }

                props.add(property);
            }
        }

        // re-order properties (implements Comparable)
        Collections.sort(props);
        return props;
    }

    private void selectVersion(final AjaxRequestTarget target, final ConnInstanceTO connInstanceTO,
            final AjaxDropDownChoicePanel<String> version, final String versionValue) {

        connInstanceTO.setVersion(versionValue);
        target.add(version);

        bundleTO = getSelectedBundleTO(connInstanceTO);
        properties = fillProperties(bundleTO, connInstanceTO);
        target.add(propertiesContainer);
    }

    public List<ConnConfProperty> getProperties() {
        return properties;
    }
}