diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/Construction.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/Construction.java index 5960bc03aee..e7162dd951b 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/Construction.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/Construction.java @@ -71,7 +71,6 @@ public class Construction extends AbstractConst protected static final String OP_EVALUATE = Construction.class.getName() + ".evaluate"; private ObjectType orderOneObject; - private String resourceOid; private ResolvedResource resolvedResource; private ExpressionProfile expressionProfile; private MappingFactory mappingFactory; @@ -351,13 +350,11 @@ public NextRecompute evaluate(Task task, OperationResult parentResult) private void evaluateKindIntentObjectClass(ResourceType resource, Task task, OperationResult result) throws SchemaException, ConfigurationException, ObjectNotFoundException, CommunicationException, SecurityViolationException, ExpressionEvaluationException { if (getConstructionType().getResourceRef() != null) { - resourceOid = getConstructionType().getResourceRef().getOid(); + String resourceOid = getConstructionType().getResourceRef().getOid(); if (resourceOid != null && !resource.getOid().equals(resourceOid)) { throw new IllegalStateException( "The specified resource and the resource in construction does not match"); } - } else { - resourceOid = null; } RefinedResourceSchema refinedSchema = RefinedResourceSchemaImpl.getRefinedSchema(resource, @@ -450,7 +447,7 @@ private PrismValueDeltaSetTriple> evaluateTagTripe(Ta } private EvaluatedConstructionImpl createEvaluatedConstruction(String tag) { - ResourceShadowDiscriminator rsd = new ResourceShadowDiscriminator(resourceOid, refinedObjectClassDefinition.getKind(), refinedObjectClassDefinition.getIntent(), tag, false); + ResourceShadowDiscriminator rsd = new ResourceShadowDiscriminator(getResourceOid(), refinedObjectClassDefinition.getKind(), refinedObjectClassDefinition.getIntent(), tag, false); return createEvaluatedConstruction(rsd); } @@ -458,44 +455,29 @@ protected EvaluatedConstructionImpl createEvaluatedConstruction(ResourceShad return new EvaluatedConstructionImpl<>(this, rsd); } - protected void evaluateConstructions(Task task, OperationResult result) throws CommunicationException, ObjectNotFoundException, SchemaException, SecurityViolationException, ConfigurationException, ExpressionEvaluationException { - try { - evaluatedConstructionTriple.foreach( evaluatedConstruction -> { - try { - evaluateConstruction(evaluatedConstruction, task, result); - } catch (Exception e) { - throw new TunnelException(e); - } - }); - } catch (TunnelException te) { - Exception e = (Exception) te.getCause(); - if (e instanceof RuntimeException) { - throw (RuntimeException)e; - } - if (e instanceof CommunicationException) { - throw (CommunicationException)e; - } - if (e instanceof ObjectNotFoundException) { - throw (ObjectNotFoundException)e; - } - if (e instanceof SchemaException) { - throw (SchemaException)e; - } - if (e instanceof SecurityViolationException) { - throw (SecurityViolationException)e; - } - if (e instanceof ConfigurationException) { - throw (ConfigurationException)e; - } - if (e instanceof ExpressionEvaluationException) { - throw (ExpressionEvaluationException)e; - } - throw new SystemException(e); + protected NextRecompute evaluateConstructions(Task task, OperationResult result) throws CommunicationException, ObjectNotFoundException, SchemaException, SecurityViolationException, ConfigurationException, ExpressionEvaluationException { + NextRecompute nextRecompute = null; + + // This code may seem primitive and old-fashioned. + // But equivalent functional code (using foreach()) is just insane due to nextRecompute and exception handling. + for (EvaluatedConstructionImpl evaluatedConstruction : evaluatedConstructionTriple.getZeroSet()) { + NextRecompute construcionNextRecompute = evaluateConstruction(evaluatedConstruction, task, result); + nextRecompute = NextRecompute.update(construcionNextRecompute, nextRecompute); + } + for (EvaluatedConstructionImpl evaluatedConstruction : evaluatedConstructionTriple.getPlusSet()) { + NextRecompute construcionNextRecompute = evaluateConstruction(evaluatedConstruction, task, result); + nextRecompute = NextRecompute.update(construcionNextRecompute, nextRecompute); + } + for (EvaluatedConstructionImpl evaluatedConstruction : evaluatedConstructionTriple.getMinusSet()) { + NextRecompute construcionNextRecompute = evaluateConstruction(evaluatedConstruction, task, result); + nextRecompute = NextRecompute.update(construcionNextRecompute, nextRecompute); } + + return nextRecompute; } - protected void evaluateConstruction(EvaluatedConstructionImpl evaluatedConstruction, Task task, OperationResult result) throws CommunicationException, ObjectNotFoundException, SchemaException, SecurityViolationException, ConfigurationException, ExpressionEvaluationException { - evaluatedConstruction.evaluate(task, result); + protected NextRecompute evaluateConstruction(EvaluatedConstructionImpl evaluatedConstruction, Task task, OperationResult result) throws CommunicationException, ObjectNotFoundException, SchemaException, SecurityViolationException, ConfigurationException, ExpressionEvaluationException { + return evaluatedConstruction.evaluate(task, result); } @@ -764,6 +746,16 @@ public String debugDump(int indent) { sb.append("\n"); sb.append(getAssignmentPath().debugDump(indent + 1)); } + sb.append("\n"); + DebugUtil.debugDumpLabel(sb, "evaluated constructions", indent + 1); + if (evaluatedConstructionTriple == null) { + sb.append(" (null)"); + } else if (evaluatedConstructionTriple.isEmpty()) { + sb.append(" (empty)"); + } else { + sb.append("\n"); + sb.append(evaluatedConstructionTriple.debugDump(indent + 2)); + } return sb.toString(); } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/EvaluatedConstructionImpl.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/EvaluatedConstructionImpl.java index 3c4223ba4f6..473cd495393 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/EvaluatedConstructionImpl.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/EvaluatedConstructionImpl.java @@ -133,6 +133,7 @@ protected void addAssociationMapping( public NextRecompute evaluate(Task task, OperationResult result) throws CommunicationException, ObjectNotFoundException, SchemaException, SecurityViolationException, ConfigurationException, ExpressionEvaluationException { initializeProjectionContext(); evaluateAttributes(task, result); + evaluateAssociations(task, result); return null; } @@ -326,7 +327,8 @@ public String debugDump(int indent) { StringBuilder sb = new StringBuilder(); DebugUtil.debugDumpLabelLn(sb, this.getClass().getSimpleName(), indent); DebugUtil.debugDumpWithLabelShortDumpLn(sb, "discriminator", rsd, indent + 1); - DebugUtil.debugDumpWithLabelLn(sb, "construction", construction, indent + 1); + // We do not want to dump construction here. This can lead to cycles. + // We usually dump EvaluatedConstruction is a Construction dump anyway, therefore the context should be quite clear. DebugUtil.debugDumpWithLabelToString(sb, "projectionContext", projectionContext, indent + 1); if (attributeMappings != null && !attributeMappings.isEmpty()) { sb.append("\n"); diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/OutboundConstruction.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/OutboundConstruction.java index d7cc0241993..426fb907fa3 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/OutboundConstruction.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/OutboundConstruction.java @@ -78,9 +78,9 @@ public NextRecompute evaluate(Task task, OperationResult parentResult) try { initializeDefinitions(); createEvaluatedConstructions(task, result); - evaluateConstructions(task, result); + NextRecompute nextRecompute = evaluateConstructions(task, result); result.recordSuccess(); - return null; + return nextRecompute; } catch (Throwable e) { result.recordFatalError(e); throw e; diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/mappings/NextRecompute.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/mappings/NextRecompute.java index 08a45d4df23..955ebd7c18f 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/mappings/NextRecompute.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/mappings/NextRecompute.java @@ -80,4 +80,12 @@ public static NextRecompute upd return existing; } } + + public static NextRecompute update(NextRecompute mappingNextRecompute, NextRecompute existing) { + if (mappingNextRecompute != null && (existing == null || existing.nextRecomputeTime.compare(mappingNextRecompute.nextRecomputeTime) == DatatypeConstants.GREATER)) { + return mappingNextRecompute; + } else { + return existing; + } + } } diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestEntitlements.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestEntitlements.java index 016f2f48db9..6e9ee5432d9 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestEntitlements.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestEntitlements.java @@ -223,10 +223,10 @@ public void test200AssignRoleSwashbucklerToJack() throws Exception { then(); assertSuccess(result); - PrismObject userAfter = getUser(USER_JACK_OID); - display("User after", userAfter); - assertAssignedRole(userAfter, ROLE_SWASHBUCKLER_OID); - assertAssignments(userAfter, 1); + assertUserAfter(USER_JACK_OID) + .assignments() + .assertAssignments(1) + .assertRole(ROLE_SWASHBUCKLER_OID); assertDefaultDummyAccount(ACCOUNT_JACK_DUMMY_USERNAME, ACCOUNT_JACK_DUMMY_FULLNAME, true); DummyGroup dummyGroup = getDummyResource().getGroupByName(GROUP_DUMMY_SWASHBUCKLERS_NAME); diff --git a/model/model-intest/src/test/resources/logback-test.xml b/model/model-intest/src/test/resources/logback-test.xml index 43e787318b8..6253e196752 100644 --- a/model/model-intest/src/test/resources/logback-test.xml +++ b/model/model-intest/src/test/resources/logback-test.xml @@ -52,18 +52,19 @@ + - - - - + + + + - +