Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ForeachSpec, RuleOutcome, Builders, flere rulesets #80

Merged
merged 11 commits into from
Feb 17, 2022
92 changes: 81 additions & 11 deletions src/main/java/no/nav/fpsak/nare/Ruleset.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import no.nav.fpsak.nare.specification.ComputationalIfSpecification;
import no.nav.fpsak.nare.specification.ConditionalOrSpecification;
import no.nav.fpsak.nare.specification.ConditionalOrSpecification.Builder;
import no.nav.fpsak.nare.specification.ForeachSpecification;
import no.nav.fpsak.nare.specification.SequenceSpecification;
import no.nav.fpsak.nare.specification.Specification;

Expand All @@ -21,13 +21,20 @@ public Specification<V> regel(String id, String beskrivelse, Specification<V> sp
return specification.medBeskrivelse(beskrivelse).medID(id);
}

public Builder<V> hvisRegel(String id, String beskrivelse) {
public ConditionalOrSpecification.Builder<V> hvisRegel(String id, String beskrivelse) {
return ConditionalOrSpecification.<V>regel(id, beskrivelse);
}

public SequenceSpecification.Builder<V> sekvensRegel(String id, String beskrivelse) {
return SequenceSpecification.<V>regel(id, beskrivelse);
}

public ComputationalIfSpecification.Builder<V> betingetSekvensRegel(Specification<V> hvis, Specification<V> evaluer) {
return ComputationalIfSpecification.<V>regel().hvis(hvis, evaluer);
}

/**
* Realiserer flyten if <betingelse> then <then-spesifikasjon> else
* <else-spesifikasjon> for beregningsregel
* Realiserer flyten if <betingelse> then <then-spesifikasjon> else <else-spesifikasjon> for beregningsregel
*
* @param testSpec
* @param thenSpec
Expand All @@ -40,23 +47,43 @@ public Specification<V> beregningHvisRegel(Specification<V> testSpec, Specificat
}

/**
* Realiserer sekvens av to spesifikasjoner der bare den siste har betydning for
* videre flyt
*
* Realiserer flyten if <betingelse> then <then-spesifikasjon> (else true) for beregningsregel
*
* @param testSpec
* @param thenSpec
* @return
*/
public Specification<V> beregningHvisRegel(Specification<V> testSpec, Specification<V> thenSpec) {
return new ComputationalIfSpecification<>(testSpec, thenSpec);
}

/**
* Realiserer sekvens av 2 spesifikasjoner der bare den siste har betydning for videre flyt
*
* @param id
* @param beskrivelse
* @param spec1
* @param spec2
* @return
*/
public Specification<V> beregningsRegel(String id, String beskrivelse, Specification<V> spec1,
Specification<V> spec2) {
public Specification<V> beregningsRegel(String id, String beskrivelse, Specification<V> spec1, Specification<V> spec2) {
return new SequenceSpecification<>(id, beskrivelse, spec1, spec2);
}

/**
* Realiserer sekvens av N spesifikasjoner der bare den siste har betydning for
* videre flyt
* Realiserer sekvens av N spesifikasjoner der bare den siste har betydning for videre flyt
*
* @param id
* @param beskrivelse
* @param specs
* @return
*/
public Specification<V> beregningsRegel(String id, String beskrivelse, Specification<V>... specs) {
return new SequenceSpecification<>(id, beskrivelse, specs);
}

/**
* Realiserer sekvens av N spesifikasjoner der bare den siste har betydning for videre flyt
*
* @param id
* @param beskrivelse
Expand All @@ -72,6 +99,48 @@ public Specification<V> beregningsRegel(String id, String beskrivelse, List<Spec
return new SequenceSpecification<>(id, beskrivelse, specs);
}

/**
* Realiserer sekvens der en regel utføres N ganger - 1 gang for hvert element i en collection
*
* @param id
* @param beskrivelse
* @param spec regel som utføres 1 gang for hvert element i argumentlisten, med argName + arg som "scope"
* @param argName
* @param args argumentlisten, inneholder N argumenter
* @return
*/
public Specification<V> beregningsForeachRegel(String id, String beskrivelse, Specification<V> spec,
String argName, List<?> args) {
Objects.requireNonNull(spec, "spec1");
Objects.requireNonNull(args, "args1");
if (args.isEmpty()) {
throw new IllegalArgumentException("Argumentlisten kan ikke være tom");
}
return new ForeachSpecification<>(id, beskrivelse, spec, args, argName);
}

/**
* Realiserer sekvens der en regel utføres N ganger - 1 gang for hvert element i en collection - fulgt av annen regel
*
* @param id
* @param beskrivelse
* @param spec regel som utføres 1 gang for hvert element i argumentlisten, med argName + arg som "scope"
* @param argName
* @param args argumentlisten, inneholder N argumenter
* @param specThen regel som utføres 1 gang etter at spec er utført N ganger
* @return
*/
public Specification<V> beregningsForeachThenRegel(String id, String beskrivelse, Specification<V> spec,
String argName, List<?> args, Specification<V> specThen) {
Objects.requireNonNull(spec, "spec");
Objects.requireNonNull(args, "args1");
Objects.requireNonNull(specThen, "specThen");
if (args.isEmpty()) {
throw new IllegalArgumentException("Argumentlisten kan ikke være tom");
}
return new SequenceSpecification<>(id, beskrivelse, new ForeachSpecification<>(id, beskrivelse, spec, args, argName), specThen);
}

/**
* Realiserer sekvens der en regel utføres N ganger, etterfulgt av en
* spesifikasjon som har betydning for videre flyt
Expand All @@ -87,6 +156,7 @@ public Specification<V> beregningsRegel(String id, String beskrivelse, List<Spec
* @param spec2 utføres 1 gang etter at spec1 er utført N ganger
* @return
*/
@Deprecated // Bruk beregningForeach eller beregningForeachThen
public Specification<V> beregningsRegel(String id, String beskrivelse, Class<? extends DynamicRuleService<V>> spec1,
V regelmodell, String argumentBeskrivelse, List<? extends Object> args1, Specification<V> spec2) {
Objects.requireNonNull(spec1, "spec1");
Expand Down
10 changes: 2 additions & 8 deletions src/main/java/no/nav/fpsak/nare/ServiceArgument.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,13 @@

import java.util.Objects;

public class ServiceArgument {
public record ServiceArgument(String beskrivelse, Object verdi) {

public ServiceArgument(String beskrivelse, Object verdi) {
super();
public ServiceArgument {
Objects.requireNonNull(beskrivelse, "beskrivelse");
Objects.requireNonNull(verdi, "verdi");
this.beskrivelse = beskrivelse;
this.verdi = verdi;
}

private String beskrivelse;
private Object verdi;

public String getBeskrivelse() {
return beskrivelse;
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/no/nav/fpsak/nare/evaluation/Operator.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@

public enum Operator {

AND, OR, SINGLE, NOT, COND_OR, SEQUENCE, COMPUTATIONAL_IF
AND, OR, SINGLE, NOT, COND_OR, SEQUENCE, COMPUTATIONAL_IF, FOREACH
}
32 changes: 32 additions & 0 deletions src/main/java/no/nav/fpsak/nare/evaluation/RuleOutcome.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package no.nav.fpsak.nare.evaluation;

/*
* Implementer gjerne en lokal DomemeRuleOutcome som kan gi ut en enum eller record, unngå getReasonCode og string-kode-magi
* - Bruk T for typet grunn til utfallet
* - Bruk R for beregnet resultat
*/
public record RuleOutcome<T, R>(T reason, String reasonCode, String reasonTextTemplate, R calculated) implements RuleReasonRef {

public RuleOutcome(R calculated) {
this(null, null, "", calculated);
}

public RuleOutcome(T reason, String reasonCode) {
this(reason, reasonCode, "", null);
}

public RuleOutcome(T reason, String reasonCode, String reasonTextTemplate) {
this(reason, reasonCode, reasonTextTemplate, null);
}

@Override
public String getReasonTextTemplate() {
return reasonTextTemplate;
}

@Override
public String getReasonCode() {
return reasonCode;
}

}
5 changes: 5 additions & 0 deletions src/main/java/no/nav/fpsak/nare/evaluation/RuleReasonRef.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,16 @@

/**
* Represents a key for a valid outcome of an evaluation (leaf).
* Senere: Generification av RuleReasonRef<T> og T getReason() - vil treffe Evaluation
*/
public interface RuleReasonRef {

String getReasonTextTemplate();

/*
* Implementer heller en lokal DomemeRuleReasonRef som kan gi ut en enum eller record, unngå kode-magi
*/
@Deprecated(forRemoval = true)
String getReasonCode();

}
17 changes: 4 additions & 13 deletions src/main/java/no/nav/fpsak/nare/evaluation/RuleReasonRefImpl.java
Original file line number Diff line number Diff line change
@@ -1,19 +1,10 @@
package no.nav.fpsak.nare.evaluation;

import no.nav.fpsak.nare.specification.LeafSpecification;

/**
* Representerer en unik output fra en kjøring av Specifications. Produseres normalt av {@link LeafSpecification}.
/*
* Bruk RuleOutcome eller implementer en lokal RuleReasonRef som kan gi ut en enum eller record, unngå kode-magi
*/
public class RuleReasonRefImpl implements RuleReasonRef {

private final String reasonCode;
private final String reason;

public RuleReasonRefImpl(String reasonCode, String reason) {
this.reasonCode = reasonCode;
this.reason = reason;
}
@Deprecated(forRemoval = true)
public record RuleReasonRefImpl(String reasonCode, String reason) implements RuleReasonRef {

@Override
public String getReasonTextTemplate() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package no.nav.fpsak.nare.evaluation.node;

import no.nav.fpsak.nare.evaluation.AggregatedEvaluation;
import no.nav.fpsak.nare.evaluation.Evaluation;
import no.nav.fpsak.nare.evaluation.Operator;
import no.nav.fpsak.nare.evaluation.Resultat;

public class ForeachEvaluation extends AggregatedEvaluation {

public ForeachEvaluation(String id, String ruleDescription, Evaluation... children) {
super(Operator.FOREACH, id, ruleDescription, children);
}

@Override
public String reason() {
return "Utført " + ruleDescriptionText();
}

@Override
public Resultat result() {
// Endre hvis man tillater andre outcomes fra loop
return lastChild().result();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,25 @@

public class SequenceEvaluation extends AggregatedEvaluation {

private static final String OG = " og ";

public SequenceEvaluation(String id, String ruleDescription, Evaluation... children) {
super(Operator.SEQUENCE, id, ruleDescription, children);
}

@Override
public String reason() {
return "Utført " + firstChild().ruleIdentification() + " og " + secondChild().ruleIdentification();
var reasonText = new StringBuilder("Utført ");
for (var child : children()) {
reasonText.append(child.ruleIdentification()).append(OG);
}
var finalOg = reasonText.lastIndexOf(OG);
reasonText.delete(finalOg, finalOg + OG.length());
return reasonText.toString();
}

@Override
public Resultat result() {
return secondChild().result();
return lastChild().result();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import java.util.EnumSet;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import no.nav.fpsak.nare.evaluation.AggregatedEvaluation;
import no.nav.fpsak.nare.evaluation.Evaluation;
Expand All @@ -28,9 +27,8 @@ public boolean check(Operator op, Evaluation parent, Evaluation child) {
return false;
}

// special case, kun prosessere siste SingleEvaluation barn av SequenceEvaluation siden alle andre
// returnerer ja.
if (Operator.SEQUENCE.equals(parent.getOperator())) {
// special case, kun prosessere siste SingleEvaluation barn av SequenceEvaluation siden alle andre returnerer ja.
if (Operator.SEQUENCE.equals(parent.getOperator()) || Operator.FOREACH.equals(parent.getOperator())) {
String childRuleId = child.ruleIdentification();
String lastChildOfParentRuleId = ((AggregatedEvaluation) parent).lastChild().ruleIdentification();
return (childRuleId.equals(lastChildOfParentRuleId));
Expand All @@ -50,7 +48,9 @@ public EvaluationSummary(Evaluation rootEvaluation) {
this.rootEvaluation = rootEvaluation;
}

/** Convenience metode for å kun returnere et Leaf. Hvis det finnes flere kastes en exception. */
/**
* Convenience metode for å kun returnere et Leaf. Hvis det finnes flere kastes en exception.
*/
public Optional<Evaluation> singleLeafEvaluation(Resultat... acceptedResults) {
Collection<Evaluation> leafEvaluations = leafEvaluations(acceptedResults);

Expand All @@ -63,20 +63,6 @@ public Optional<Evaluation> singleLeafEvaluation(Resultat... acceptedResults) {
return Optional.of(leafEvaluations.iterator().next());
}
}

/** Convenience metode for å kun returnere et Leaf. Hvis det finnes flere kastes en exception. */
public Optional<String> singleLeafReason(Resultat... acceptedResults) {
Collection<String> leafReasons = leafReasons(acceptedResults);

if (leafReasons.size() > 1) {
throw new IllegalStateException("Det finnes flere enn ett Leaf resultat for angitt aksepterte resultater (" //$NON-NLS-1$
+ Arrays.toString(acceptedResults) + "): " + leafReasons); //$NON-NLS-1$
} else if (leafReasons.isEmpty()) {
return Optional.empty();
} else {
return Optional.of(leafReasons.iterator().next());
}
}

public Collection<Evaluation> leafEvaluations(Resultat... acceptedResults) {
Set<Resultat> accepted = acceptedResults.length > 0 ? EnumSet.copyOf(Arrays.asList(acceptedResults))
Expand All @@ -87,20 +73,4 @@ public Collection<Evaluation> leafEvaluations(Resultat... acceptedResults) {
return visitor.getCollected();
}

public Collection<String> leafReasons(Resultat... acceptedResults) {

Set<Resultat> accepted = acceptedResults.length > 0 ? EnumSet.copyOf(Arrays.asList(acceptedResults))
: EnumSet.allOf(Resultat.class);

NonCircularVisitorEvaluationCollector visitor = new NonCircularVisitorEvaluationCollector(new LeafNodeVisitorCondition(accepted));

rootEvaluation.visit(rootEvaluation, visitor);
return visitor.getCollected().stream()
.filter(e -> e.getOutcome() != null)
.map(this::getReasonCode).distinct().collect(Collectors.toList());
}

private String getReasonCode(Evaluation e) {
return e.getOutcome() == null ? null : e.getOutcome().getReasonCode();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import no.nav.fpsak.nare.evaluation.Evaluation;
import no.nav.fpsak.nare.evaluation.Operator;
import no.nav.fpsak.nare.evaluation.node.SingleEvaluation;
import no.nav.fpsak.nare.evaluation.summary.EvaluationSummary.EvaluationVisitorCondition;

public class NonCircularVisitorEvaluationCollector implements EvaluationVisitor {
Expand All @@ -24,9 +25,10 @@ public Set<Evaluation> getCollected() {

@Override
public boolean visiting(Operator operator, Evaluation parentEvaluation, Evaluation evaluation) {
if (Objects.equals(parentEvaluation, evaluation)) {
// er ved roten
return true;
if (Objects.equals(parentEvaluation, evaluation) &&
(!(evaluation instanceof SingleEvaluation) || visited.contains(evaluation))) {
// er ved roten. Special case med at roten er en Leaf
return true;
}
boolean added = visited.add(evaluation);
if (!added) {
Expand Down
Loading