-
Notifications
You must be signed in to change notification settings - Fork 188
/
PathExpressionEvaluation.java
149 lines (126 loc) · 7.18 KB
/
PathExpressionEvaluation.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
/*
* Copyright (c) 2020 Evolveum and contributors
*
* This work is dual-licensed under the Apache License 2.0
* and European Union Public License. See LICENSE file for details.
*/
package com.evolveum.midpoint.model.common.expression.evaluator.path;
import com.evolveum.midpoint.prism.*;
import com.evolveum.midpoint.prism.delta.PrismValueDeltaSetTriple;
import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.prism.util.DefinitionResolver;
import com.evolveum.midpoint.prism.util.ItemDeltaItem;
import com.evolveum.midpoint.repo.common.expression.ExpressionEvaluationContext;
import com.evolveum.midpoint.schema.expression.TypedValue;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.util.exception.*;
import org.jetbrains.annotations.Nullable;
/**
* Evaluation of the "path" expression.
*/
class PathExpressionEvaluation<V extends PrismValue, D extends ItemDefinition> {
private final PathExpressionEvaluator<V, D> evaluator;
private final ExpressionEvaluationContext context;
/**
* Path to be resolved. Changes during resolution process.
*/
private ItemPath pathToResolve;
/**
* Context (e.g. prism item or prism value) in which the resolution takes places.
* Changes during resolution process.
*/
private ResolutionContext resolutionContext;
PathExpressionEvaluation(PathExpressionEvaluator<V, D> evaluator, ExpressionEvaluationContext context) {
this.evaluator = evaluator;
this.context = context;
}
PrismValueDeltaSetTriple<V> evaluate(OperationResult result) throws ExpressionEvaluationException, SchemaException,
ObjectNotFoundException, SecurityViolationException, CommunicationException, ConfigurationException {
pathToResolve = evaluator.getPath();
resolutionContext = determineInitialResolveContext();
if (resolutionContext == null) {
return null;
}
stepAlongResolvePath();
return prepareOutputTriple(result);
}
private ResolutionContext determineInitialResolveContext() throws ExpressionEvaluationException {
if (pathToResolve.startsWithVariable()) {
return getInitialResolveContextFromVariable();
} else if (context.getSources().size() == 1) {
return IdiResolutionContext.fromIdi(context.getSources().iterator().next());
} else if (context.getDefaultSource() != null) {
return IdiResolutionContext.fromIdi(context.getDefaultSource());
} else if (context.getSources().isEmpty()) {
throw new IllegalStateException("There is no source to be used for path resolution. In " +
context.getContextDescription());
} else {
throw new IllegalStateException("There is are multiple sources to be used for path resolution. In " +
context.getContextDescription());
}
}
private ResolutionContext getInitialResolveContextFromVariable() throws ExpressionEvaluationException {
String variableName = ItemPath.toVariableName(pathToResolve.first()).getLocalPart();
pathToResolve = pathToResolve.rest();
TypedValue variableValueAndDefinition = evaluator.findInSourcesAndVariables(context, variableName);
if (variableValueAndDefinition == null) {
throw new ExpressionEvaluationException("No variable with name "+variableName+" in "+ context.getContextDescription());
}
Object variableValue = variableValueAndDefinition.getValue();
if (variableValue == null) {
return null;
} else if (variableValue instanceof Item || variableValue instanceof ItemDeltaItem<?,?>) {
return IdiResolutionContext.fromAnyObject(variableValue);
} else if (variableValue instanceof PrismValue) {
return new ValueResolutionContext((PrismValue) variableValue, context.getContextDescription());
} else if (variableValueAndDefinition.getTypeClass().isAssignableFrom(variableValue.getClass())) {
return ValueResolutionContext.fromRealValue(variableValue, context.getContextDescription(), evaluator.getPrismContext());
} else {
throw new ExpressionEvaluationException("Unexpected variable value "+variableValue+" ("+variableValue.getClass()+")");
}
}
@Nullable
private PrismValueDeltaSetTriple<V> prepareOutputTriple(OperationResult result) throws SchemaException,
ConfigurationException, ObjectNotFoundException, CommunicationException, SecurityViolationException,
ExpressionEvaluationException {
PrismValueDeltaSetTriple<V> outputTriple = resolutionContext.createOutputTriple(evaluator.getPrismContext());
evaluator.applyValueMetadata(outputTriple, context, result);
return evaluator.finishOutputTriple(outputTriple, context.getAdditionalConvertor(), null);
}
private void stepAlongResolvePath() throws SchemaException, ExpressionEvaluationException {
while (!pathToResolve.isEmpty()) {
if (resolutionContext.isContainer()) {
DefinitionResolver defResolver = (parentDef, path) -> {
if (parentDef != null && parentDef.isDynamic()) {
// This is the case of dynamic schema extensions, such as assignment extension.
// Those may not have a definition. In that case just assume strings.
// In fact, this is a HACK. All such schemas should have a definition.
// Otherwise there may be problems with parameter types for caching compiles scripts and so on.
return evaluator.getPrismContext().definitionFactory().createPropertyDefinition(path.firstName(), PrimitiveType.STRING.getQname());
} else {
return null;
}
};
try {
resolutionContext = resolutionContext.stepInto(pathToResolve.firstToName(), defResolver);
pathToResolve = pathToResolve.rest();
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException(e.getMessage()+"; resolving path "+ pathToResolve.firstAsPath()+" on "+
resolutionContext +"; in "+context.getContextDescription(), e);
}
if (resolutionContext == null) {
throw new ExpressionEvaluationException("Cannot find item using path "+evaluator.getPath()+" in "+
context.getContextDescription());
}
} else if (resolutionContext.isStructuredProperty()) {
resolutionContext = resolutionContext.resolveStructuredProperty(pathToResolve,
(PrismPropertyDefinition) evaluator.getOutputDefinition(), evaluator.getPrismContext());
pathToResolve = ItemPath.EMPTY_PATH;
} else if (resolutionContext.isNull()) {
pathToResolve = ItemPath.EMPTY_PATH;
} else {
throw new ExpressionEvaluationException("Cannot resolve path "+ pathToResolve +" on "+ resolutionContext +" in "+ context.getContextDescription());
}
}
}
}