Skip to content

Commit faf3c95

Browse files
authored
refactor: bind policy scope to policy context hierarchy (#4535)
* refactor: bind policy scope to policy context hierarchy * PR remarks
1 parent 6e78b8b commit faf3c95

File tree

58 files changed

+1315
-1027
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+1315
-1027
lines changed

core/common/lib/policy-engine-lib/src/main/java/org/eclipse/edc/policy/engine/PolicyEngineImpl.java

+162-111
Large diffs are not rendered by default.

core/common/lib/policy-engine-lib/src/main/java/org/eclipse/edc/policy/engine/plan/PolicyEvaluationPlanner.java

+32-81
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@
1414

1515
package org.eclipse.edc.policy.engine.plan;
1616

17-
import org.eclipse.edc.policy.engine.spi.AtomicConstraintFunction;
18-
import org.eclipse.edc.policy.engine.spi.DynamicAtomicConstraintFunction;
17+
import org.eclipse.edc.policy.engine.spi.AtomicConstraintRuleFunction;
18+
import org.eclipse.edc.policy.engine.spi.DynamicAtomicConstraintRuleFunction;
1919
import org.eclipse.edc.policy.engine.spi.PolicyContext;
20-
import org.eclipse.edc.policy.engine.spi.PolicyValidatorFunction;
21-
import org.eclipse.edc.policy.engine.spi.RuleFunction;
20+
import org.eclipse.edc.policy.engine.spi.PolicyRuleFunction;
21+
import org.eclipse.edc.policy.engine.spi.PolicyValidatorRule;
2222
import org.eclipse.edc.policy.engine.spi.plan.PolicyEvaluationPlan;
2323
import org.eclipse.edc.policy.engine.spi.plan.step.AndConstraintStep;
2424
import org.eclipse.edc.policy.engine.spi.plan.step.AtomicConstraintStep;
@@ -37,14 +37,12 @@
3737
import org.eclipse.edc.policy.model.Constraint;
3838
import org.eclipse.edc.policy.model.Duty;
3939
import org.eclipse.edc.policy.model.MultiplicityConstraint;
40-
import org.eclipse.edc.policy.model.Operator;
4140
import org.eclipse.edc.policy.model.OrConstraint;
4241
import org.eclipse.edc.policy.model.Permission;
4342
import org.eclipse.edc.policy.model.Policy;
4443
import org.eclipse.edc.policy.model.Prohibition;
4544
import org.eclipse.edc.policy.model.Rule;
4645
import org.eclipse.edc.policy.model.XoneConstraint;
47-
import org.eclipse.edc.spi.result.Result;
4846

4947
import java.util.ArrayList;
5048
import java.util.List;
@@ -54,17 +52,16 @@
5452
import java.util.TreeMap;
5553
import java.util.stream.Collectors;
5654

57-
import static org.eclipse.edc.policy.engine.PolicyEngineImpl.scopeFilter;
5855
import static org.eclipse.edc.policy.engine.spi.PolicyEngine.DELIMITER;
5956

6057
public class PolicyEvaluationPlanner implements Policy.Visitor<PolicyEvaluationPlan>, Rule.Visitor<RuleStep<? extends Rule>>, Constraint.Visitor<ConstraintStep> {
6158

6259
private final Stack<Rule> ruleContext = new Stack<>();
63-
private final List<PolicyValidatorFunction> preValidators = new ArrayList<>();
64-
private final List<PolicyValidatorFunction> postValidators = new ArrayList<>();
65-
private final Map<String, List<ConstraintFunctionEntry<Rule>>> constraintFunctions = new TreeMap<>();
66-
private final List<DynamicAtomicConstraintFunctionEntry<Rule>> dynamicConstraintFunctions = new ArrayList<>();
67-
private final List<RuleFunctionFunctionEntry<Rule>> ruleFunctions = new ArrayList<>();
60+
private final List<PolicyValidatorRule<? extends PolicyContext>> preValidators = new ArrayList<>();
61+
private final List<PolicyValidatorRule<? extends PolicyContext>> postValidators = new ArrayList<>();
62+
private final Map<String, List<ConstraintFunctionEntry<Rule, ? extends PolicyContext>>> constraintFunctions = new TreeMap<>();
63+
private final List<DynamicAtomicConstraintFunctionEntry<Rule, ? extends PolicyContext>> dynamicConstraintFunctions = new ArrayList<>();
64+
private final List<RuleFunctionFunctionEntry<Rule, ? extends PolicyContext>> ruleFunctions = new ArrayList<>();
6865
private final String delimitedScope;
6966
private final String scope;
7067

@@ -98,19 +95,19 @@ public XoneConstraintStep visitXoneConstraint(XoneConstraint constraint) {
9895
public AtomicConstraintStep visitAtomicConstraint(AtomicConstraint constraint) {
9996
var currentRule = currentRule();
10097
var leftValue = constraint.getLeftExpression().accept(s -> s.getValue().toString());
101-
var function = getFunctions(leftValue, currentRule.getClass());
98+
var functionName = getFunctionName(leftValue, currentRule.getClass());
10299

103100
var filteringReasons = new ArrayList<String>();
104101

105102
if (!ruleValidator.isInScope(leftValue, delimitedScope)) {
106103
filteringReasons.add("leftOperand '%s' is not bound to scope '%s'".formatted(leftValue, scope));
107104
}
108105

109-
if (function == null) {
106+
if (functionName == null) {
110107
filteringReasons.add("leftOperand '%s' is not bound to any function within scope '%s'".formatted(leftValue, scope));
111108
}
112109

113-
return new AtomicConstraintStep(constraint, filteringReasons, currentRule, function);
110+
return new AtomicConstraintStep(constraint, filteringReasons, currentRule, functionName);
114111
}
115112

116113
@Override
@@ -161,17 +158,17 @@ public DutyStep visitDuty(Duty duty) {
161158
return prohibitionStepBuilder.build();
162159
}
163160

164-
private AtomicConstraintFunction<Rule> getFunctions(String key, Class<? extends Rule> ruleKind) {
161+
private String getFunctionName(String key, Class<? extends Rule> ruleKind) {
165162
return constraintFunctions.getOrDefault(key, new ArrayList<>())
166163
.stream()
167164
.filter(entry -> ruleKind.isAssignableFrom(entry.type()))
168-
.map(entry -> entry.function)
165+
.map(entry -> entry.function.name())
169166
.findFirst()
170167
.or(() -> dynamicConstraintFunctions
171168
.stream()
172169
.filter(f -> ruleKind.isAssignableFrom(f.type))
173170
.filter(f -> f.function.canHandle(key))
174-
.map(entry -> wrapDynamicFunction(key, entry.function))
171+
.map(f -> f.function.name())
175172
.findFirst())
176173
.orElse(null);
177174
}
@@ -215,43 +212,19 @@ private List<ConstraintStep> validateMultiplicityConstraint(MultiplicityConstrai
215212
.collect(Collectors.toList());
216213
}
217214

218-
private <R extends Rule> AtomicConstraintFunction<R> wrapDynamicFunction(String key, DynamicAtomicConstraintFunction<R> function) {
219-
return new AtomicConstraintFunctionWrapper<>(key, function);
220-
}
221-
222-
private record ConstraintFunctionEntry<R extends Rule>(
215+
private record ConstraintFunctionEntry<R extends Rule, C extends PolicyContext>(
223216
Class<R> type,
224-
AtomicConstraintFunction<R> function) {
217+
AtomicConstraintRuleFunction<R, C> function) {
225218
}
226219

227-
private record DynamicAtomicConstraintFunctionEntry<R extends Rule>(
220+
private record DynamicAtomicConstraintFunctionEntry<R extends Rule, C extends PolicyContext>(
228221
Class<R> type,
229-
DynamicAtomicConstraintFunction<R> function) {
222+
DynamicAtomicConstraintRuleFunction<R, C> function) {
230223
}
231224

232-
private record RuleFunctionFunctionEntry<R extends Rule>(
225+
private record RuleFunctionFunctionEntry<R extends Rule, C extends PolicyContext>(
233226
Class<R> type,
234-
RuleFunction<R> function) {
235-
}
236-
237-
private record AtomicConstraintFunctionWrapper<R extends Rule>(
238-
String leftOperand,
239-
DynamicAtomicConstraintFunction<R> inner) implements AtomicConstraintFunction<R> {
240-
241-
@Override
242-
public boolean evaluate(Operator operator, Object rightValue, R rule, PolicyContext context) {
243-
return inner.evaluate(leftOperand, operator, rightValue, rule, context);
244-
}
245-
246-
@Override
247-
public Result<Void> validate(Operator operator, Object rightValue, R rule) {
248-
return inner.validate(leftOperand, operator, rightValue, rule);
249-
}
250-
251-
@Override
252-
public String name() {
253-
return inner.name();
254-
}
227+
PolicyRuleFunction<R, C> function) {
255228
}
256229

257230
public static class Builder {
@@ -270,55 +243,33 @@ public Builder ruleValidator(RuleValidator ruleValidator) {
270243
return this;
271244
}
272245

273-
public Builder preValidator(String scope, PolicyValidatorFunction validator) {
274-
275-
if (scopeFilter(scope, planner.delimitedScope)) {
276-
planner.preValidators.add(validator);
277-
}
246+
public <C extends PolicyContext> Builder preValidator(PolicyValidatorRule<C> validator) {
247+
planner.preValidators.add(validator);
278248

279249
return this;
280250
}
281251

282-
public Builder preValidators(String scope, List<PolicyValidatorFunction> validators) {
283-
validators.forEach(validator -> preValidator(scope, validator));
284-
return this;
285-
}
286-
287-
public Builder postValidator(String scope, PolicyValidatorFunction validator) {
288-
if (scopeFilter(scope, planner.delimitedScope)) {
289-
planner.postValidators.add(validator);
290-
}
291-
return this;
292-
}
293-
294-
public Builder postValidators(String scope, List<PolicyValidatorFunction> validators) {
295-
validators.forEach(validator -> postValidator(scope, validator));
252+
public <C extends PolicyContext> Builder postValidator(PolicyValidatorRule<C> validator) {
253+
planner.postValidators.add(validator);
296254
return this;
297255
}
298256

299257
@SuppressWarnings({ "unchecked", "rawtypes" })
300-
public <R extends Rule> Builder evaluationFunction(String scope, String key, Class<R> ruleKind, AtomicConstraintFunction<R> function) {
301-
302-
if (scopeFilter(scope, planner.delimitedScope)) {
303-
planner.constraintFunctions.computeIfAbsent(key, k -> new ArrayList<>())
304-
.add(new ConstraintFunctionEntry(ruleKind, function));
305-
}
258+
public <R extends Rule, C extends PolicyContext> Builder evaluationFunction(String key, Class<R> ruleKind, AtomicConstraintRuleFunction<R, C> function) {
259+
planner.constraintFunctions.computeIfAbsent(key, k -> new ArrayList<>())
260+
.add(new ConstraintFunctionEntry(ruleKind, function));
306261
return this;
307262
}
308263

309264
@SuppressWarnings({ "unchecked", "rawtypes" })
310-
public <R extends Rule> Builder evaluationFunction(String scope, Class<R> ruleKind, DynamicAtomicConstraintFunction<R> function) {
311-
if (scopeFilter(scope, planner.delimitedScope)) {
312-
planner.dynamicConstraintFunctions.add(new DynamicAtomicConstraintFunctionEntry(ruleKind, function));
313-
}
265+
public <R extends Rule, C extends PolicyContext> Builder evaluationFunction(Class<R> ruleKind, DynamicAtomicConstraintRuleFunction<R, C> function) {
266+
planner.dynamicConstraintFunctions.add(new DynamicAtomicConstraintFunctionEntry(ruleKind, function));
314267
return this;
315268
}
316269

317270
@SuppressWarnings({ "unchecked", "rawtypes" })
318-
public <R extends Rule> Builder evaluationFunction(String scope, Class<R> ruleKind, RuleFunction<R> function) {
319-
if (scopeFilter(scope, planner.delimitedScope)) {
320-
planner.ruleFunctions.add(new RuleFunctionFunctionEntry(ruleKind, function));
321-
}
271+
public <R extends Rule, C extends PolicyContext> Builder evaluationFunction(Class<R> ruleKind, PolicyRuleFunction<R, C> function) {
272+
planner.ruleFunctions.add(new RuleFunctionFunctionEntry(ruleKind, function));
322273
return this;
323274
}
324275

core/common/lib/policy-engine-lib/src/main/java/org/eclipse/edc/policy/engine/validation/PolicyValidator.java

+22-35
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515
package org.eclipse.edc.policy.engine.validation;
1616

1717
import org.eclipse.edc.policy.engine.spi.AtomicConstraintFunction;
18+
import org.eclipse.edc.policy.engine.spi.AtomicConstraintRuleFunction;
1819
import org.eclipse.edc.policy.engine.spi.DynamicAtomicConstraintFunction;
20+
import org.eclipse.edc.policy.engine.spi.DynamicAtomicConstraintRuleFunction;
1921
import org.eclipse.edc.policy.engine.spi.PolicyContext;
2022
import org.eclipse.edc.policy.model.AndConstraint;
2123
import org.eclipse.edc.policy.model.AtomicConstraint;
@@ -39,7 +41,6 @@
3941
import java.util.Objects;
4042
import java.util.Stack;
4143
import java.util.TreeMap;
42-
import java.util.stream.Collectors;
4344
import java.util.stream.Stream;
4445

4546
/**
@@ -59,8 +60,8 @@ public class PolicyValidator implements Policy.Visitor<Result<Void>>, Rule.Visit
5960

6061
private final Stack<Rule> ruleContext = new Stack<>();
6162

62-
private final Map<String, List<ConstraintFunctionEntry<Rule>>> constraintFunctions = new TreeMap<>();
63-
private final List<DynamicAtomicConstraintFunctionEntry<Rule>> dynamicConstraintFunctions = new ArrayList<>();
63+
private final Map<String, List<ConstraintFunctionEntry<Rule, ? extends PolicyContext>>> constraintFunctions = new TreeMap<>();
64+
private final List<DynamicAtomicConstraintFunctionEntry<Rule, ? extends PolicyContext>> dynamicConstraintFunctions = new ArrayList<>();
6465
private RuleValidator ruleValidator;
6566

6667
public Result<Void> validate(Policy policy) {
@@ -133,12 +134,12 @@ private Result<Void> validateLeftExpression(Rule rule, String leftOperand) {
133134
}
134135

135136
private Result<Void> validateConstraint(String leftOperand, Operator operator, Object rightOperand, Rule rule) {
136-
var functions = getFunctions(leftOperand, rule.getClass());
137+
var functions = getValidations(leftOperand, rule.getClass());
137138
if (functions.isEmpty()) {
138139
return Result.failure("left operand '%s' is not bound to any functions: Rule { %s }".formatted(leftOperand, rule));
139140
} else {
140141
return functions.stream()
141-
.map(f -> f.validate(operator, rightOperand, rule))
142+
.map(f -> f.validate(leftOperand, operator, rightOperand, rule))
142143
.reduce(Result.success(), Result::merge);
143144
}
144145
}
@@ -164,29 +165,30 @@ private Result<Void> validateAction(Rule rule) {
164165
}
165166
}
166167

167-
private <R extends Rule> List<AtomicConstraintFunction<Rule>> getFunctions(String key, Class<R> ruleKind) {
168+
private <R extends Rule, C extends PolicyContext> List<PolicyValidation> getValidations(String key, Class<R> ruleKind) {
168169
// first look-up for an exact match
169170
var functions = constraintFunctions.getOrDefault(key, new ArrayList<>())
170171
.stream()
171172
.filter(entry -> ruleKind.isAssignableFrom(entry.type()))
172-
.map(entry -> entry.function)
173-
.collect(Collectors.toList());
173+
.map(entry -> (PolicyValidation) (leftOperand, operator, rightOperand, rule) ->
174+
entry.function.validate(operator, rightOperand, rule))
175+
.toList();
174176

175177
// if not found inspect the dynamic functions
176178
if (functions.isEmpty()) {
177-
functions = dynamicConstraintFunctions
179+
return dynamicConstraintFunctions
178180
.stream()
179-
.filter(f -> ruleKind.isAssignableFrom(f.type))
180-
.filter(f -> f.function.canHandle(key))
181-
.map(entry -> wrapDynamicFunction(key, entry.function))
181+
.filter(entry -> ruleKind.isAssignableFrom(entry.type))
182+
.filter(entry -> entry.function.canHandle(key))
183+
.map(entry -> (PolicyValidation) entry.function::validate)
182184
.toList();
183185
}
184186

185187
return functions;
186188
}
187189

188-
private <R extends Rule> AtomicConstraintFunction<R> wrapDynamicFunction(String key, DynamicAtomicConstraintFunction<R> function) {
189-
return new AtomicConstraintFunctionWrapper<>(key, function);
190+
private interface PolicyValidation {
191+
Result<Void> validate(String leftOperand, Operator operator, Object rightOperand, Rule rule);
190192
}
191193

192194
private Rule currentRule() {
@@ -210,14 +212,14 @@ public Builder ruleValidator(RuleValidator ruleValidator) {
210212
}
211213

212214
@SuppressWarnings({ "unchecked", "rawtypes" })
213-
public <R extends Rule> Builder evaluationFunction(String key, Class<R> ruleKind, AtomicConstraintFunction<R> function) {
215+
public <R extends Rule, C extends PolicyContext> Builder evaluationFunction(String key, Class<R> ruleKind, AtomicConstraintRuleFunction<R, C> function) {
214216
validator.constraintFunctions.computeIfAbsent(key, k -> new ArrayList<>())
215217
.add(new ConstraintFunctionEntry(ruleKind, function));
216218
return this;
217219
}
218220

219221
@SuppressWarnings({ "unchecked", "rawtypes" })
220-
public <R extends Rule> Builder dynamicEvaluationFunction(Class<R> ruleKind, DynamicAtomicConstraintFunction<R> function) {
222+
public <R extends Rule, C extends PolicyContext> Builder dynamicEvaluationFunction(Class<R> ruleKind, DynamicAtomicConstraintRuleFunction<R, C> function) {
221223
validator.dynamicConstraintFunctions.add(new DynamicAtomicConstraintFunctionEntry(ruleKind, function));
222224
return this;
223225
}
@@ -229,28 +231,13 @@ public PolicyValidator build() {
229231

230232
}
231233

232-
private record ConstraintFunctionEntry<R extends Rule>(
234+
private record ConstraintFunctionEntry<R extends Rule, C extends PolicyContext>(
233235
Class<R> type,
234-
AtomicConstraintFunction<R> function) {
236+
AtomicConstraintRuleFunction<R, C> function) {
235237
}
236238

237-
private record DynamicAtomicConstraintFunctionEntry<R extends Rule>(
239+
private record DynamicAtomicConstraintFunctionEntry<R extends Rule, C extends PolicyContext>(
238240
Class<R> type,
239-
DynamicAtomicConstraintFunction<R> function) {
240-
}
241-
242-
private record AtomicConstraintFunctionWrapper<R extends Rule>(
243-
String leftOperand,
244-
DynamicAtomicConstraintFunction<R> inner) implements AtomicConstraintFunction<R> {
245-
246-
@Override
247-
public boolean evaluate(Operator operator, Object rightValue, R rule, PolicyContext context) {
248-
throw new UnsupportedOperationException("Evaluation is not supported");
249-
}
250-
251-
@Override
252-
public Result<Void> validate(Operator operator, Object rightValue, R rule) {
253-
return inner.validate(leftOperand, operator, rightValue, rule);
254-
}
241+
DynamicAtomicConstraintRuleFunction<R, C> function) {
255242
}
256243
}

0 commit comments

Comments
 (0)