/* * 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.component.wizard.resource; import com.evolveum.midpoint.gui.api.component.result.OpResult; import com.evolveum.midpoint.gui.api.model.NonEmptyLoadableModel; import com.evolveum.midpoint.gui.api.page.PageBase; import com.evolveum.midpoint.gui.api.util.WebComponentUtil; import com.evolveum.midpoint.gui.api.util.WebModelServiceUtils; import com.evolveum.midpoint.model.api.ModelService; import com.evolveum.midpoint.prism.*; import com.evolveum.midpoint.prism.delta.ObjectDelta; import com.evolveum.midpoint.prism.path.ItemPath; import com.evolveum.midpoint.prism.schema.PrismSchema; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.schema.util.ConnectorTypeUtil; import com.evolveum.midpoint.schema.util.ResourceTypeUtil; import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.util.exception.ObjectNotFoundException; import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.util.exception.SystemException; import com.evolveum.midpoint.util.logging.LoggingUtils; 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.TabbedPanel; import com.evolveum.midpoint.web.component.prism.ContainerStatus; import com.evolveum.midpoint.web.component.prism.ContainerWrapper; import com.evolveum.midpoint.web.component.prism.ContainerWrapperFactory; import com.evolveum.midpoint.web.component.prism.PrismContainerPanel; import com.evolveum.midpoint.web.component.util.VisibleEnableBehaviour; import com.evolveum.midpoint.web.component.wizard.WizardStep; import com.evolveum.midpoint.web.page.admin.resources.PageResourceWizard; import com.evolveum.midpoint.web.page.admin.resources.component.TestConnectionResultPanel; import com.evolveum.midpoint.xml.ns._public.common.common_3.ConnectorConfigurationType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ConnectorType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceType; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.extensions.markup.html.tabs.AbstractTab; import org.apache.wicket.extensions.markup.html.tabs.ITab; import org.apache.wicket.markup.html.WebMarkupContainer; import org.apache.wicket.markup.html.form.Form; import org.apache.wicket.model.Model; import org.apache.wicket.model.util.ListModel; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; /** * @author lazyman * @author mederly */ public class ConfigurationStep extends WizardStep { private static final Trace LOGGER = TraceManager.getTrace(ConfigurationStep.class); private static final String DOT_CLASS = ConfigurationStep.class.getName() + "."; private static final String TEST_CONNECTION = DOT_CLASS + "testConnection"; private static final String OPERATION_SAVE = DOT_CLASS + "saveResource"; private static final String ID_CONFIGURATION = "configuration"; private static final String ID_TEST_CONNECTION = "testConnection"; private static final String ID_MAIN = "main"; final private NonEmptyLoadableModel<PrismObject<ResourceType>> resourceModelNoFetch; final private NonEmptyLoadableModel<List<ContainerWrapper>> configurationPropertiesModel; final private PageResourceWizard parentPage; public ConfigurationStep(NonEmptyLoadableModel<PrismObject<ResourceType>> modelNoFetch, final PageResourceWizard parentPage) { super(parentPage); this.resourceModelNoFetch = modelNoFetch; this.parentPage = parentPage; this.configurationPropertiesModel = new NonEmptyLoadableModel<List<ContainerWrapper>>(false) { @Override @NotNull protected List<ContainerWrapper> load() { try { return createConfigContainerWrappers(); } catch (SchemaException e) { throw new SystemException(e.getMessage(), e); } } }; parentPage.registerDependentModel(configurationPropertiesModel); initLayout(); } @NotNull private List<ContainerWrapper> createConfigContainerWrappers() throws SchemaException { PrismObject<ResourceType> resource = resourceModelNoFetch.getObject(); PrismContainer<ConnectorConfigurationType> configuration = resource.findContainer(ResourceType.F_CONNECTOR_CONFIGURATION); List<ContainerWrapper> containerWrappers = new ArrayList<>(); if (configuration == null) { PrismObject<ConnectorType> connector = ResourceTypeUtil.getConnectorIfPresent(resource); if (connector == null) { throw new IllegalStateException("No resolved connector object in resource object"); } ConnectorType connectorType = connector.asObjectable(); PrismSchema schema; try { schema = ConnectorTypeUtil.parseConnectorSchema(connectorType, parentPage.getPrismContext()); } catch (SchemaException e) { throw new SystemException("Couldn't parse connector schema: " + e.getMessage(), e); } PrismContainerDefinition<ConnectorConfigurationType> definition = ConnectorTypeUtil.findConfigurationContainerDefinition(connectorType, schema); // Fixing (errorneously) set maxOccurs = unbounded. See MID-2317 and related issues. PrismContainerDefinition<ConnectorConfigurationType> definitionFixed = definition.clone(); ((PrismContainerDefinitionImpl) definitionFixed).setMaxOccurs(1); configuration = definitionFixed.instantiate(); } List<PrismContainerDefinition> containerDefinitions = getSortedConfigContainerDefinitions(configuration); for (PrismContainerDefinition<?> containerDef : containerDefinitions) { ItemPath containerPath = new ItemPath(ResourceType.F_CONNECTOR_CONFIGURATION, containerDef.getName()); PrismContainer container = configuration.findContainer(containerDef.getName()); ContainerWrapperFactory cwf = new ContainerWrapperFactory(parentPage); ContainerWrapper containerWrapper; if (container != null) { containerWrapper = cwf.createContainerWrapper(container, ContainerStatus.MODIFYING, containerPath, parentPage.isReadOnly()); } else { container = containerDef.instantiate(); containerWrapper = cwf.createContainerWrapper(container, ContainerStatus.ADDING, containerPath, parentPage.isReadOnly()); } containerWrappers.add(containerWrapper); } return containerWrappers; } @NotNull private List<PrismContainerDefinition> getSortedConfigContainerDefinitions(PrismContainer<ConnectorConfigurationType> configuration) { List<PrismContainerDefinition> relevantDefinitions = new ArrayList<>(); for (ItemDefinition<?> def : configuration.getDefinition().getDefinitions()) { if (def instanceof PrismContainerDefinition) { relevantDefinitions.add((PrismContainerDefinition) def); } } Collections.sort(relevantDefinitions, new Comparator<PrismContainerDefinition>() { @Override public int compare(PrismContainerDefinition o1, PrismContainerDefinition o2) { int ord1 = o1.getDisplayOrder() != null ? o1.getDisplayOrder() : Integer.MAX_VALUE; int ord2 = o2.getDisplayOrder() != null ? o2.getDisplayOrder() : Integer.MAX_VALUE; return Integer.compare(ord1, ord2); } }); return relevantDefinitions; } @Override protected void onConfigure() { updateConfigurationTabs(); } private void initLayout() { com.evolveum.midpoint.web.component.form.Form form = new com.evolveum.midpoint.web.component.form.Form<>(ID_MAIN, true); form.setOutputMarkupId(true); add(form); form.add(WebComponentUtil.createTabPanel(ID_CONFIGURATION, parentPage, new ArrayList<ITab>(), null)); AjaxSubmitButton testConnection = new AjaxSubmitButton(ID_TEST_CONNECTION, createStringResource("ConfigurationStep.button.testConnection")) { @Override protected void onError(final AjaxRequestTarget target, Form<?> form) { WebComponentUtil.refreshFeedbacks(form, target); } @Override protected void onSubmit(AjaxRequestTarget target, Form<?> form) { testConnectionPerformed(target); } }; testConnection.add(new VisibleEnableBehaviour() { @Override public boolean isVisible() { return !parentPage.isReadOnly(); } }); add(testConnection); } private void updateConfigurationTabs() { final com.evolveum.midpoint.web.component.form.Form form = getForm(); TabbedPanel<ITab> tabbedPanel = getConfigurationTabbedPanel(); List<ITab> tabs = tabbedPanel.getTabs().getObject(); tabs.clear(); List<ContainerWrapper> wrappers = configurationPropertiesModel.getObject(); for (final ContainerWrapper wrapper : wrappers) { String tabName = getString(wrapper.getDisplayName(), null, wrapper.getDisplayName()); tabs.add(new AbstractTab(new Model<>(tabName)) { @Override public WebMarkupContainer getPanel(String panelId) { return new PrismContainerPanel(panelId, new Model<>(wrapper), true, form, parentPage); } }); } int i = tabbedPanel.getSelectedTab(); if (i < 0 || i > tabs.size()) { i = 0; } tabbedPanel.setSelectedTab(i); } @SuppressWarnings("unchecked") private com.evolveum.midpoint.web.component.form.Form getForm() { return (com.evolveum.midpoint.web.component.form.Form) get(ID_MAIN); } @SuppressWarnings("unchecked") private TabbedPanel<ITab> getConfigurationTabbedPanel() { return (TabbedPanel<ITab>) get(createComponentPath(ID_MAIN, ID_CONFIGURATION)); } // copied from PageResource, TODO deduplicate private void testConnectionPerformed(AjaxRequestTarget target) { parentPage.refreshIssues(null); if (parentPage.isReadOnly() || !isComplete()) { return; } saveChanges(); PageBase page = getPageBase(); TestConnectionResultPanel testConnectionPanel = new TestConnectionResultPanel(page.getMainPopupBodyId(), resourceModelNoFetch.getObject().getOid(), getPage()); testConnectionPanel.setOutputMarkupId(true); page.showMainPopup(testConnectionPanel, target); // page.showResult(result, "Test connection failed", false); target.add(page.getFeedbackPanel()); target.add(getForm()); } @Override public void applyState() { parentPage.refreshIssues(null); if (parentPage.isReadOnly() || !isComplete()) { return; } saveChanges(); } private void saveChanges() { Task task = parentPage.createSimpleTask(OPERATION_SAVE); OperationResult result = task.getResult(); boolean saved = false; try { List<ContainerWrapper> wrappers = configurationPropertiesModel.getObject(); ObjectDelta delta = ObjectDelta.createEmptyModifyDelta(ResourceType.class, parentPage.getEditedResourceOid(), parentPage.getPrismContext()); for (ContainerWrapper wrapper : wrappers) { wrapper.collectModifications(delta); } if (!delta.isEmpty()) { parentPage.logDelta(delta); WebModelServiceUtils.save(delta, result, parentPage); parentPage.resetModels(); saved = true; } } catch (Exception ex) { LoggingUtils.logUnexpectedException(LOGGER, "Error occurred during saving changes", ex); result.recordFatalError("Couldn't save configuration changes.", ex); } finally { result.computeStatusIfUnknown(); setResult(result); } if (parentPage.showSaveResultInPage(saved, result)) { parentPage.showResult(result); } configurationPropertiesModel.reset(); updateConfigurationTabs(); } }