Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

import com.evolveum.midpoint.gui.api.component.DisplayNamePanel;
import com.evolveum.midpoint.gui.api.component.tabs.PanelTab;
import com.evolveum.midpoint.gui.impl.component.input.range.MappingRangePanel;
import com.evolveum.midpoint.gui.api.prism.wrapper.ItemWrapper;
import com.evolveum.midpoint.gui.api.prism.wrapper.PrismContainerValueWrapper;
import com.evolveum.midpoint.gui.api.prism.wrapper.PrismContainerWrapper;
Expand Down Expand Up @@ -127,6 +128,20 @@ protected WebMarkupContainer getMultivalueContainerDetailsPanel(ListItem<PrismCo
protected DisplayNamePanel<MappingType> createDisplayNamePanel(String displayNamePanelId) {
return new DisplayNamePanel<>(displayNamePanelId, Model.of(item.getModelObject().getRealValue()));
}

@Override
protected @NotNull List<ITab> createTabs() {
List<ITab> mappingTabs = super.createTabs();
mappingTabs.add(new PanelTab(createStringResource("MappingRangePanel.range")) {
@Serial private static final long serialVersionUID = 1L;

@Override
public WebMarkupContainer createPanel(String panelId) {
return new MappingRangePanel(panelId, getModel());
}
});
return mappingTabs;
}
};
}
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*
* Copyright (C) 2026 Evolveum and contributors
*
* Licensed under the EUPL-1.2 or later.
*/

package com.evolveum.midpoint.gui.impl.component.input.range;

import java.io.Serial;

import org.apache.wicket.model.IModel;

import com.evolveum.midpoint.gui.api.prism.wrapper.PrismContainerValueWrapper;
import com.evolveum.midpoint.gui.api.prism.wrapper.PrismPropertyWrapper;
import com.evolveum.midpoint.gui.api.prism.wrapper.PrismValueWrapper;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
import com.evolveum.midpoint.web.util.ExpressionUtil;
import com.evolveum.midpoint.xml.ns._public.common.common_3.MappingType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ValueSetDefinitionType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.VariableBindingDefinitionType;

