/*
* Copyright (c) 2010-2017 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.model.common.mapping;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.xml.datatype.DatatypeConstants;
import javax.xml.datatype.Duration;
import javax.xml.datatype.XMLGregorianCalendar;
import javax.xml.namespace.QName;
import com.evolveum.midpoint.prism.*;
import com.evolveum.midpoint.schema.SchemaConstantsGenerated;
import com.evolveum.midpoint.schema.constants.ExpressionConstants;
import com.evolveum.midpoint.security.api.SecurityEnforcer;
import com.evolveum.midpoint.xml.ns._public.common.common_3.*;
import com.evolveum.prism.xml.ns._public.types_3.ItemPathType;
import org.jetbrains.annotations.NotNull;
import org.w3c.dom.Element;
import com.evolveum.midpoint.common.filter.Filter;
import com.evolveum.midpoint.common.filter.FilterManager;
import com.evolveum.midpoint.common.refinery.RefinedObjectClassDefinition;
import com.evolveum.midpoint.model.common.expression.Expression;
import com.evolveum.midpoint.model.common.expression.ExpressionEvaluationContext;
import com.evolveum.midpoint.model.common.expression.ExpressionFactory;
import com.evolveum.midpoint.model.common.expression.ExpressionUtil;
import com.evolveum.midpoint.model.common.expression.ExpressionVariables;
import com.evolveum.midpoint.model.common.expression.ItemDeltaItem;
import com.evolveum.midpoint.model.common.expression.ObjectDeltaObject;
import com.evolveum.midpoint.model.common.expression.Source;
import com.evolveum.midpoint.model.common.expression.StringPolicyResolver;
import com.evolveum.midpoint.model.common.expression.ValueSetDefinition;
import com.evolveum.midpoint.prism.delta.PrismValueDeltaSetTriple;
import com.evolveum.midpoint.prism.delta.ItemDelta;
import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.schema.internals.InternalsConfig;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.schema.util.SchemaDebugUtil;
import com.evolveum.midpoint.schema.util.ObjectResolver;
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.util.DOMUtil;
import com.evolveum.midpoint.util.DebugDumpable;
import com.evolveum.midpoint.util.MiscUtil;
import com.evolveum.midpoint.util.exception.ExpressionEvaluationException;
import com.evolveum.midpoint.util.exception.ObjectNotFoundException;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.util.exception.TunnelException;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
/**
*
* Mapping is non-recyclable single-use object. Once evaluated it should not be evaluated again. It will retain its original
* inputs and outputs that can be read again and again. But these should not be changed after evaluation.
*
* Configuration properties are unmodifiable. They are to be set via Mapping.Builder.
*
* @author Radovan Semancik
*
*/
public class Mapping<V extends PrismValue,D extends ItemDefinition> implements DebugDumpable, PrismValueDeltaSetTripleProducer<V, D> {
// configuration properties (unmodifiable)
private final MappingType mappingType;
private final ExpressionFactory expressionFactory;
private final ExpressionVariables variables;
private final ObjectDeltaObject<?> sourceContext;
private final Collection<Source<?,?>> sources;
private final Source<?,?> defaultSource;
private final PrismObjectDefinition<?> targetContext;
private final ItemPath defaultTargetPath;
private final D defaultTargetDefinition;
private final Collection<V> originalTargetValues;
private final ObjectResolver objectResolver;
private final SecurityEnforcer securityEnforcer; // in order to get c:actor variable
private final OriginType originType;
private final ObjectType originObject;
private final FilterManager<Filter> filterManager;
private final StringPolicyResolver stringPolicyResolver;
private final boolean conditionMaskOld;
private final boolean conditionMaskNew;
private final XMLGregorianCalendar defaultReferenceTime;
private final XMLGregorianCalendar now;
private final boolean profiling;
private final String contextDescription;
private final QName mappingQName; // This is sometimes used to identify the element that mapping produces
// if it is different from itemName. E.g. this happens with associations.
private final RefinedObjectClassDefinition refinedObjectClassDefinition;
// working and output properties
private D outputDefinition;
private ItemPath outputPath;
private MappingEvaluationState state = MappingEvaluationState.UNINITIALIZED;
private PrismValueDeltaSetTriple<V> outputTriple;
private PrismValueDeltaSetTriple<PrismPropertyValue<Boolean>> conditionOutputTriple;
private Boolean timeConstraintValid = null;
private XMLGregorianCalendar nextRecomputeTime = null;
private Long evaluationStartTime = null;
private Long evaluationEndTime = null;
private String mappingContextDescription = null;
// This is single-use only. Once evaluated it is not used any more
// it is remembered only for tracing purposes.
private Expression<V,D> expression;
private static final Trace LOGGER = TraceManager.getTrace(Mapping.class);
private Mapping(Builder<V,D> builder) {
expressionFactory = builder.expressionFactory;
variables = builder.variables;
mappingType = builder.mappingType;
objectResolver = builder.objectResolver;
securityEnforcer = builder.securityEnforcer;
defaultSource = builder.defaultSource;
defaultTargetDefinition = builder.defaultTargetDefinition;
defaultTargetPath = builder.defaultTargetPath;
originalTargetValues = builder.originalTargetValues;
sourceContext = builder.sourceContext;
targetContext = builder.targetContext;
sources = builder.sources;
originType = builder.originType;
originObject = builder.originObject;
filterManager = builder.filterManager;
stringPolicyResolver = builder.stringPolicyResolver;
conditionMaskOld = builder.conditionMaskOld;
conditionMaskNew = builder.conditionMaskNew;
defaultReferenceTime = builder.defaultReferenceTime;
profiling = builder.profiling;
contextDescription = builder.contextDescription;
mappingQName = builder.mappingQName;
refinedObjectClassDefinition = builder.refinedObjectClassDefinition;
now = builder.now;
}
public ObjectResolver getObjectResolver() {
return objectResolver;
}
public QName getItemName() {
if (outputDefinition != null) {
return outputDefinition.getName();
}
return null;
}
public OriginType getOriginType() {
return originType;
}
public ObjectType getOriginObject() {
return originObject;
}
public Source<?,?> getDefaultSource() {
return defaultSource;
}
public D getDefaultTargetDefinition() {
return defaultTargetDefinition;
}
public ItemPath getDefaultTargetPath() {
return defaultTargetPath;
}
public ObjectDeltaObject<?> getSourceContext() {
return sourceContext;
}
public PrismObjectDefinition<?> getTargetContext() {
return targetContext;
}
public String getContextDescription() {
return contextDescription;
}
public String getMappingContextDescription() {
if (mappingContextDescription == null) {
StringBuilder sb = new StringBuilder("mapping ");
if (mappingType.getName() != null) {
sb.append("'").append(mappingType.getName()).append("' ");
}
sb.append("in ");
sb.append(contextDescription);
mappingContextDescription = sb.toString();
}
return mappingContextDescription;
}
public MappingType getMappingType() {
return mappingType;
}
@Override
public boolean isSourceless() {
return sources.isEmpty();
}
public MappingStrengthType getStrength() {
return getStrength(mappingType);
}
public static MappingStrengthType getStrength(MappingType mappingType) {
if (mappingType == null) {
return MappingStrengthType.NORMAL;
}
MappingStrengthType value = mappingType.getStrength();
if (value == null) {
value = MappingStrengthType.NORMAL;
}
return value;
}
public boolean isAuthoritative() {
if (mappingType == null) {
return true;
}
Boolean value = mappingType.isAuthoritative();
if (value == null) {
value = true;
}
return value;
}
public boolean isExclusive() {
if (mappingType == null) {
return false;
}
Boolean value = mappingType.isExclusive();
if (value == null) {
value = false;
}
return value;
}
public Boolean isTolerant() {
if (mappingType == null) {
return null;
}
return mappingType.isTolerant();
}
public boolean isConditionMaskOld() {
return conditionMaskOld;
}
public boolean isConditionMaskNew() {
return conditionMaskNew;
}
private PrismContext getPrismContext() {
return outputDefinition.getPrismContext();
}
public FilterManager<Filter> getFilterManager() {
return filterManager;
}
public StringPolicyResolver getStringPolicyResolver() {
return stringPolicyResolver;
}
public boolean isApplicableToChannel(String channelUri) {
return isApplicableToChannel(mappingType, channelUri);
}
public static boolean isApplicableToChannel(MappingType mappingType, String channelUri) {
List<String> exceptChannel = mappingType.getExceptChannel();
if (exceptChannel != null && !exceptChannel.isEmpty()){
return !exceptChannel.contains(channelUri);
}
List<String> applicableChannels = mappingType.getChannel();
if (applicableChannels == null || applicableChannels.isEmpty()) {
return true;
}
return applicableChannels.contains(channelUri);
}
public XMLGregorianCalendar getNow() {
return now;
}
public XMLGregorianCalendar getDefaultReferenceTime() {
return defaultReferenceTime;
}
public XMLGregorianCalendar getNextRecomputeTime() {
return nextRecomputeTime;
}
public boolean isProfiling() {
return profiling;
}
public Long getEvaluationStartTime() {
return evaluationStartTime;
}
public Long getEvaluationEndTime() {
return evaluationEndTime;
}
public Long getEtime() {
if (evaluationStartTime == null || evaluationEndTime == null) {
return null;
}
return evaluationEndTime - evaluationStartTime;
}
/* (non-Javadoc)
* @see com.evolveum.midpoint.model.common.mapping.PrismValueDeltaSetTripleProducer#getMappingQName()
*/
@Override
public QName getMappingQName() {
return mappingQName;
}
public RefinedObjectClassDefinition getRefinedObjectClassDefinition() {
return refinedObjectClassDefinition;
}
// TODO: rename to evaluateAll
public void evaluate(Task task, OperationResult parentResult) throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException {
prepare(task, parentResult);
// if (!isActivated()) {
// outputTriple = null;
// LOGGER.debug("Skipping evaluation of mapping {} in {} because it is not activated",
// mappingType.getName() == null?null:mappingType.getName(), contextDescription);
// return;
// }
evaluateBody(task, parentResult);
}
/**
* Prepare mapping for evaluation. Parse the values
* After this call it can checked if a mapping is activated
* (i.e. if the input changes will "trigger" the mapping).
*/
public void prepare(Task task, OperationResult parentResult) throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException {
OperationResult result = parentResult.createMinorSubresult(Mapping.class.getName()+".prepare");
assertState(MappingEvaluationState.UNINITIALIZED);
try {
parseSources(task, result);
parseTarget();
if (outputPath != null && outputDefinition == null) {
throw new IllegalArgumentException("No output definition, cannot evaluate "+getMappingContextDescription());
}
} catch (ExpressionEvaluationException | ObjectNotFoundException | RuntimeException | SchemaException | Error e) {
result.recordFatalError(e);
throw e;
}
transitionState(MappingEvaluationState.PREPARED);
result.recordSuccess();
}
public boolean isActivated() {
// TODO
// return isActivated;
return sourcesChanged();
}
// TODO: rename to evaluate
public void evaluateBody(Task task, OperationResult parentResult) throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException {
assertState(MappingEvaluationState.PREPARED);
OperationResult result = parentResult.createMinorSubresult(Mapping.class.getName()+".evaluate");
traceEvaluationStart();
try {
// We may need to re-parse the sources here
evaluateTimeConstraintValid(task, result);
if (!timeConstraintValid) {
outputTriple = null;
result.recordNotApplicableIfUnknown();
traceDeferred();
return;
}
evaluateCondition(task, result);
boolean conditionOutputOld = computeConditionResult(conditionOutputTriple.getNonPositiveValues());
boolean conditionResultOld = conditionOutputOld && conditionMaskOld;
boolean conditionOutputNew = computeConditionResult(conditionOutputTriple.getNonNegativeValues());
boolean conditionResultNew = conditionOutputNew && conditionMaskNew;
if (!conditionResultOld && !conditionResultNew) {
outputTriple = null;
transitionState(MappingEvaluationState.EVALUATED);
result.recordNotApplicableIfUnknown();
traceNotApplicable("condition is false");
return;
}
// TODO: input filter
evaluateExpression(task, result, conditionResultOld, conditionResultNew);
fixDefinition();
recomputeValues();
setOrigin();
// TODO: output filter
checkRange(task, result);
transitionState(MappingEvaluationState.EVALUATED);
result.recordSuccess();
traceSuccess(conditionResultOld, conditionResultNew);
} catch (ExpressionEvaluationException | ObjectNotFoundException | RuntimeException | SchemaException | Error e) {
result.recordFatalError(e);
traceFailure(e);
throw e;
}
}
private void checkRange(Task task, OperationResult result)
throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException {
VariableBindingDefinitionType target = mappingType.getTarget();
if (target != null && target.getSet() != null) {
checkRangeTarget(task, result);
}
if (mappingType.getRange() != null) {
checkRangeLegacy(task, result);
}
}
private void checkRangeTarget(Task task, OperationResult result)
throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException {
if (originalTargetValues == null) {
throw new IllegalStateException("Couldn't check range for mapping in " + contextDescription + ", as original target values are not known.");
}
ValueSetDefinitionType rangetSetDefType = mappingType.getTarget().getSet();
QName name = outputPath.lastNamed().getName();
ValueSetDefinition setDef = new ValueSetDefinition(rangetSetDefType, name, "range of "+name.getLocalPart()+" in "+getMappingContextDescription(), task, result);
setDef.init(expressionFactory);
for (V originalValue : originalTargetValues) {
if (!setDef.contains(originalValue)) {
continue;
}
addToMinusIfNecessary(originalValue);
}
}
@SuppressWarnings("unchecked")
private void addToMinusIfNecessary(V originalValue) {
if (outputTriple != null && (outputTriple.presentInPlusSet(originalValue) || outputTriple.presentInZeroSet(originalValue))) {
return;
}
// remove it!
if (outputTriple == null) {
outputTriple = new PrismValueDeltaSetTriple<>();
}
LOGGER.trace("Original value is in the mapping range (while not in mapping result), adding it to minus set: {}", originalValue);
outputTriple.addToMinusSet((V)originalValue.clone());
}
private void checkRangeLegacy(Task task, OperationResult result)
throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException {
if (originalTargetValues == null) {
throw new IllegalStateException("Couldn't check range for mapping in " + contextDescription + ", as original target values are not known.");
}
for (V originalValue : originalTargetValues) {
if (!isInRange(originalValue, task, result)) {
continue;
}
addToMinusIfNecessary(originalValue);
}
}
private boolean isInRange(V value, Task task, OperationResult result) throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException {
@NotNull ValueSetSpecificationType range = mappingType.getRange();
if (range.getIsInSetExpression() == null) {
return false;
}
ExpressionVariables variables = new ExpressionVariables();
variables.addVariableDefinitions(this.variables); // TODO is this ok?
if (value instanceof PrismContainerValue) {
// artifically create parent for PCV in order to pass it to expression
PrismContainer.createParentIfNeeded((PrismContainerValue) value, outputDefinition);
}
variables.addVariableDefinition(ExpressionConstants.VAR_VALUE, value);
PrismPropertyDefinition<Boolean> outputDef = new PrismPropertyDefinitionImpl<Boolean>(SchemaConstantsGenerated.C_VALUE, DOMUtil.XSD_BOOLEAN, getPrismContext(), null, false);
PrismPropertyValue<Boolean> rv = ExpressionUtil.evaluateExpression(variables, outputDef, range.getIsInSetExpression(), expressionFactory, "isInSet expression in " + contextDescription, task, result);
// but now remove the parent!
if (value.getParent() != null) {
value.setParent(null);
}
return rv != null && rv.getValue() != null ? rv.getValue() : Boolean.FALSE;
}
public boolean isSatisfyCondition() {
boolean conditionOutputOld = computeConditionResult(conditionOutputTriple.getNonPositiveValues());
boolean conditionResultOld = conditionOutputOld && conditionMaskOld;
boolean conditionOutputNew = computeConditionResult(conditionOutputTriple.getNonNegativeValues());
boolean conditionResultNew = conditionOutputNew && conditionMaskNew;
return (conditionResultOld || conditionResultNew);
}
public PrismValueDeltaSetTriple<PrismPropertyValue<Boolean>> getConditionOutputTriple() {
return conditionOutputTriple;
}
private void traceEvaluationStart() {
if (profiling) {
evaluationStartTime = System.currentTimeMillis();
}
}
private void traceEvaluationEnd() {
if (profiling) {
evaluationEndTime = System.currentTimeMillis();
}
}
private void traceSuccess(boolean conditionResultOld, boolean conditionResultNew) {
traceEvaluationEnd();
if (!isTrace()) {
return;
}
StringBuilder sb = new StringBuilder();
sb.append("Mapping trace:\n");
appendTraceHeader(sb);
sb.append("\nCondition: ").append(conditionResultOld).append(" -> ").append(conditionResultNew);
if (nextRecomputeTime != null) {
sb.append("\nNext recompute: ");
sb.append(nextRecomputeTime);
}
sb.append("\nResult: ");
if (outputTriple == null) {
sb.append("null");
} else {
sb.append(outputTriple.toHumanReadableString());
}
if (profiling) {
sb.append("\nEtime: ");
sb.append(getEtime());
sb.append(" ms");
}
appendTraceFooter(sb);
trace(sb.toString());
}
private void traceDeferred() {
traceEvaluationEnd();
if (!isTrace()) {
return;
}
StringBuilder sb = new StringBuilder();
sb.append("Mapping trace:\n");
appendTraceHeader(sb);
sb.append("\nEvaluation DEFERRED to: ");
if (nextRecomputeTime == null) {
sb.append("null");
} else {
sb.append(nextRecomputeTime);
}
if (profiling) {
sb.append("\nEtime: ");
sb.append(getEtime());
sb.append(" ms");
}
appendTraceFooter(sb);
trace(sb.toString());
}
private void traceNotApplicable(String reason) {
traceEvaluationEnd();
if (!isTrace()) {
return;
}
StringBuilder sb = new StringBuilder();
sb.append("Mapping trace:\n");
appendTraceHeader(sb);
sb.append("\nEvaluation is NOT APPLICABLE because "+reason);
if (profiling) {
sb.append("\nEtime: ");
sb.append(getEtime());
sb.append(" ms");
}
appendTraceFooter(sb);
trace(sb.toString());
}
private void traceFailure(Throwable e) {
LOGGER.error("Error evaluating {}: {}", new Object[]{getMappingContextDescription(), e.getMessage(), e});
traceEvaluationEnd();
if (!isTrace()) {
return;
}
StringBuilder sb = new StringBuilder();
sb.append("Mapping FAILURE:\n");
appendTraceHeader(sb);
sb.append("\nERROR: ").append(e.getClass().getSimpleName()).append(": ").append(e.getMessage());
if (profiling) {
sb.append("\nEtime: ");
sb.append(getEtime());
sb.append(" ms");
}
appendTraceFooter(sb);
trace(sb.toString());
}
private boolean isTrace() {
return LOGGER.isTraceEnabled() || (mappingType != null && mappingType.isTrace() == Boolean.TRUE);
}
private void trace(String msg) {
if (mappingType != null && mappingType.isTrace() == Boolean.TRUE) {
LOGGER.info(msg);
} else {
LOGGER.trace(msg);
}
}
private void appendTraceHeader(StringBuilder sb) {
sb.append("---[ MAPPING ");
if (mappingType.getName() != null) {
sb.append("'").append(mappingType.getName()).append("' ");
}
sb.append(" in ");
sb.append(contextDescription);
sb.append("]---------------------------");
for (Source<?,?> source: sources) {
sb.append("\nSource: ");
sb.append(source.shortDebugDump());
}
sb.append("\nTarget: ").append(MiscUtil.toString(outputDefinition));
sb.append("\nExpression: ");
if (expression == null) {
sb.append("null");
} else {
sb.append(expression.shortDebugDump());
}
}
private void appendTraceFooter(StringBuilder sb) {
sb.append("\n------------------------------------------------------");
}
private boolean computeConditionResult(Collection<PrismPropertyValue<Boolean>> booleanPropertyValues) {
if (mappingType.getCondition() == null) {
// If condition is not present at all consider it to be true
return true;
}
return ExpressionUtil.computeConditionResult(booleanPropertyValues);
}
public Boolean evaluateTimeConstraintValid(Task task, OperationResult result) throws SchemaException, ObjectNotFoundException {
if (timeConstraintValid == null) {
parseTimeConstraints(task, result);
}
return timeConstraintValid;
}
private void parseTimeConstraints(Task task, OperationResult result) throws SchemaException, ObjectNotFoundException {
MappingTimeDeclarationType timeFromType = mappingType.getTimeFrom();
MappingTimeDeclarationType timeToType = mappingType.getTimeTo();
if (timeFromType == null && timeToType == null) {
timeConstraintValid = true;
return;
}
XMLGregorianCalendar timeFrom = parseTime(timeFromType, task, result);
if (timeFrom == null && timeFromType != null) {
// Time is specified but there is no value for it.
// This means that event that should start validity haven't happened yet
// therefore the mapping is not yet valid.
timeConstraintValid = false;
return;
}
XMLGregorianCalendar timeTo = parseTime(timeToType, task, result);
if (timeFrom != null && timeFrom.compare(now) == DatatypeConstants.GREATER) {
// before timeFrom
nextRecomputeTime = timeFrom;
timeConstraintValid = false;
return;
}
if (timeTo == null && timeToType != null) {
// Time is specified but there is no value for it.
// This means that event that should stop validity haven't happened yet
// therefore the mapping is still valid.
timeConstraintValid = true;
return;
}
if (timeTo != null && timeTo.compare(now) == DatatypeConstants.GREATER) {
// between timeFrom and timeTo (also no timeFrom and before timeTo)
nextRecomputeTime = timeTo;
timeConstraintValid = true;
return;
}
if (timeTo == null) {
// after timeFrom and no timeTo
// no nextRecomputeTime set, there is nothing to recompute in the future
timeConstraintValid = true;
return;
} else {
// after timeTo
// no nextRecomputeTime set, there is nothing to recompute in the future
timeConstraintValid = false;
return;
}
}
private XMLGregorianCalendar parseTime(MappingTimeDeclarationType timeType, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException {
if (timeType == null) {
return null;
}
XMLGregorianCalendar time;
VariableBindingDefinitionType referenceTimeType = timeType.getReferenceTime();
if (referenceTimeType == null) {
if (defaultReferenceTime == null) {
throw new SchemaException("No reference time specified (and there is also no default) in time specification in "+getMappingContextDescription());
} else {
time = (XMLGregorianCalendar) defaultReferenceTime.clone();
}
} else {
time = parseTimeSource(referenceTimeType, task, result);
if (time == null) {
// Reference time is specified but the value is not present.
return null;
}
time = (XMLGregorianCalendar) time.clone();
}
Duration offset = timeType.getOffset();
if (offset != null) {
time.add(offset);
}
return time;
}
private XMLGregorianCalendar parseTimeSource(VariableBindingDefinitionType sourceType, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException {
ItemPathType itemPathType = sourceType.getPath();
if (itemPathType == null) {
throw new SchemaException("No path in source definition in "+getMappingContextDescription());
}
ItemPath path = itemPathType.getItemPath();
if (path.isEmpty()) {
throw new SchemaException("Empty source path in "+getMappingContextDescription());
}
Object sourceObject = ExpressionUtil.resolvePath(path, variables, sourceContext, objectResolver, "reference time definition in "+getMappingContextDescription(), task, result);
if (sourceObject == null) {
return null;
}
PrismProperty<XMLGregorianCalendar> timeProperty;
if (sourceObject instanceof ItemDeltaItem<?,?>) {
timeProperty = (PrismProperty<XMLGregorianCalendar>) ((ItemDeltaItem<?,?>)sourceObject).getItemNew();
} else if (sourceObject instanceof Item<?,?>) {
timeProperty = (PrismProperty<XMLGregorianCalendar>) sourceObject;
} else {
throw new IllegalStateException("Unknown resolve result "+sourceObject);
}
if (timeProperty == null) {
return null;
}
return timeProperty.getRealValue();
}
private Collection<Source<?,?>> parseSources(Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException {
List<VariableBindingDefinitionType> sourceTypes = mappingType.getSource();
if (defaultSource != null) {
defaultSource.recompute();
sources.add(defaultSource);
defaultSource.recompute();
}
if (sourceTypes != null) {
for (VariableBindingDefinitionType sourceType: sourceTypes) {
Source<?,?> source = parseSource(sourceType, task, result);
source.recompute();
// Override existing sources (e.g. default source)
Iterator<Source<?,?>> iterator = sources.iterator();
while (iterator.hasNext()) {
Source<?,?> next = iterator.next();
if (next.getName().equals(source.getName())) {
iterator.remove();
}
}
sources.add(source);
}
}
return sources;
}
private <IV extends PrismValue, ID extends ItemDefinition> Source<IV,ID> parseSource(VariableBindingDefinitionType sourceType, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException {
ItemPathType itemPathType = sourceType.getPath();
if (itemPathType == null) {
throw new SchemaException("No path in source definition in "+getMappingContextDescription());
}
ItemPath path = itemPathType.getItemPath();
if (path.isEmpty()) {
throw new SchemaException("Empty source path in "+getMappingContextDescription());
}
QName name = sourceType.getName();
if (name == null) {
name = ItemPath.getName(path.last());
}
ItemPath resolvePath = path;
Object sourceObject = ExpressionUtil.resolvePath(path, variables, sourceContext, objectResolver, "source definition in "+getMappingContextDescription(), task, result);
Item<IV,ID> itemOld = null;
ItemDelta<IV,ID> delta = null;
Item<IV,ID> itemNew = null;
ItemPath residualPath = null;
Collection<? extends ItemDelta<?,?>> subItemDeltas = null;
if (sourceObject != null) {
if (sourceObject instanceof ItemDeltaItem<?,?>) {
itemOld = ((ItemDeltaItem<IV,ID>)sourceObject).getItemOld();
delta = ((ItemDeltaItem<IV,ID>)sourceObject).getDelta();
itemNew = ((ItemDeltaItem<IV,ID>)sourceObject).getItemNew();
residualPath = ((ItemDeltaItem<IV,ID>)sourceObject).getResidualPath();
resolvePath = ((ItemDeltaItem<IV,ID>)sourceObject).getResolvePath();
subItemDeltas = ((ItemDeltaItem<IV,ID>)sourceObject).getSubItemDeltas();
} else if (sourceObject instanceof Item<?,?>) {
itemOld = (Item<IV,ID>) sourceObject;
itemNew = (Item<IV,ID>) sourceObject;
} else {
throw new IllegalStateException("Unknown resolve result "+sourceObject);
}
}
// apply domain
ValueSetDefinitionType domainSetType = sourceType.getSet();
if (domainSetType != null) {
ValueSetDefinition setDef = new ValueSetDefinition(domainSetType, name, "domain of "+name.getLocalPart()+" in "+getMappingContextDescription(), task, result);
setDef.init(expressionFactory);
try {
if (itemOld != null) {
itemOld = itemOld.clone();
itemOld.filterValues(val -> setDef.containsTunnel(val));
}
if (itemNew != null) {
itemNew = itemNew.clone();
itemNew.filterValues(val -> setDef.containsTunnel(val));
}
if (delta != null) {
delta = delta.clone();
delta.filterValues(val -> setDef.containsTunnel(val));
}
} catch (TunnelException te) {
Throwable cause = te.getCause();
if (cause instanceof SchemaException) {
throw (SchemaException)cause;
} else if (cause instanceof ExpressionEvaluationException) {
throw (ExpressionEvaluationException)cause;
} else if (cause instanceof ObjectNotFoundException) {
throw (ObjectNotFoundException)cause;
}
}
}
Source<IV,ID> source = new Source<>(itemOld, delta, itemNew, name);
source.setResidualPath(residualPath);
source.setResolvePath(resolvePath);
source.setSubItemDeltas(subItemDeltas);
return source;
}
private boolean sourcesChanged() {
for (Source<?,?> source: sources) {
if (source.getDelta() != null) {
return true;
}
}
return false;
}
private void parseTarget() throws SchemaException {
VariableBindingDefinitionType targetType = mappingType.getTarget();
if (targetType == null) {
outputDefinition = defaultTargetDefinition;
outputPath = defaultTargetPath;
} else {
ItemPathType itemPathType = targetType.getPath();
if (itemPathType == null) {
outputDefinition = defaultTargetDefinition;
outputPath = defaultTargetPath;
} else {
ItemPath path = itemPathType.getItemPath();
outputDefinition = ExpressionUtil.resolveDefinitionPath(path, variables, targetContext, "target definition in "+getMappingContextDescription());
if (outputDefinition == null) {
throw new SchemaException("No target item that would conform to the path "+path+" in "+getMappingContextDescription());
}
outputPath = path.stripVariableSegment();
}
}
if (stringPolicyResolver != null) {
stringPolicyResolver.setOutputDefinition(outputDefinition);
stringPolicyResolver.setOutputPath(outputPath);
}
}
public D getOutputDefinition() throws SchemaException {
if (outputDefinition == null) {
parseTarget();
}
return outputDefinition;
}
public ItemPath getOutputPath() throws SchemaException {
if (outputDefinition == null) {
parseTarget();
}
return outputPath;
}
/**
* Applies definition to the output if needed.
*/
private void fixDefinition() throws SchemaException {
if (outputTriple == null) {
return;
}
if (outputTriple.isRaw()) {
outputTriple.applyDefinition(outputDefinition);
}
}
private void recomputeValues() {
if (outputTriple == null) {
return;
}
Visitor visitor = new Visitor() {
@Override
public void visit(Visitable visitable) {
if (visitable instanceof PrismValue) {
((PrismValue)visitable).recompute(getPrismContext());
}
}
};
outputTriple.accept(visitor);
}
private void setOrigin() {
if (outputTriple == null) {
return;
}
if (originType != null) {
outputTriple.setOriginType(originType);
}
if (originObject != null) {
outputTriple.setOriginObject(originObject);
}
}
private void evaluateCondition(Task task, OperationResult result) throws SchemaException, ExpressionEvaluationException, ObjectNotFoundException {
ExpressionType conditionExpressionType = mappingType.getCondition();
if (conditionExpressionType == null) {
// True -> True
conditionOutputTriple = new PrismValueDeltaSetTriple<PrismPropertyValue<Boolean>>();
conditionOutputTriple.addToZeroSet(new PrismPropertyValue<Boolean>(Boolean.TRUE));
return;
}
Expression<PrismPropertyValue<Boolean>,PrismPropertyDefinition<Boolean>> expression =
ExpressionUtil.createCondition(conditionExpressionType, expressionFactory,
"condition in "+getMappingContextDescription(), task, result);
ExpressionEvaluationContext context = new ExpressionEvaluationContext(sources, variables,
"condition in "+getMappingContextDescription(), task, result);
context.setStringPolicyResolver(stringPolicyResolver);
context.setExpressionFactory(expressionFactory);
context.setDefaultSource(defaultSource);
context.setDefaultTargetContext(getTargetContext());
context.setRefinedObjectClassDefinition(getRefinedObjectClassDefinition());
context.setMappingQName(mappingQName);
conditionOutputTriple = expression.evaluate(context);
}
private void evaluateExpression(Task task, OperationResult result, boolean conditionResultOld, boolean conditionResultNew) throws SchemaException, ExpressionEvaluationException, ObjectNotFoundException {
ExpressionType expressionType = null;
if (mappingType != null) {
expressionType = mappingType.getExpression();
}
expression = expressionFactory.makeExpression(expressionType, outputDefinition,
"expression in "+getMappingContextDescription(), task, result);
ExpressionEvaluationContext context = new ExpressionEvaluationContext(sources, variables,
"expression in "+getMappingContextDescription(), task, result);
context.setDefaultSource(defaultSource);
context.setSkipEvaluationMinus(!conditionResultOld);
context.setSkipEvaluationPlus(!conditionResultNew);
context.setStringPolicyResolver(stringPolicyResolver);
context.setExpressionFactory(expressionFactory);
context.setDefaultTargetContext(getTargetContext());
context.setRefinedObjectClassDefinition(getRefinedObjectClassDefinition());
context.setMappingQName(mappingQName);
outputTriple = expression.evaluate(context);
if (outputTriple == null) {
if (conditionResultNew) {
// We need to return empty triple instead of null.
// The condition was true (or there was not condition at all)
// so the mapping is applicable.
// Returning null would mean that the mapping is not applicable
// at all.
outputTriple = new PrismValueDeltaSetTriple<>();
}
} else {
// reflect condition change
if (!conditionResultOld && conditionResultNew) {
// Condition change false -> true
outputTriple.addAllToPlusSet(outputTriple.getZeroSet());
outputTriple.clearZeroSet();
outputTriple.clearMinusSet();
}
if (conditionResultOld && !conditionResultNew) {
// Condition change true -> false
outputTriple.addAllToMinusSet(outputTriple.getZeroSet());
outputTriple.clearZeroSet();
outputTriple.clearPlusSet();
}
}
}
/* (non-Javadoc)
* @see com.evolveum.midpoint.model.common.mapping.PrismValueDeltaSetTripleProducer#getOutputTriple()
*/
@Override
public PrismValueDeltaSetTriple<V> getOutputTriple() {
if (outputTriple != null && InternalsConfig.consistencyChecks) {
try {
outputTriple.checkNoParent();
} catch (IllegalStateException e) {
throw new IllegalStateException(e.getMessage() + " in output triple in " + getContextDescription(), e);
}
}
return outputTriple;
}
public Item<V,D> getOutput() throws SchemaException {
if (outputTriple == null) {
return null;
}
Item<V,D> output = outputDefinition.instantiate();
output.addAll(PrismValue.cloneCollection(outputTriple.getNonNegativeValues()));
return output;
}
public ItemDelta<V,D> createEmptyDelta(ItemPath path) {
return outputDefinition.createEmptyDelta(path);
}
private <T> PrismPropertyValue<T> filterValue(PrismPropertyValue<T> propertyValue, List<ValueFilterType> filters) {
PrismPropertyValue<T> filteredValue = propertyValue.clone();
filteredValue.setOriginType(OriginType.INBOUND);
if (filters == null || filters.isEmpty()) {
return filteredValue;
}
for (ValueFilterType filter : filters) {
Filter filterInstance = filterManager.getFilterInstance(filter.getType(), filter.getAny());
filterInstance.apply(filteredValue);
}
return filteredValue;
}
private void transitionState(MappingEvaluationState newState) {
state = newState;
}
private void assertState(MappingEvaluationState expecetdState) {
if (state != expecetdState) {
throw new IllegalArgumentException("Expected mapping state "+expecetdState+", but was "+state);
}
}
/**
* Shallow clone. Only the output is cloned deeply.
*/
public PrismValueDeltaSetTripleProducer<V, D> clone() {
Mapping<V, D> clone = new Builder<V, D>()
.mappingType(mappingType)
.contextDescription(contextDescription)
.expressionFactory(expressionFactory)
.securityEnforcer(securityEnforcer)
.variables(variables)
.conditionMaskNew(conditionMaskNew)
.conditionMaskOld(conditionMaskOld)
.defaultSource(defaultSource)
.defaultTargetDefinition(defaultTargetDefinition)
.objectResolver(objectResolver)
.originObject(originObject)
.originType(originType)
.sourceContext(sourceContext)
.sources(sources)
.targetContext(targetContext)
.build();
clone.outputDefinition = outputDefinition;
clone.outputPath = outputPath;
if (this.outputTriple != null) {
clone.outputTriple = this.outputTriple.clone();
}
if (this.conditionOutputTriple != null) {
clone.conditionOutputTriple = this.conditionOutputTriple.clone();
}
return clone;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (conditionMaskNew ? 1231 : 1237);
result = prime * result + (conditionMaskOld ? 1231 : 1237);
result = prime * result + ((conditionOutputTriple == null) ? 0 : conditionOutputTriple.hashCode());
result = prime * result + ((defaultSource == null) ? 0 : defaultSource.hashCode());
result = prime * result
+ ((defaultTargetDefinition == null) ? 0 : defaultTargetDefinition.hashCode());
result = prime * result + ((expressionFactory == null) ? 0 : expressionFactory.hashCode());
result = prime * result + ((mappingType == null) ? 0 : mappingType.hashCode());
result = prime * result + ((objectResolver == null) ? 0 : objectResolver.hashCode());
result = prime * result + ((originObject == null) ? 0 : originObject.hashCode());
result = prime * result + ((originType == null) ? 0 : originType.hashCode());
result = prime * result + ((outputDefinition == null) ? 0 : outputDefinition.hashCode());
result = prime * result + ((outputTriple == null) ? 0 : outputTriple.hashCode());
result = prime * result + ((contextDescription == null) ? 0 : contextDescription.hashCode());
result = prime * result + ((sourceContext == null) ? 0 : sourceContext.hashCode());
result = prime * result + ((sources == null) ? 0 : sources.hashCode());
result = prime * result + ((targetContext == null) ? 0 : targetContext.hashCode());
result = prime * result + ((variables == null) ? 0 : variables.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Mapping other = (Mapping) obj;
if (conditionMaskNew != other.conditionMaskNew)
return false;
if (conditionMaskOld != other.conditionMaskOld)
return false;
if (conditionOutputTriple == null) {
if (other.conditionOutputTriple != null)
return false;
} else if (!conditionOutputTriple.equals(other.conditionOutputTriple))
return false;
if (defaultSource == null) {
if (other.defaultSource != null)
return false;
} else if (!defaultSource.equals(other.defaultSource))
return false;
if (defaultTargetDefinition == null) {
if (other.defaultTargetDefinition != null)
return false;
} else if (!defaultTargetDefinition.equals(other.defaultTargetDefinition))
return false;
if (expressionFactory == null) {
if (other.expressionFactory != null)
return false;
} else if (!expressionFactory.equals(other.expressionFactory))
return false;
if (mappingType == null) {
if (other.mappingType != null)
return false;
} else if (!mappingType.equals(other.mappingType))
return false;
if (objectResolver == null) {
if (other.objectResolver != null)
return false;
} else if (!objectResolver.equals(other.objectResolver))
return false;
if (originObject == null) {
if (other.originObject != null)
return false;
} else if (!originObject.equals(other.originObject))
return false;
if (originType != other.originType)
return false;
if (outputDefinition == null) {
if (other.outputDefinition != null)
return false;
} else if (!outputDefinition.equals(other.outputDefinition))
return false;
if (outputTriple == null) {
if (other.outputTriple != null)
return false;
} else if (!outputTriple.equals(other.outputTriple))
return false;
if (contextDescription == null) {
if (other.contextDescription != null)
return false;
} else if (!contextDescription.equals(other.contextDescription))
return false;
if (sourceContext == null) {
if (other.sourceContext != null)
return false;
} else if (!sourceContext.equals(other.sourceContext))
return false;
if (sources == null) {
if (other.sources != null)
return false;
} else if (!sources.equals(other.sources))
return false;
if (targetContext == null) {
if (other.targetContext != null)
return false;
} else if (!targetContext.equals(other.targetContext))
return false;
if (variables == null) {
if (other.variables != null)
return false;
} else if (!variables.equals(other.variables))
return false;
return true;
}
@Override
public String debugDump() {
return debugDump(0);
}
@Override
public String debugDump(int indent) {
StringBuilder sb = new StringBuilder();
for (int i=0;i<indent;i++) {
sb.append(INDENT_STRING);
}
sb.append(toString());
return sb.toString();
}
@Override
public String toString() {
if (mappingType != null && mappingType.getName() != null) {
return "M(" + mappingType.getName()+ ": "+ getMappingDisplayName() + " = " + outputTriple + toStringStrength() + ")";
} else {
return "M(" + getMappingDisplayName() + " = " + outputTriple + toStringStrength() + ")";
}
}
private String getMappingDisplayName() {
if (mappingQName != null) {
return SchemaDebugUtil.prettyPrint(mappingQName);
}
if (outputDefinition == null) {
return null;
}
return SchemaDebugUtil.prettyPrint(outputDefinition.getName());
}
private String toStringStrength() {
switch (getStrength()) {
case NORMAL: return "";
case WEAK: return ", weak";
case STRONG: return ", strong";
}
return null;
}
/**
* Builder is used to construct a configuration of Mapping object, which - after building - becomes
* immutable.
*
* In order to provide backward-compatibility with existing use of Mapping object, the builder has
* also traditional setter methods. Both setters and "builder-style" methods MODIFY existing Builder
* object (i.e. they do not create a new one).
*
* TODO decide on which style of setters to keep (setters vs builder-style).
*/
public static final class Builder<V extends PrismValue, D extends ItemDefinition> {
private ExpressionFactory expressionFactory;
private ExpressionVariables variables = new ExpressionVariables();
private MappingType mappingType;
private ObjectResolver objectResolver;
private SecurityEnforcer securityEnforcer;
private Source<?, ?> defaultSource;
private D defaultTargetDefinition;
private ItemPath defaultTargetPath;
private Collection<V> originalTargetValues;
private ObjectDeltaObject<?> sourceContext;
private PrismObjectDefinition<?> targetContext;
private Collection<Source<?, ?>> sources = new ArrayList<>();
private OriginType originType;
private ObjectType originObject;
private FilterManager<Filter> filterManager;
private StringPolicyResolver stringPolicyResolver;
private boolean conditionMaskOld = true;
private boolean conditionMaskNew = true;
private XMLGregorianCalendar now;
private XMLGregorianCalendar defaultReferenceTime;
private boolean profiling;
private String contextDescription;
private QName mappingQName;
private RefinedObjectClassDefinition refinedObjectClassDefinition;
private PrismContext prismContext;
public Builder<V,D> expressionFactory(ExpressionFactory val) {
expressionFactory = val;
return this;
}
public Builder<V,D> variables(ExpressionVariables val) {
variables = val;
return this;
}
public Builder<V,D> mappingType(MappingType val) {
mappingType = val;
return this;
}
public Builder<V,D> objectResolver(ObjectResolver val) {
objectResolver = val;
return this;
}
public Builder<V,D> securityEnforcer(SecurityEnforcer val) {
securityEnforcer = val;
return this;
}
public Builder<V,D> defaultSource(Source<?, ?> val) {
defaultSource = val;
return this;
}
public Builder<V,D> defaultTargetDefinition(D val) {
defaultTargetDefinition = val;
return this;
}
public Builder<V,D> defaultTargetPath(ItemPath val) {
defaultTargetPath = val;
return this;
}
public Builder<V,D> originalTargetValues(Collection<V> values) {
originalTargetValues = values;
return this;
}
public Builder<V,D> sourceContext(ObjectDeltaObject<?> val) {
sourceContext = val;
return this;
}
public Builder<V,D> targetContext(PrismObjectDefinition<?> val) {
targetContext = val;
return this;
}
public Builder<V,D> sources(Collection<Source<?, ?>> val) {
sources = val;
return this;
}
public Builder<V,D> originType(OriginType val) {
originType = val;
return this;
}
public Builder<V,D> originObject(ObjectType val) {
originObject = val;
return this;
}
public Builder<V,D> filterManager(FilterManager<Filter> val) {
filterManager = val;
return this;
}
public Builder<V,D> stringPolicyResolver(StringPolicyResolver val) {
stringPolicyResolver = val;
return this;
}
public Builder<V,D> conditionMaskOld(boolean val) {
conditionMaskOld = val;
return this;
}
public Builder<V,D> conditionMaskNew(boolean val) {
conditionMaskNew = val;
return this;
}
public Builder<V,D> now(XMLGregorianCalendar val) {
now = val;
return this;
}
public Builder<V,D> defaultReferenceTime(XMLGregorianCalendar val) {
defaultReferenceTime = val;
return this;
}
public Builder<V,D> profiling(boolean val) {
profiling = val;
return this;
}
public Builder<V,D> contextDescription(String val) {
contextDescription = val;
return this;
}
public Builder<V,D> mappingQName(QName val) {
mappingQName = val;
return this;
}
public Builder<V,D> refinedObjectClassDefinition(RefinedObjectClassDefinition val) {
refinedObjectClassDefinition = val;
return this;
}
public Builder<V,D> prismContext(PrismContext val) {
prismContext = val;
return this;
}
public Mapping<V,D> build() {
return new Mapping<>(this);
}
public ExpressionFactory getExpressionFactory() {
return expressionFactory;
}
public ExpressionVariables getVariables() {
return variables;
}
public MappingType getMappingType() {
return mappingType;
}
public ObjectResolver getObjectResolver() {
return objectResolver;
}
public SecurityEnforcer getSecurityEnforcer() {
return securityEnforcer;
}
public Source<?, ?> getDefaultSource() {
return defaultSource;
}
public D getDefaultTargetDefinition() {
return defaultTargetDefinition;
}
public ItemPath getDefaultTargetPath() {
return defaultTargetPath;
}
public Collection<V> getOriginalTargetValues() {
return originalTargetValues;
}
public ObjectDeltaObject<?> getSourceContext() {
return sourceContext;
}
public PrismObjectDefinition<?> getTargetContext() {
return targetContext;
}
public Collection<Source<?, ?>> getSources() {
return sources;
}
public OriginType getOriginType() {
return originType;
}
public ObjectType getOriginObject() {
return originObject;
}
public FilterManager<Filter> getFilterManager() {
return filterManager;
}
public StringPolicyResolver getStringPolicyResolver() {
return stringPolicyResolver;
}
public boolean isConditionMaskOld() {
return conditionMaskOld;
}
public boolean isConditionMaskNew() {
return conditionMaskNew;
}
public XMLGregorianCalendar getNow() {
return now;
}
public XMLGregorianCalendar getDefaultReferenceTime() {
return defaultReferenceTime;
}
public boolean isProfiling() {
return profiling;
}
public String getContextDescription() {
return contextDescription;
}
public QName getMappingQName() {
return mappingQName;
}
public RefinedObjectClassDefinition getRefinedObjectClassDefinition() {
return refinedObjectClassDefinition;
}
public Builder<V, D> rootNode(ObjectReferenceType objectRef) {
return addVariableDefinition(null,(Object)objectRef);
}
public Builder<V, D> rootNode(ObjectDeltaObject<?> odo) {
return addVariableDefinition(null,(Object)odo);
}
public Builder<V, D> rootNode(ObjectType objectType) {
return addVariableDefinition(null,(Object)objectType);
}
public Builder<V, D> rootNode(PrismObject<? extends ObjectType> mpObject) {
return addVariableDefinition(null,(Object)mpObject);
}
@Deprecated
public void setRootNode(ObjectReferenceType objectRef) {
rootNode(objectRef);
}
@Deprecated
public void setRootNode(ObjectDeltaObject<?> odo) {
rootNode(odo);
}
@Deprecated
public void setRootNode(ObjectType objectType) {
rootNode(objectType);
}
@Deprecated
public void setRootNode(PrismObject<? extends ObjectType> mpObject) {
rootNode(mpObject);
}
public PrismContext getPrismContext() {
return prismContext;
}
public Builder<V, D> addVariableDefinition(ExpressionVariableDefinitionType varDef) throws SchemaException {
if (varDef.getObjectRef() != null) {
ObjectReferenceType ref = varDef.getObjectRef();
ref.setType(getPrismContext().getSchemaRegistry().qualifyTypeName(ref.getType()));
return addVariableDefinition(varDef.getName(), ref);
} else if (varDef.getValue() != null) {
return addVariableDefinition(varDef.getName(),varDef.getValue());
} else {
LOGGER.warn("Empty definition of variable {} in {}, ignoring it", varDef.getName(), getContextDescription());
return this;
}
}
public Builder<V, D> addVariableDefinition(QName name, ObjectReferenceType objectRef) {
return addVariableDefinition(name, (Object)objectRef);
}
public Builder<V, D> addVariableDefinition(QName name, ObjectType objectType) {
return addVariableDefinition(name,(Object)objectType);
}
public Builder<V, D> addVariableDefinition(QName name, PrismObject<? extends ObjectType> midpointObject) {
return addVariableDefinition(name,(Object)midpointObject);
}
public Builder<V, D> addVariableDefinition(QName name, String value) {
return addVariableDefinition(name,(Object)value);
}
public Builder<V, D> addVariableDefinition(QName name, int value) {
return addVariableDefinition(name,(Object)value);
}
public Builder<V, D> addVariableDefinition(QName name, Element value) {
return addVariableDefinition(name,(Object)value);
}
public Builder<V, D> addVariableDefinition(QName name, PrismValue value) {
return addVariableDefinition(name,(Object)value);
}
public Builder<V, D> addVariableDefinition(QName name, ObjectDeltaObject<?> value) {
return addVariableDefinition(name,(Object)value);
}
public Builder<V, D> addVariableDefinitions(Map<QName, Object> extraVariables) {
variables.addVariableDefinitions(extraVariables);
return this;
}
public Builder<V, D> addVariableDefinition(QName name, Object value) {
variables.addVariableDefinition(name, value);
return this;
}
public boolean hasVariableDefinition(QName varName) {
return variables.containsKey(varName);
}
public boolean isApplicableToChannel(String channel) {
return Mapping.isApplicableToChannel(mappingType, channel);
}
public Builder<V, D> addSource(Source<?,?> source) {
sources.add(source);
return this;
}
// traditional setters are also here, to avoid massive changes to existing code
@Deprecated
public void setExpressionFactory(ExpressionFactory expressionFactory) {
this.expressionFactory = expressionFactory;
}
@Deprecated
public void setVariables(ExpressionVariables variables) {
this.variables = variables;
}
@Deprecated
public void setMappingType(MappingType mappingType) {
this.mappingType = mappingType;
}
@Deprecated
public void setObjectResolver(ObjectResolver objectResolver) {
this.objectResolver = objectResolver;
}
@Deprecated
public void setSecurityEnforcer(SecurityEnforcer securityEnforcer) {
this.securityEnforcer = securityEnforcer;
}
@Deprecated
public void setDefaultSource(Source<?, ?> defaultSource) {
this.defaultSource = defaultSource;
}
@Deprecated
public void setDefaultTargetDefinition(D defaultTargetDefinition) {
this.defaultTargetDefinition = defaultTargetDefinition;
}
@Deprecated
public void setDefaultTargetPath(ItemPath defaultTargetPath) {
this.defaultTargetPath = defaultTargetPath;
}
@Deprecated
public void setSourceContext(ObjectDeltaObject<?> sourceContext) {
this.sourceContext = sourceContext;
}
@Deprecated
public void setTargetContext(PrismObjectDefinition<?> targetContext) {
this.targetContext = targetContext;
}
@Deprecated
public void setSources(Collection<Source<?, ?>> sources) {
this.sources = sources;
}
@Deprecated
public void setOriginType(OriginType originType) {
this.originType = originType;
}
@Deprecated
public void setOriginObject(ObjectType originObject) {
this.originObject = originObject;
}
@Deprecated
public void setFilterManager(
FilterManager<Filter> filterManager) {
this.filterManager = filterManager;
}
@Deprecated
public void setStringPolicyResolver(
StringPolicyResolver stringPolicyResolver) {
this.stringPolicyResolver = stringPolicyResolver;
}
@Deprecated
public void setConditionMaskOld(boolean conditionMaskOld) {
this.conditionMaskOld = conditionMaskOld;
}
@Deprecated
public void setConditionMaskNew(boolean conditionMaskNew) {
this.conditionMaskNew = conditionMaskNew;
}
@Deprecated
public void setNow(XMLGregorianCalendar now) {
this.now = now;
}
@Deprecated
public void setDefaultReferenceTime(XMLGregorianCalendar defaultReferenceTime) {
this.defaultReferenceTime = defaultReferenceTime;
}
@Deprecated
public void setProfiling(boolean profiling) {
this.profiling = profiling;
}
@Deprecated
public void setContextDescription(String contextDescription) {
this.contextDescription = contextDescription;
}
@Deprecated
public void setMappingQName(QName mappingQName) {
this.mappingQName = mappingQName;
}
@Deprecated
public void setRefinedObjectClassDefinition(
RefinedObjectClassDefinition refinedObjectClassDefinition) {
this.refinedObjectClassDefinition = refinedObjectClassDefinition;
}
@Deprecated
public void setPrismContext(PrismContext prismContext) {
this.prismContext = prismContext;
}
public MappingStrengthType getStrength() {
return Mapping.getStrength(mappingType);
}
}
}