/**
* Range of a mapping, which the schema keeps in the set of the mapping target.
*
*
* @author jjarabinec
*/
public class MappingRangeModel implements IModel<ValueSetDefinitionType> {

@Serial private static final long serialVersionUID = 1L;

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

private final IModel<PrismContainerValueWrapper<MappingType>> mappingModel;

public MappingRangeModel(IModel<PrismContainerValueWrapper<MappingType>> mappingModel) {
this.mappingModel = mappingModel;
}

@Override
public ValueSetDefinitionType getObject() {
VariableBindingDefinitionType target = getTarget();
return target != null ? target.getSet() : null;
}

@Override
public void setObject(ValueSetDefinitionType set) {
PrismValueWrapper<VariableBindingDefinitionType> value = findTargetValue();
if (value == null) {
LOGGER.error("Target of the mapping {} not found, there is nothing to store the range into", getMapping());
return;
}

VariableBindingDefinitionType current = value.getRealValue();
VariableBindingDefinitionType updated =
current != null ? current.clone() : new VariableBindingDefinitionType();

updated.setSet(isEmpty(set) ? null : set);
value.setRealValue(updated);
}

private static boolean isEmpty(ValueSetDefinitionType set) {
return set == null
|| (set.getPredefined() == null
&& ExpressionUtil.isEmpty(set.getCondition())
&& ExpressionUtil.isEmpty(set.getYieldCondition())
&& set.getAdditionalMappingSpecification().isEmpty());
}

private VariableBindingDefinitionType getTarget() {
MappingType mapping = getMapping();
return mapping != null ? mapping.getTarget() : null;
}

private MappingType getMapping() {
PrismContainerValueWrapper<MappingType> mappingValue = mappingModel.getObject();
return mappingValue != null ? mappingValue.getRealValue() : null;
}

private PrismValueWrapper<VariableBindingDefinitionType> findTargetValue() {
PrismContainerValueWrapper<MappingType> mappingValue = mappingModel.getObject();
if (mappingValue == null) {
return null;
}

try {
PrismPropertyWrapper<VariableBindingDefinitionType> wrapper =
mappingValue.findProperty(MappingType.F_TARGET);
return wrapper != null ? wrapper.getValue() : null;
} catch (SchemaException ex) {
LOGGER.warn("Couldn't find the target of the mapping {}: {}", getMapping(), ex.getMessage(), ex);
return null;
}
}

@Override
public void detach() {
mappingModel.detach();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Copyright (C) 2026 Evolveum and contributors
*
* Licensed under the EUPL-1.2 or later.
*/

package com.evolveum.midpoint.gui.impl.component.input.range;

import com.evolveum.midpoint.web.util.ExpressionUtil;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ValueSetDefinitionPredefinedType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ValueSetDefinitionType;

/**
* Range of a mapping as it is offered by the GUI.
*
* @author jjarabinec
*/
public enum MappingRangeOption {

ALL(ValueSetDefinitionPredefinedType.ALL),
MATCHING_PROVENANCE(ValueSetDefinitionPredefinedType.MATCHING_PROVENANCE),

CONDITION(null),

NONE(ValueSetDefinitionPredefinedType.NONE);

private final ValueSetDefinitionPredefinedType predefined;

MappingRangeOption(ValueSetDefinitionPredefinedType predefined) {
this.predefined = predefined;
}

public ValueSetDefinitionPredefinedType getPredefined() {
return predefined;
}

/**
* Reads the option out of the set of a mapping target.
*
* @param set set to read, null when the mapping has no range.
* @return the option the set stands for, or null when it stands for none of them.
*/
public static MappingRangeOption of(ValueSetDefinitionType set) {
if (set == null) {
return null;
}

if (!ExpressionUtil.isEmpty(set.getCondition())) {
return CONDITION;
}

ValueSetDefinitionPredefinedType predefined = set.getPredefined();
if (predefined == null) {
return null;
}

return switch (predefined) {
case ALL -> ALL;
case MATCHING_PROVENANCE -> MATCHING_PROVENANCE;
case NONE -> NONE;
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<!DOCTYPE html>
<!--
~ Copyright (c) 2026 Evolveum
~
~ Licensed under the EUPL-1.2 or later.
-->

<html xmlns:wicket="http://wicket.apache.org">
<wicket:panel>
<div class="pb-2">
<div class="prism-property-label p-0">
<span><wicket:message key="MappingRangePanel.range"/></span>
</div>
<div class="prism-property-value" wicket:id="rangeChoice"/>
</div>

<wicket:enclosure child="condition">
<div class="pb-2">
<div class="prism-property-label p-0">
<span><wicket:message key="MappingRangePanel.condition"/></span>
</div>
<div class="prism-property-value" wicket:id="condition"/>
</div>
</wicket:enclosure>
</wicket:panel>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
/*
* Copyright (C) 2026 Evolveum and contributors
*
* Licensed under the EUPL-1.2 or later.
*/

package com.evolveum.midpoint.gui.impl.component.input.range;

import java.io.Serial;
import java.util.List;

import org.apache.wicket.Component;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.markup.html.form.EnumChoiceRenderer;
import org.apache.wicket.model.IModel;

import com.evolveum.midpoint.gui.api.component.BasePanel;
import com.evolveum.midpoint.gui.api.prism.wrapper.PrismContainerValueWrapper;
import com.evolveum.midpoint.gui.impl.component.input.expression.ExpressionPanel;
import com.evolveum.midpoint.web.component.input.DropDownChoicePanel;
import com.evolveum.midpoint.web.component.util.VisibleBehaviour;
import com.evolveum.midpoint.web.page.admin.configuration.component.EmptyOnChangeAjaxFormUpdatingBehavior;
import com.evolveum.midpoint.web.util.ExpressionUtil;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ExpressionType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.MappingType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ValueSetDefinitionType;

/**
* Range of a mapping, telling which of the existing target values the mapping is in charge of.
*
* @author jjarabinec
*/
public class MappingRangePanel extends BasePanel<PrismContainerValueWrapper<MappingType>> {

@Serial private static final long serialVersionUID = 1L;

private static final String ID_RANGE_CHOICE = "rangeChoice";
private static final String ID_CONDITION = "condition";

private MappingRangeModel rangeModel;

private MappingRangeOption selectedOption;

public MappingRangePanel(String id, IModel<PrismContainerValueWrapper<MappingType>> model) {
super(id, model);
}

@Override
protected void onInitialize() {
super.onInitialize();

setOutputMarkupId(true);
rangeModel = new MappingRangeModel(getModel());

add(createRangeChoice());
add(createConditionPanel());
}

private Component createRangeChoice() {
IModel<List<MappingRangeOption>> options = () -> MappingRangeUtils.optionsFor(getModelObject());

DropDownChoicePanel<MappingRangeOption> choice = new DropDownChoicePanel<>(
ID_RANGE_CHOICE, createOptionModel(), options, new EnumChoiceRenderer<>(this), true);

choice.setOutputMarkupId(true);
choice.getBaseFormComponent().add(new EmptyOnChangeAjaxFormUpdatingBehavior() {

@Override
protected void onUpdate(AjaxRequestTarget target) {
super.onUpdate(target);
target.add(MappingRangePanel.this);
}
});

return choice;
}

private Component createConditionPanel() {
ExpressionPanel condition = new ExpressionPanel(ID_CONDITION, createConditionModel()) {

@Override
protected List<RecognizedEvaluator> getChoices() {
return List.of(RecognizedEvaluator.SCRIPT, RecognizedEvaluator.FILTER);
}
};

condition.setEvaluatorPanelExpanded(true);
condition.add(new VisibleBehaviour(() -> MappingRangeOption.CONDITION == getSelectedOption()));
return condition;
}

private IModel<MappingRangeOption> createOptionModel() {
return new IModel<>() {

@Override
public MappingRangeOption getObject() {
return getSelectedOption();
}

@Override
public void setObject(MappingRangeOption option) {
selectedOption = option;
storeOption(option);
}
};
}

private MappingRangeOption getSelectedOption() {
return selectedOption != null ? selectedOption : MappingRangeOption.of(rangeModel.getObject());
}

private void storeOption(MappingRangeOption option) {
ValueSetDefinitionType updated = copyOfRange();

if (MappingRangeOption.CONDITION == option) {
updated.setPredefined(null);
} else {
updated.setCondition(null);
updated.setPredefined(option != null ? option.getPredefined() : null);
}

rangeModel.setObject(updated);
}

private IModel<ExpressionType> createConditionModel() {
return new IModel<>() {

@Override
public ExpressionType getObject() {
ValueSetDefinitionType set = rangeModel.getObject();
return set != null ? set.getCondition() : null;
}

@Override
public void setObject(ExpressionType condition) {
ValueSetDefinitionType updated = copyOfRange();
updated.setCondition(ExpressionUtil.hasEvaluatorContent(condition) ? condition : null);
rangeModel.setObject(updated);
}
};
}

private ValueSetDefinitionType copyOfRange() {
ValueSetDefinitionType current = rangeModel.getObject();
return current != null ? current.clone() : new ValueSetDefinitionType();
}
}
Loading
Loading