From de1b3a88c5e090aacc35159cd5fa60e0a3b6b5cd Mon Sep 17 00:00:00 2001 From: Radovan Semancik Date: Fri, 3 Mar 2017 14:31:08 +0100 Subject: [PATCH] Light recompute/clockwork partial execution (MID-3384, MID-1876) --- .../midpoint/prism/delta/ReferenceDelta.java | 8 +- .../schema/constants/SchemaConstants.java | 3 +- .../xml/ns/public/common/common-core-3.xsd | 11 + .../model/api/ModelExecuteOptions.java | 46 +- .../midpoint/model/api/ModelService.java | 26 + .../impl/controller/ModelController.java | 14 +- .../impl/expr/MidpointFunctionsImpl.java | 2 +- .../model/impl/lens/ContextFactory.java | 17 +- .../midpoint/model/impl/lens/LensContext.java | 1182 +++++++++-------- .../lens/projector/AssignmentProcessor.java | 2 +- .../sync/FocusValidityScannerTaskHandler.java | 18 +- .../model/impl/sync/RecomputeTaskHandler.java | 22 +- .../impl/trigger/RecomputeTriggerHandler.java | 10 +- .../midpoint/model/impl/util/Utils.java | 26 +- ...bstractConfiguredModelIntegrationTest.java | 21 + .../midpoint/model/intest/TestActivation.java | 40 +- .../model/intest/TestMultiResource.java | 11 +- .../intest/negative/TestAssignmentErrors.java | 12 +- .../model/intest/orgstruct/TestOrgStruct.java | 123 +- .../orgstruct/TestOrgStructCaribbean.java | 10 +- .../midpoint/model/intest/rbac/TestRbac.java | 6 +- .../model/intest/sync/TestRecomputeTask.java | 101 +- .../src/test/resources/logback-test.xml | 5 +- .../sync/task-user-recompute-light.xml | 48 + .../test/AbstractModelIntegrationTest.java | 8 +- 25 files changed, 1131 insertions(+), 641 deletions(-) create mode 100644 model/model-intest/src/test/resources/sync/task-user-recompute-light.xml diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/ReferenceDelta.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/ReferenceDelta.java index 0a6276d7510..aaef0a25004 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/ReferenceDelta.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/ReferenceDelta.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2015 Evolveum + * 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. @@ -114,7 +114,11 @@ public static ReferenceDelta createModificationReplace(ItemPath path, PrismObjec PrismReferenceValue refValue) { PrismReferenceDefinition referenceDefinition = objectDefinition.findItemDefinition(path, PrismReferenceDefinition.class); ReferenceDelta referenceDelta = new ReferenceDelta(path, referenceDefinition, objectDefinition.getPrismContext()); // hoping the prismContext is there - referenceDelta.setValueToReplace(refValue); + if (refValue == null) { + referenceDelta.setValueToReplace(); + } else { + referenceDelta.setValueToReplace(refValue); + } return referenceDelta; } diff --git a/infra/schema/src/main/java/com/evolveum/midpoint/schema/constants/SchemaConstants.java b/infra/schema/src/main/java/com/evolveum/midpoint/schema/constants/SchemaConstants.java index 02164a919a0..13355c6e1f4 100644 --- a/infra/schema/src/main/java/com/evolveum/midpoint/schema/constants/SchemaConstants.java +++ b/infra/schema/src/main/java/com/evolveum/midpoint/schema/constants/SchemaConstants.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Evolveum + * 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. @@ -127,6 +127,7 @@ public abstract class SchemaConstants { public static final QName C_ITEM_PATH_FIELD = new QName(NS_C, "itemPathField"); public static final QName C_ACTIVATION_STATUS_TYPE = new QName(NS_C, "ActivationStatusType"); public static final QName C_SECURITY_POLICY = new QName(NS_C, "securityPolicy"); + public static final QName C_MODEL_EXECUTE_OPTIONS = new QName(NS_C, "modelExecuteOptions"); public static final QName T_POLY_STRING_TYPE = new QName(SchemaConstantsGenerated.NS_TYPES, "PolyStringType"); diff --git a/infra/schema/src/main/resources/xml/ns/public/common/common-core-3.xsd b/infra/schema/src/main/resources/xml/ns/public/common/common-core-3.xsd index 8cff0be355f..2169a6677b9 100644 --- a/infra/schema/src/main/resources/xml/ns/public/common/common-core-3.xsd +++ b/infra/schema/src/main/resources/xml/ns/public/common/common-core-3.xsd @@ -12135,6 +12135,16 @@ + + + + Option to reconcile focus while executing changes. + If this option is set and the reconcile option is not set then the projections + reconciliation will not be forced (but it may still happen if other configuration + loads full projection). + + + @@ -12203,6 +12213,7 @@ + diff --git a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelExecuteOptions.java b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelExecuteOptions.java index b0d12e9034f..ffdf9a4f7cc 100644 --- a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelExecuteOptions.java +++ b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelExecuteOptions.java @@ -50,9 +50,18 @@ public class ModelExecuteOptions extends AbstractOptions implements Serializable private Boolean noCrypt; /** - * Option to reconcile focus while executing changes. + * Option to reconcile focus and all projections while executing changes. + * (implies reconcileFocus) */ private Boolean reconcile; + + /** + * Option to reconcile focus while executing changes. + * If this option is set and the reconcile option is not set then the projections + * reconciliation will not be forced (but it may still happen if other configuration + * loads full projection). + */ + private Boolean reconcileFocus; /** * Option to reconcile affected objects after executing changes. @@ -196,7 +205,7 @@ public void setReconcile(Boolean reconcile) { this.reconcile = reconcile; } - public static boolean isReconcile(ModelExecuteOptions options){ + public static boolean isReconcile(ModelExecuteOptions options) { if (options == null){ return false; } @@ -206,16 +215,40 @@ public static boolean isReconcile(ModelExecuteOptions options){ return options.reconcile; } - public static ModelExecuteOptions createReconcile(){ + public static ModelExecuteOptions createReconcile() { ModelExecuteOptions opts = new ModelExecuteOptions(); opts.setReconcile(true); return opts; } - public ModelExecuteOptions setReconcile(){ + public ModelExecuteOptions setReconcile() { setReconcile(true); return this; } + + public Boolean getReconcileFocus() { + return reconcileFocus; + } + + public void setReconcileFocus(Boolean reconcileFocus) { + this.reconcileFocus = reconcileFocus; + } + + public static ModelExecuteOptions createReconcileFocus() { + ModelExecuteOptions opts = new ModelExecuteOptions(); + opts.setReconcileFocus(true); + return opts; + } + + public static boolean isReconcileFocus(ModelExecuteOptions options) { + if (options == null){ + return false; + } + if (options.reconcileFocus == null){ + return false; + } + return options.reconcileFocus; + } public Boolean getReconcileAffected() { return reconcileAffected; @@ -456,6 +489,7 @@ public ModelExecuteOptionsType toModelExecutionOptionsType() { retval.setRaw(raw); retval.setNoCrypt(noCrypt); retval.setReconcile(reconcile); + retval.setReconcileFocus(reconcileFocus); retval.setExecuteImmediatelyAfterApproval(executeImmediatelyAfterApproval); retval.setOverwrite(overwrite); retval.setIsImport(isImport); @@ -463,6 +497,7 @@ public ModelExecuteOptionsType toModelExecutionOptionsType() { retval.setReevaluateSearchFilters(reevaluateSearchFilters); // preAuthorized is purposefully omitted (security reasons) retval.setRequestBusinessContext(requestBusinessContext); + retval.setPartialProcessing(partialProcessing); return retval; } @@ -475,6 +510,7 @@ public static ModelExecuteOptions fromModelExecutionOptionsType(ModelExecuteOpti retval.setRaw(type.isRaw()); retval.setNoCrypt(type.isNoCrypt()); retval.setReconcile(type.isReconcile()); + retval.setReconcileFocus(type.isReconcileFocus()); retval.setExecuteImmediatelyAfterApproval(type.isExecuteImmediatelyAfterApproval()); retval.setOverwrite(type.isOverwrite()); retval.setIsImport(type.isIsImport()); @@ -482,6 +518,7 @@ public static ModelExecuteOptions fromModelExecutionOptionsType(ModelExecuteOpti retval.setReevaluateSearchFilters(type.isReevaluateSearchFilters()); // preAuthorized is purposefully omitted (security reasons) retval.setRequestBusinessContext(type.getRequestBusinessContext()); + retval.setPartialProcessing(type.getPartialProcessing()); return retval; } @@ -537,6 +574,7 @@ public String toString() { appendFlag(sb, "preAuthorized", preAuthorized); appendFlag(sb, "raw", raw); appendFlag(sb, "reconcile", reconcile); + appendFlag(sb, "reconcileFocus", reconcileFocus); appendFlag(sb, "reevaluateSearchFilters", reevaluateSearchFilters); appendFlag(sb, "reconcileAffected", reconcileAffected); appendFlag(sb, "requestBusinessContext", requestBusinessContext == null ? null : true); diff --git a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelService.java b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelService.java index 25f8da0b785..cd0d2b716fd 100644 --- a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelService.java +++ b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelService.java @@ -241,8 +241,15 @@ Collection> executeChanges(Collection CommunicationException, ConfigurationException, PolicyViolationException, SecurityViolationException; /** + *

* Recomputes focal object with the specified OID. The operation considers all the applicable policies and * mapping and tries to re-apply them as necessary. + *

+ *

+ * This method is DEPRECATED. It is provided for compatibility only. Please use the version with options + * instead of this one. This method will assume the reconcile option to keep compatible behavior with + * previous versions. + *

* * @param type type (class) of an object to recompute * @param oid OID of the object to recompute @@ -252,9 +259,28 @@ Collection> executeChanges(Collection * Task instance. It gives context to the execution (e.g. security context) * @param parentResult parent OperationResult (in/out) */ + @Deprecated void recompute(Class type, String oid, Task task, OperationResult parentResult) throws SchemaException, PolicyViolationException, ExpressionEvaluationException, ObjectNotFoundException, ObjectAlreadyExistsException, CommunicationException, ConfigurationException, SecurityViolationException; + /** + * Recomputes focal object with the specified OID. The operation considers all the applicable policies and + * mapping and tries to re-apply them as necessary. + * + * @since 3.6 + * + * @param type type (class) of an object to recompute + * @param oid OID of the object to recompute + * @param options execute options + * @param parentResult + * parent OperationResult (in/out) + * @param task + * Task instance. It gives context to the execution (e.g. security context) + * @param parentResult parent OperationResult (in/out) + */ + void recompute(Class type, String oid, ModelExecuteOptions options, Task task, OperationResult parentResult) + throws SchemaException, PolicyViolationException, ExpressionEvaluationException, ObjectNotFoundException, ObjectAlreadyExistsException, CommunicationException, ConfigurationException, SecurityViolationException; + /** *

* Returns the User object representing owner of specified account (account diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelController.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelController.java index 37c2afd960e..2f134aa8b46 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelController.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelController.java @@ -580,7 +580,7 @@ public Collection> executeChanges(fin LOGGER.debug("Recomputing {} because there was explosive projection", focus); - LensContext recomputeContext = contextFactory.createRecomputeContext(focus, task, result); + LensContext recomputeContext = contextFactory.createRecomputeContext(focus, options, task, result); recomputeContext.setDoReconciliationForAllProjections(true); if (LOGGER.isTraceEnabled()) { LOGGER.trace("Recomputing {}, context:\n{}", focus, recomputeContext.debugDump()); @@ -670,6 +670,12 @@ private void reevaluateSearchFilters(Class objectTypeC @Override public void recompute(Class type, String oid, Task task, OperationResult parentResult) throws SchemaException, PolicyViolationException, ExpressionEvaluationException, ObjectNotFoundException, ObjectAlreadyExistsException, CommunicationException, ConfigurationException, SecurityViolationException { + ModelExecuteOptions options = ModelExecuteOptions.createReconcile(); + recompute(type, oid, options, task, parentResult); + } + + @Override + public void recompute(Class type, String oid, ModelExecuteOptions options, Task task, OperationResult parentResult) throws SchemaException, PolicyViolationException, ExpressionEvaluationException, ObjectNotFoundException, ObjectAlreadyExistsException, CommunicationException, ConfigurationException, SecurityViolationException { OperationResult result = parentResult.createMinorSubresult(RECOMPUTE); result.addParams(new String[] { "oid", "type" }, oid, type); @@ -683,11 +689,11 @@ public void recompute(Class type, String oid, Task tas LOGGER.debug("Recomputing {}", focus); - LensContext syncContext = contextFactory.createRecomputeContext(focus, task, result); + LensContext lensContext = contextFactory.createRecomputeContext(focus, options, task, result); if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Recomputing {}, context:\n{}", focus, syncContext.debugDump()); + LOGGER.trace("Recomputing {}, context:\n{}", focus, lensContext.debugDump()); } - clockwork.run(syncContext, task, result); + clockwork.run(lensContext, task, result); result.computeStatus(); diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/expr/MidpointFunctionsImpl.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/expr/MidpointFunctionsImpl.java index 36eba72a225..248ab2c38fa 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/expr/MidpointFunctionsImpl.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/expr/MidpointFunctionsImpl.java @@ -910,7 +910,7 @@ public void recompute(Class type, String oid) throws Sc ExpressionEvaluationException, ObjectNotFoundException, ObjectAlreadyExistsException, CommunicationException, ConfigurationException, SecurityViolationException { - modelService.recompute(type, oid, getCurrentTask(), getCurrentResult()); + modelService.recompute(type, oid, null, getCurrentTask(), getCurrentResult()); } @Override diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/ContextFactory.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/ContextFactory.java index 5fce9522583..672ec160dfb 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/ContextFactory.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/ContextFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2013 Evolveum + * 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. @@ -161,41 +161,42 @@ public LensContext createContext( public LensContext createRecomputeContext( - PrismObject object, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException { + PrismObject object, ModelExecuteOptions options, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException { Class typeClass = object.getCompileTimeClass(); LensContext context; if (isFocalClass(typeClass)) { - context = createRecomputeFocusContext((Class)typeClass, (PrismObject) object, task, result); + context = createRecomputeFocusContext((Class)typeClass, (PrismObject) object, options, task, result); } else if (ShadowType.class.isAssignableFrom(typeClass)) { - context = createRecomputeProjectionContext((PrismObject) object, task, result); + context = createRecomputeProjectionContext((PrismObject) object, options, task, result); } else { throw new IllegalArgumentException("Cannot create recompute context for "+object); } + context.setOptions(options); context.setLazyAuditRequest(true); return context; } public LensContext createRecomputeFocusContext( - Class focusType, PrismObject focus, Task task, OperationResult result) { + Class focusType, PrismObject focus, ModelExecuteOptions options, Task task, OperationResult result) { LensContext syncContext = new LensContext(focusType, prismContext, provisioningService); LensFocusContext focusContext = syncContext.createFocusContext(); focusContext.setLoadedObject(focus); focusContext.setOid(focus.getOid()); syncContext.setChannel(QNameUtil.qNameToUri(SchemaConstants.CHANGE_CHANNEL_RECOMPUTE)); - syncContext.setDoReconciliationForAllProjections(true); + syncContext.setDoReconciliationForAllProjections(ModelExecuteOptions.isReconcile(options)); return syncContext; } public LensContext createRecomputeProjectionContext( - PrismObject shadow, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException { + PrismObject shadow, ModelExecuteOptions options, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException { provisioningService.applyDefinition(shadow, result); LensContext syncContext = new LensContext(null, prismContext, provisioningService); LensProjectionContext projectionContext = syncContext.createProjectionContext(); projectionContext.setLoadedObject(shadow); projectionContext.setOid(shadow.getOid()); - projectionContext.setDoReconciliation(true); + projectionContext.setDoReconciliation(ModelExecuteOptions.isReconcile(options)); syncContext.setChannel(QNameUtil.qNameToUri(SchemaConstants.CHANGE_CHANNEL_RECOMPUTE)); return syncContext; } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensContext.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensContext.java index df15b876043..58da4e5ae0c 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensContext.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensContext.java @@ -47,155 +47,163 @@ */ public class LensContext implements ModelContext { - private static final long serialVersionUID = -778283437426659540L; - private static final String DOT_CLASS = LensContext.class.getName() + "."; + private static final long serialVersionUID = -778283437426659540L; + private static final String DOT_CLASS = LensContext.class.getName() + "."; + + private ModelState state = ModelState.INITIAL; - private ModelState state = ModelState.INITIAL; - /** - * Channel that is the source of primary change (GUI, live sync, import, ...) - */ - private String channel; - + * Channel that is the source of primary change (GUI, live sync, import, + * ...) + */ + private String channel; + private LensFocusContext focusContext; private Collection projectionContexts = new ArrayList(); /** - * EXPERIMENTAL. A trace of resource objects that once existed but were unlinked or deleted, - * and the corresponding contexts were rotten and removed afterwards. + * EXPERIMENTAL. A trace of resource objects that once existed but were + * unlinked or deleted, and the corresponding contexts were rotten and + * removed afterwards. * * Necessary to evaluate old state of hasLinkedAccount. * - * TODO implement as non-transient. - * TODO consider storing whole projection contexts here. - */ + * TODO implement as non-transient. TODO consider storing whole projection + * contexts here. + */ transient private Collection historicResourceObjects; private Class focusClass; - - private boolean lazyAuditRequest = false; // should be the request audited just before the execution is audited? - private boolean requestAudited = false; // was the request audited? - private boolean executionAudited = false; // was the execution audited? + + private boolean lazyAuditRequest = false; // should be the request audited + // just before the execution is + // audited? + private boolean requestAudited = false; // was the request audited? + private boolean executionAudited = false; // was the execution audited? private LensContextStatsType stats = new LensContextStatsType(); - + /** - * Metadata of the request. Metadata recorded when the operation has started. - * Currently only the requestTimestamp and requestorRef are meaningful. But - * later other metadata may be used. + * Metadata of the request. Metadata recorded when the operation has + * started. Currently only the requestTimestamp and requestorRef are + * meaningful. But later other metadata may be used. */ private MetadataType requestMetadata; /* - * Executed deltas from rotten contexts. + * Executed deltas from rotten contexts. */ private List> rottenExecutedDeltas = new ArrayList>(); transient private ObjectTemplateType focusTemplate; transient private ProjectionPolicyType accountSynchronizationSettings; transient private ValuePolicyType globalPasswordPolicy; - + transient private DeltaSetTriple evaluatedAssignmentTriple; - + /** - * Just a cached copy. Keep it in context so we do not need to reload it all the time. + * Just a cached copy. Keep it in context so we do not need to reload it all + * the time. */ transient private PrismObject systemConfiguration; - + + /** + * True if we want to reconcile all accounts in this context. + */ + private boolean doReconciliationForAllProjections = false; + /** - * True if we want to reconcile all accounts in this context. - */ - private boolean doReconciliationForAllProjections = false; - - /** * Current wave of computation and execution. */ int projectionWave = 0; - /** + /** * Current wave of execution. */ int executionWave = 0; - + private String triggeredResourceOid; /** - * At this level, isFresh == false means that deeper recomputation has to be carried out. + * At this level, isFresh == false means that deeper recomputation has to be + * carried out. */ transient private boolean isFresh = false; transient private boolean isRequestAuthorized = false; - + /** - * Cache of resource instances. It is used to reduce the number of read (getObject) calls for ResourceType objects. - */ - transient private Map resourceCache; - + * Cache of resource instances. It is used to reduce the number of read + * (getObject) calls for ResourceType objects. + */ + transient private Map resourceCache; + transient private PrismContext prismContext; - transient private ProvisioningService provisioningService; - + transient private ProvisioningService provisioningService; + private ModelExecuteOptions options; - + /** * Used mostly in unit tests. */ transient private LensDebugListener debugListener; - /** - * User feedback. - */ - transient private Collection progressListeners; - - private Map sequences = new HashMap<>(); + /** + * User feedback. + */ + transient private Collection progressListeners; + + private Map sequences = new HashMap<>(); /** - * Moved from ProjectionValuesProcessor - * TODO consider if necessary to serialize to XML + * Moved from ProjectionValuesProcessor TODO consider if necessary to + * serialize to XML */ private List conflictingProjectionContexts = new ArrayList<>(); - public LensContext(Class focusClass, PrismContext prismContext, ProvisioningService provisioningService) { + public LensContext(Class focusClass, PrismContext prismContext, + ProvisioningService provisioningService) { Validate.notNull(prismContext, "No prismContext"); - - this.prismContext = prismContext; - this.provisioningService = provisioningService; - this.focusClass = focusClass; - } - + + this.prismContext = prismContext; + this.provisioningService = provisioningService; + this.focusClass = focusClass; + } + protected LensContext(PrismContext prismContext) { this.prismContext = prismContext; } - + public PrismContext getPrismContext() { return prismContext; } - + protected PrismContext getNotNullPrismContext() { if (prismContext == null) { - throw new IllegalStateException("Null prism context in "+this+"; the context was not adopted (most likely)"); + throw new IllegalStateException( + "Null prism context in " + this + "; the context was not adopted (most likely)"); } return prismContext; } - public ProvisioningService getProvisioningService() { - return provisioningService; - } - - public void setTriggeredResource(String triggeredResourceOid) { + public ProvisioningService getProvisioningService() { + return provisioningService; + } + + public void setTriggeredResource(String triggeredResourceOid) { this.triggeredResourceOid = triggeredResourceOid; } - - public void setTriggeredResource(ResourceType triggeredResource) { - if (triggeredResource != null){ - this.triggeredResourceOid = triggeredResource.getOid(); - } + + public void setTriggeredResource(ResourceType triggeredResource) { + if (triggeredResource != null) { + this.triggeredResourceOid = triggeredResource.getOid(); + } } - - public String getTriggeredResourceOid() { + + public String getTriggeredResourceOid() { return triggeredResourceOid; } - - @Override + @Override public ModelState getState() { return state; } @@ -208,15 +216,15 @@ public void setState(ModelState state) { public LensFocusContext getFocusContext() { return focusContext; } - + public void setFocusContext(LensFocusContext focusContext) { this.focusContext = focusContext; } - + public LensFocusContext createFocusContext() { return createFocusContext(null); } - + public LensFocusContext createFocusContext(Class explicitFocusClass) { if (explicitFocusClass != null) { this.focusClass = explicitFocusClass; @@ -224,11 +232,11 @@ public LensFocusContext createFocusContext(Class explicitFocusClass) { focusContext = new LensFocusContext(focusClass, this); return focusContext; } - + public LensFocusContext getOrCreateFocusContext() { return getOrCreateFocusContext(null); } - + public LensFocusContext getOrCreateFocusContext(Class explicitFocusClass) { if (focusContext == null) { createFocusContext(explicitFocusClass); @@ -240,27 +248,27 @@ public LensFocusContext getOrCreateFocusContext(Class explicitFocusClass) public Collection getProjectionContexts() { return projectionContexts; } - + public Iterator getProjectionContextsIterator() { return projectionContexts.iterator(); } - + public void addProjectionContext(LensProjectionContext projectionContext) { projectionContexts.add(projectionContext); } - + public LensProjectionContext findProjectionContextByOid(String oid) { - for (LensProjectionContext projCtx: getProjectionContexts()) { + for (LensProjectionContext projCtx : getProjectionContexts()) { if (oid.equals(projCtx.getOid())) { return projCtx; } } return null; } - + public LensProjectionContext findProjectionContext(ResourceShadowDiscriminator rat) { Validate.notNull(rat); - for (LensProjectionContext projCtx: getProjectionContexts()) { + for (LensProjectionContext projCtx : getProjectionContexts()) { if (projCtx.compareResourceShadowDiscriminator(rat, true)) { return projCtx; } @@ -275,22 +283,23 @@ public LensProjectionContext findOrCreateProjectionContext(ResourceShadowDiscrim } return projectionContext; } - + public ObjectTemplateType getFocusTemplate() { return focusTemplate; } - + public void setFocusTemplate(ObjectTemplateType focusTemplate) { this.focusTemplate = focusTemplate; } - + public LensProjectionContext findProjectionContext(ResourceShadowDiscriminator rat, String oid) { LensProjectionContext projectionContext = findProjectionContext(rat); - - if (projectionContext == null || projectionContext.getOid() == null || !oid.equals(projectionContext.getOid())) { + + if (projectionContext == null || projectionContext.getOid() == null + || !oid.equals(projectionContext.getOid())) { return null; } - + return projectionContext; } @@ -298,8 +307,7 @@ public PrismObject getSystemConfiguration() { return systemConfiguration; } - public void setSystemConfiguration( - PrismObject systemConfiguration) { + public void setSystemConfiguration(PrismObject systemConfiguration) { this.systemConfiguration = systemConfiguration; } @@ -307,19 +315,18 @@ public ProjectionPolicyType getAccountSynchronizationSettings() { return accountSynchronizationSettings; } - public void setAccountSynchronizationSettings( - ProjectionPolicyType accountSynchronizationSettings) { + public void setAccountSynchronizationSettings(ProjectionPolicyType accountSynchronizationSettings) { this.accountSynchronizationSettings = accountSynchronizationSettings; } - + public ValuePolicyType getGlobalPasswordPolicy() { return globalPasswordPolicy; } - + public void setGlobalPasswordPolicy(ValuePolicyType globalPasswordPolicy) { this.globalPasswordPolicy = globalPasswordPolicy; } - + public int getProjectionWave() { return projectionWave; } @@ -327,15 +334,15 @@ public int getProjectionWave() { public void setProjectionWave(int wave) { this.projectionWave = wave; } - + public void incrementProjectionWave() { projectionWave++; } - + public void resetProjectionWave() { projectionWave = executionWave; } - + public int getExecutionWave() { return executionWave; } @@ -350,14 +357,14 @@ public void incrementExecutionWave() { public int getMaxWave() { int maxWave = 0; - for (LensProjectionContext projContext: projectionContexts) { + for (LensProjectionContext projContext : projectionContexts) { if (projContext.getWave() > maxWave) { maxWave = projContext.getWave(); } } return maxWave; } - + public boolean isFresh() { return isFresh; } @@ -365,7 +372,7 @@ public boolean isFresh() { public void setFresh(boolean isFresh) { this.isFresh = isFresh; } - + public boolean isRequestAuthorized() { return isRequestAuthorized; } @@ -382,45 +389,48 @@ public void rot() { if (focusContext != null) { focusContext.setFresh(false); } - for (LensProjectionContext projectionContext: projectionContexts) { + for (LensProjectionContext projectionContext : projectionContexts) { projectionContext.setFresh(false); projectionContext.setFullShadow(false); } } - -// /** -// * Make the context as clean as new. Except for the executed deltas and other "traces" of -// * what was already done and cannot be undone. Also the configuration items that were loaded may remain. -// * This is used to restart the context computation but keep the trace of what was already done. -// */ -// public void reset() { -// state = ModelState.INITIAL; -// evaluatedAssignmentTriple = null; -// projectionWave = 0; -// executionWave = 0; -// isFresh = false; -// if (focusContext != null) { -// focusContext.reset(); -// } -// if (projectionContexts != null) { -// for (LensProjectionContext projectionContext: projectionContexts) { -// projectionContext.reset(); -// } -// } -// } + + // /** + // * Make the context as clean as new. Except for the executed deltas and + // other "traces" of + // * what was already done and cannot be undone. Also the configuration + // items that were loaded may remain. + // * This is used to restart the context computation but keep the trace of + // what was already done. + // */ + // public void reset() { + // state = ModelState.INITIAL; + // evaluatedAssignmentTriple = null; + // projectionWave = 0; + // executionWave = 0; + // isFresh = false; + // if (focusContext != null) { + // focusContext.reset(); + // } + // if (projectionContexts != null) { + // for (LensProjectionContext projectionContext: projectionContexts) { + // projectionContext.reset(); + // } + // } + // } public String getChannel() { - return channel; - } + return channel; + } - public void setChannel(String channelUri) { - this.channel = channelUri; - } - - public void setChannel(QName channelQName) { - this.channel = QNameUtil.qNameToUri(channelQName); - } + public void setChannel(String channelUri) { + this.channel = channelUri; + } + public void setChannel(QName channelQName) { + this.channel = QNameUtil.qNameToUri(channelQName); + } + public boolean isDoReconciliationForAllProjections() { return doReconciliationForAllProjections; } @@ -429,22 +439,27 @@ public void setDoReconciliationForAllProjections(boolean doReconciliationForAllP this.doReconciliationForAllProjections = doReconciliationForAllProjections; } + public boolean isReconcileFocus() { + return doReconciliationForAllProjections || ModelExecuteOptions.isReconcileFocus(options); + } + public DeltaSetTriple getEvaluatedAssignmentTriple() { return evaluatedAssignmentTriple; } - public void setEvaluatedAssignmentTriple(DeltaSetTriple evaluatedAssignmentTriple) { + public void setEvaluatedAssignmentTriple( + DeltaSetTriple evaluatedAssignmentTriple) { this.evaluatedAssignmentTriple = evaluatedAssignmentTriple; } - + public ModelExecuteOptions getOptions() { return options; } - + public void setOptions(ModelExecuteOptions options) { this.options = options; } - + public PartialProcessingOptionsType getPartialProcessingOptions() { if (options == null || options.getPartialProcessing() == null) { return new PartialProcessingOptionsType(); @@ -488,7 +503,7 @@ public boolean isRequestAudited() { public void setRequestAudited(boolean requestAudited) { this.requestAudited = requestAudited; } - + public boolean isExecutionAudited() { return executionAudited; } @@ -513,22 +528,22 @@ public OperationBusinessContextType getRequestBusinessContext() { } /** - * Returns all changes, user and all accounts. Both primary and secondary changes are returned, but - * these are not merged. - * TODO: maybe it would be better to merge them. - */ - public Collection> getAllChanges() throws SchemaException { - Collection> allChanges = new ArrayList>(); - if (focusContext != null) { - addChangeIfNotNull(allChanges, focusContext.getPrimaryDelta()); - addChangeIfNotNull(allChanges, focusContext.getSecondaryDelta()); - } - for (LensProjectionContext projCtx: getProjectionContexts()) { - addChangeIfNotNull(allChanges, projCtx.getPrimaryDelta()); - addChangeIfNotNull(allChanges, projCtx.getSecondaryDelta()); - } - return allChanges; - } + * Returns all changes, user and all accounts. Both primary and secondary + * changes are returned, but these are not merged. TODO: maybe it would be + * better to merge them. + */ + public Collection> getAllChanges() throws SchemaException { + Collection> allChanges = new ArrayList>(); + if (focusContext != null) { + addChangeIfNotNull(allChanges, focusContext.getPrimaryDelta()); + addChangeIfNotNull(allChanges, focusContext.getSecondaryDelta()); + } + for (LensProjectionContext projCtx : getProjectionContexts()) { + addChangeIfNotNull(allChanges, projCtx.getPrimaryDelta()); + addChangeIfNotNull(allChanges, projCtx.getSecondaryDelta()); + } + return allChanges; + } public boolean hasAnyPrimaryChange() throws SchemaException { if (focusContext != null) { @@ -536,129 +551,134 @@ public boolean hasAnyPrimaryChange() throws SchemaException { return true; } } - for (LensProjectionContext projCtx: getProjectionContexts()) { + for (LensProjectionContext projCtx : getProjectionContexts()) { if (!ObjectDelta.isNullOrEmpty(projCtx.getPrimaryDelta())) { return true; } } return false; } - - public Collection> getPrimaryChanges() throws SchemaException { - Collection> allChanges = new ArrayList>(); - if (focusContext != null) { - addChangeIfNotNull(allChanges, focusContext.getPrimaryDelta()); - } - for (LensProjectionContext projCtx: getProjectionContexts()) { - addChangeIfNotNull(allChanges, projCtx.getPrimaryDelta()); - } - return allChanges; - } - - private void addChangeIfNotNull(Collection> changes, - ObjectDelta change) { - if (change != null) { - changes.add(change); - } - } - - public void replacePrimaryFocusDelta(ObjectDelta newDelta) { - focusContext.setPrimaryDelta(newDelta); - // todo any other changes have to be done? - } - - public void replacePrimaryFocusDeltas(List> deltas) throws SchemaException { - replacePrimaryFocusDelta(null); - if (deltas != null) { - for (ObjectDelta delta : deltas) { - focusContext.addPrimaryDelta(delta); - } - } - // todo any other changes have to be done? - } - - - /** - * Returns all executed deltas, user and all accounts. - */ - public Collection> getExecutedDeltas() throws SchemaException { - return getExecutedDeltas(null); - } + + public Collection> getPrimaryChanges() throws SchemaException { + Collection> allChanges = new ArrayList>(); + if (focusContext != null) { + addChangeIfNotNull(allChanges, focusContext.getPrimaryDelta()); + } + for (LensProjectionContext projCtx : getProjectionContexts()) { + addChangeIfNotNull(allChanges, projCtx.getPrimaryDelta()); + } + return allChanges; + } + + private void addChangeIfNotNull( + Collection> changes, ObjectDelta change) { + if (change != null) { + changes.add(change); + } + } + + public void replacePrimaryFocusDelta(ObjectDelta newDelta) { + focusContext.setPrimaryDelta(newDelta); + // todo any other changes have to be done? + } + + public void replacePrimaryFocusDeltas(List> deltas) throws SchemaException { + replacePrimaryFocusDelta(null); + if (deltas != null) { + for (ObjectDelta delta : deltas) { + focusContext.addPrimaryDelta(delta); + } + } + // todo any other changes have to be done? + } + + /** + * Returns all executed deltas, user and all accounts. + */ + public Collection> getExecutedDeltas() throws SchemaException { + return getExecutedDeltas(null); + } + + /** + * Returns all executed deltas, user and all accounts. + */ + public Collection> getUnauditedExecutedDeltas() + throws SchemaException { + return getExecutedDeltas(false); + } /** - * Returns all executed deltas, user and all accounts. - */ - public Collection> getUnauditedExecutedDeltas() throws SchemaException { - return getExecutedDeltas(false); - } - - /** - * Returns all executed deltas, user and all accounts. - */ - Collection> getExecutedDeltas(Boolean audited) throws SchemaException { - Collection> executedDeltas = new ArrayList>(); - if (focusContext != null) { - executedDeltas.addAll(focusContext.getExecutedDeltas(audited)); - } - for (LensProjectionContext projCtx: getProjectionContexts()) { - executedDeltas.addAll(projCtx.getExecutedDeltas(audited)); - } - if (audited == null) { - executedDeltas.addAll(getRottenExecutedDeltas()); - } - return executedDeltas; - } - - public void markExecutedDeltasAudited() { - if (focusContext != null) { - focusContext.markExecutedDeltasAudited(); - } - for (LensProjectionContext projCtx: getProjectionContexts()) { - projCtx.markExecutedDeltasAudited(); - } - } - + * Returns all executed deltas, user and all accounts. + */ + Collection> getExecutedDeltas(Boolean audited) + throws SchemaException { + Collection> executedDeltas = new ArrayList>(); + if (focusContext != null) { + executedDeltas.addAll(focusContext.getExecutedDeltas(audited)); + } + for (LensProjectionContext projCtx : getProjectionContexts()) { + executedDeltas.addAll(projCtx.getExecutedDeltas(audited)); + } + if (audited == null) { + executedDeltas.addAll(getRottenExecutedDeltas()); + } + return executedDeltas; + } + + public void markExecutedDeltasAudited() { + if (focusContext != null) { + focusContext.markExecutedDeltasAudited(); + } + for (LensProjectionContext projCtx : getProjectionContexts()) { + projCtx.markExecutedDeltasAudited(); + } + } + public List> getRottenExecutedDeltas() { return rottenExecutedDeltas; } - + public void recompute() throws SchemaException { recomputeFocus(); recomputeProjections(); } - // mainly computes new state based on old state and delta(s) + // mainly computes new state based on old state and delta(s) public void recomputeFocus() throws SchemaException { if (focusContext != null) { focusContext.recompute(); } } - + public void recomputeProjections() throws SchemaException { - for (LensProjectionContext projCtx: getProjectionContexts()) { + for (LensProjectionContext projCtx : getProjectionContexts()) { projCtx.recompute(); } } - + public void refreshAuxiliaryObjectClassDefinitions() throws SchemaException { - for (LensProjectionContext projCtx: getProjectionContexts()) { + for (LensProjectionContext projCtx : getProjectionContexts()) { projCtx.refreshAuxiliaryObjectClassDefinitions(); - } + } } - public void checkAbortRequested() { - if (isAbortRequested()) { - throw new RuntimeException("Aborted on user request"); // TODO more meaningful exception + message - } - } + public void checkAbortRequested() { + if (isAbortRequested()) { + throw new RuntimeException("Aborted on user request"); // TODO more + // meaningful + // exception + // + message + } + } public void checkConsistence() { - checkAbortRequested(); + checkAbortRequested(); if (focusContext != null) { focusContext.checkConsistence(); } - for (LensProjectionContext projectionContext: projectionContexts) { - projectionContext.checkConsistence(this.toString(), isFresh, ModelExecuteOptions.isForce(options)); + for (LensProjectionContext projectionContext : projectionContexts) { + projectionContext.checkConsistence(this.toString(), isFresh, + ModelExecuteOptions.isForce(options)); } } @@ -666,23 +686,23 @@ public void checkEncrypted() { if (focusContext != null && !focusContext.isDelete()) { focusContext.checkEncrypted(); } - for (LensProjectionContext projectionContext: projectionContexts) { + for (LensProjectionContext projectionContext : projectionContexts) { if (!projectionContext.isDelete()) { projectionContext.checkEncrypted(); } } } - + public LensProjectionContext createProjectionContext() { return createProjectionContext(null); } - + public LensProjectionContext createProjectionContext(ResourceShadowDiscriminator rat) { LensProjectionContext projCtx = new LensProjectionContext(this, rat); addProjectionContext(projCtx); return projCtx; } - + private Map getResourceCache() { if (resourceCache == null) { resourceCache = new HashMap(); @@ -691,186 +711,190 @@ private Map getResourceCache() { } /** - * Returns a resource for specified account type. - * This is supposed to be efficient, taking the resource from the cache. It assumes the resource is in the cache. - * - * @see SyncContext#rememberResource(ResourceType) - */ - public ResourceType getResource(ResourceShadowDiscriminator rat) { - return getResource(rat.getResourceOid()); - } - - /** - * Returns a resource for specified account type. - * This is supposed to be efficient, taking the resource from the cache. It assumes the resource is in the cache. - * - * @see SyncContext#rememberResource(ResourceType) - */ - public ResourceType getResource(String resourceOid) { - return getResourceCache().get(resourceOid); - } - + * Returns a resource for specified account type. This is supposed to be + * efficient, taking the resource from the cache. It assumes the resource is + * in the cache. + * + * @see SyncContext#rememberResource(ResourceType) + */ + public ResourceType getResource(ResourceShadowDiscriminator rat) { + return getResource(rat.getResourceOid()); + } + /** - * Puts resources in the cache for later use. The resources should be fetched from provisioning - * and have pre-parsed schemas. So the next time just reuse them without the other overhead. - */ - public void rememberResources(Collection resources) { - for (ResourceType resourceType : resources) { - rememberResource(resourceType); - } - } - - /** - * Puts resource in the cache for later use. The resource should be fetched from provisioning - * and have pre-parsed schemas. So the next time just reuse it without the other overhead. - */ - public void rememberResource(ResourceType resourceType) { - getResourceCache().put(resourceType.getOid(), resourceType); - } - + * Returns a resource for specified account type. This is supposed to be + * efficient, taking the resource from the cache. It assumes the resource is + * in the cache. + * + * @see SyncContext#rememberResource(ResourceType) + */ + public ResourceType getResource(String resourceOid) { + return getResourceCache().get(resourceOid); + } + + /** + * Puts resources in the cache for later use. The resources should be + * fetched from provisioning and have pre-parsed schemas. So the next time + * just reuse them without the other overhead. + */ + public void rememberResources(Collection resources) { + for (ResourceType resourceType : resources) { + rememberResource(resourceType); + } + } + + /** + * Puts resource in the cache for later use. The resource should be fetched + * from provisioning and have pre-parsed schemas. So the next time just + * reuse it without the other overhead. + */ + public void rememberResource(ResourceType resourceType) { + getResourceCache().put(resourceType.getOid(), resourceType); + } + /** - * Cleans up the contexts by removing some of the working state. - * The current wave number is retained. Otherwise it ends up in endless loop. + * Cleans up the contexts by removing some of the working state. The current + * wave number is retained. Otherwise it ends up in endless loop. */ public void cleanup() throws SchemaException { if (focusContext != null) { focusContext.cleanup(); } - for (LensProjectionContext projectionContext: projectionContexts) { + for (LensProjectionContext projectionContext : projectionContexts) { projectionContext.cleanup(); } recompute(); } - - public void adopt(PrismContext prismContext) throws SchemaException { - this.prismContext = prismContext; - - if (focusContext != null) { - focusContext.adopt(prismContext); - } - for (LensProjectionContext projectionContext: projectionContexts) { - projectionContext.adopt(prismContext); - } - } - - public void normalize() { - if (focusContext != null) { - focusContext.normalize(); - } - if (projectionContexts != null) { - for (LensProjectionContext projectionContext: projectionContexts) { - projectionContext.normalize(); - } - } - } - - public LensContext clone() { - LensContext clone = new LensContext(focusClass, prismContext, provisioningService); - copyValues(clone); - return clone; - } - - protected void copyValues(LensContext clone) { - clone.state = this.state; - clone.channel = this.channel; - clone.doReconciliationForAllProjections = this.doReconciliationForAllProjections; - clone.focusClass = this.focusClass; - clone.isFresh = this.isFresh; - clone.prismContext = this.prismContext; - clone.resourceCache = cloneResourceCache(); - // User template is de-facto immutable, OK to just pass reference here. - clone.focusTemplate = this.focusTemplate; - clone.projectionWave = this.projectionWave; - if (options != null) { - clone.options = this.options.clone(); - } - - if (this.focusContext != null) { - clone.focusContext = this.focusContext.clone(this); - } - - for (LensProjectionContext thisProjectionContext: this.projectionContexts) { - clone.projectionContexts.add(thisProjectionContext.clone(this)); - } - } + + public void adopt(PrismContext prismContext) throws SchemaException { + this.prismContext = prismContext; + + if (focusContext != null) { + focusContext.adopt(prismContext); + } + for (LensProjectionContext projectionContext : projectionContexts) { + projectionContext.adopt(prismContext); + } + } + + public void normalize() { + if (focusContext != null) { + focusContext.normalize(); + } + if (projectionContexts != null) { + for (LensProjectionContext projectionContext : projectionContexts) { + projectionContext.normalize(); + } + } + } + + public LensContext clone() { + LensContext clone = new LensContext(focusClass, prismContext, provisioningService); + copyValues(clone); + return clone; + } + + protected void copyValues(LensContext clone) { + clone.state = this.state; + clone.channel = this.channel; + clone.doReconciliationForAllProjections = this.doReconciliationForAllProjections; + clone.focusClass = this.focusClass; + clone.isFresh = this.isFresh; + clone.prismContext = this.prismContext; + clone.resourceCache = cloneResourceCache(); + // User template is de-facto immutable, OK to just pass reference here. + clone.focusTemplate = this.focusTemplate; + clone.projectionWave = this.projectionWave; + if (options != null) { + clone.options = this.options.clone(); + } + + if (this.focusContext != null) { + clone.focusContext = this.focusContext.clone(this); + } + + for (LensProjectionContext thisProjectionContext : this.projectionContexts) { + clone.projectionContexts.add(thisProjectionContext.clone(this)); + } + } private Map cloneResourceCache() { if (resourceCache == null) { return null; } Map clonedMap = new HashMap(); - for (Entry entry: resourceCache.entrySet()) { + for (Entry entry : resourceCache.entrySet()) { clonedMap.put(entry.getKey(), entry.getValue()); } return clonedMap; } - + public void distributeResource() { - for (LensProjectionContext projCtx: getProjectionContexts()) { + for (LensProjectionContext projCtx : getProjectionContexts()) { projCtx.distributeResource(); } } - @Override - public Class getFocusClass() { - return focusClass; - } - - @Override - public String debugDump() { - return debugDump(0); - } - - public String dump(boolean showTriples) { - return debugDump(0, showTriples); - } - - @Override - public String debugDump(int indent) { - return debugDump(indent, true); - } - - public String debugDump(int indent, boolean showTriples) { - StringBuilder sb = new StringBuilder(); - DebugUtil.indentDebugDump(sb, indent); - sb.append("LensContext: state=").append(state); - sb.append(", Wave(e=").append(executionWave); - sb.append(",p=").append(projectionWave); - sb.append(",max=").append(getMaxWave()); - sb.append("), "); - if (focusContext != null) { - sb.append("focus, "); - } - sb.append(projectionContexts.size()); - sb.append(" projections, "); - try { + @Override + public Class getFocusClass() { + return focusClass; + } + + @Override + public String debugDump() { + return debugDump(0); + } + + public String dump(boolean showTriples) { + return debugDump(0, showTriples); + } + + @Override + public String debugDump(int indent) { + return debugDump(indent, true); + } + + public String debugDump(int indent, boolean showTriples) { + StringBuilder sb = new StringBuilder(); + DebugUtil.indentDebugDump(sb, indent); + sb.append("LensContext: state=").append(state); + sb.append(", Wave(e=").append(executionWave); + sb.append(",p=").append(projectionWave); + sb.append(",max=").append(getMaxWave()); + sb.append("), "); + if (focusContext != null) { + sb.append("focus, "); + } + sb.append(projectionContexts.size()); + sb.append(" projections, "); + try { Collection> allChanges = getAllChanges(); sb.append(allChanges.size()); } catch (SchemaException e) { sb.append("[ERROR]"); } - sb.append(" changes, "); - sb.append("fresh=").append(isFresh); - if (systemConfiguration == null) { - sb.append(" null-system-configuration"); - } - sb.append("\n"); - - DebugUtil.debugDumpLabel(sb, "Channel", indent + 1); - sb.append(" ").append(channel).append("\n"); - DebugUtil.debugDumpLabel(sb, "Options", indent + 1); - sb.append(" ").append(options).append("\n"); - DebugUtil.debugDumpLabel(sb, "Settings", indent + 1); - sb.append(" "); - if (accountSynchronizationSettings != null) { - sb.append("assignments="); - sb.append(accountSynchronizationSettings.getAssignmentPolicyEnforcement()); - } else { - sb.append("null"); - } - sb.append("\n"); - - DebugUtil.debugDumpWithLabel(sb, "FOCUS", focusContext, indent + 1); + sb.append(" changes, "); + sb.append("fresh=").append(isFresh); + if (systemConfiguration == null) { + sb.append(" null-system-configuration"); + } + sb.append("\n"); + + DebugUtil.debugDumpLabel(sb, "Channel", indent + 1); + sb.append(" ").append(channel).append("\n"); + DebugUtil.debugDumpLabel(sb, "Options", indent + 1); + sb.append(" ").append(options).append("\n"); + DebugUtil.debugDumpLabel(sb, "Settings", indent + 1); + sb.append(" "); + if (accountSynchronizationSettings != null) { + sb.append("assignments="); + sb.append(accountSynchronizationSettings.getAssignmentPolicyEnforcement()); + } else { + sb.append("null"); + } + sb.append("\n"); + + DebugUtil.debugDumpWithLabel(sb, "FOCUS", focusContext, indent + 1); sb.append("\n"); if (DebugUtil.isDetailedDebugDump()) { @@ -879,34 +903,39 @@ public String debugDump(int indent, boolean showTriples) { DebugUtil.indentDebugDump(sb, indent + 3); sb.append("Evaluated assignments:"); if (evaluatedAssignmentTriple != null) { - dumpEvaluatedAssignments(sb, "Zero", (Collection) evaluatedAssignmentTriple.getZeroSet(), indent + 4); - dumpEvaluatedAssignments(sb, "Plus", (Collection) evaluatedAssignmentTriple.getPlusSet(), indent + 4); - dumpEvaluatedAssignments(sb, "Minus", (Collection) evaluatedAssignmentTriple.getMinusSet(), indent + 4); + dumpEvaluatedAssignments(sb, "Zero", (Collection) evaluatedAssignmentTriple.getZeroSet(), + indent + 4); + dumpEvaluatedAssignments(sb, "Plus", (Collection) evaluatedAssignmentTriple.getPlusSet(), + indent + 4); + dumpEvaluatedAssignments(sb, "Minus", (Collection) evaluatedAssignmentTriple.getMinusSet(), + indent + 4); } else { sb.append(" (null)"); } } sb.append("\n"); - DebugUtil.indentDebugDump(sb, indent + 1); - sb.append("PROJECTIONS:"); - if (projectionContexts.isEmpty()) { - sb.append(" none"); - } else { - sb.append(" (").append(projectionContexts.size()).append("):"); - for (LensProjectionContext projCtx : projectionContexts) { + DebugUtil.indentDebugDump(sb, indent + 1); + sb.append("PROJECTIONS:"); + if (projectionContexts.isEmpty()) { + sb.append(" none"); + } else { + sb.append(" (").append(projectionContexts.size()).append("):"); + for (LensProjectionContext projCtx : projectionContexts) { sb.append("\n"); - sb.append(projCtx.debugDump(indent + 2, showTriples)); - } - } + sb.append(projCtx.debugDump(indent + 2, showTriples)); + } + } if (historicResourceObjects != null && !historicResourceObjects.isEmpty()) { sb.append("\n"); - DebugUtil.debugDumpWithLabel(sb, "Deleted/unlinked resource objects", historicResourceObjects.toString(), indent + 1); // temporary impl + DebugUtil.debugDumpWithLabel(sb, "Deleted/unlinked resource objects", + historicResourceObjects.toString(), indent + 1); // temporary + // impl } - return sb.toString(); - } + return sb.toString(); + } - @Override + @Override public String dumpPolicyRules(int indent) { if (evaluatedAssignmentTriple == null) { return ""; @@ -915,31 +944,33 @@ public String dumpPolicyRules(int indent) { evaluatedAssignmentTriple.debugDumpSets(sb, assignment -> { DebugUtil.indentDebugDump(sb, indent); sb.append(assignment.toHumanReadableString()); - @SuppressWarnings({"unchecked", "raw"}) + @SuppressWarnings({ "unchecked", "raw" }) Collection targetPolicyRules = assignment.getTargetPolicyRules(); @SuppressWarnings("unchecked") Collection thisTargetPolicyRules = assignment.getThisTargetPolicyRules(); - for (EvaluatedPolicyRule rule: targetPolicyRules) { + for (EvaluatedPolicyRule rule : targetPolicyRules) { sb.append("\n"); - DebugUtil.indentDebugDump(sb, indent+1); + DebugUtil.indentDebugDump(sb, indent + 1); if (thisTargetPolicyRules.stream().anyMatch(d -> d == rule)) { sb.append("local "); } sb.append("rule: ").append(rule.getName()); - for (EvaluatedPolicyRuleTrigger trigger: rule.getTriggers()) { + for (EvaluatedPolicyRuleTrigger trigger : rule.getTriggers()) { sb.append("\n"); - DebugUtil.indentDebugDump(sb, indent+2); + DebugUtil.indentDebugDump(sb, indent + 2); sb.append("trigger: ").append(trigger); if (trigger instanceof EvaluatedExclusionTrigger && ((EvaluatedExclusionTrigger) trigger).getConflictingAssignment() != null) { sb.append("\n"); - DebugUtil.indentDebugDump(sb, indent+3); - sb.append("conflict: ").append(((EvaluatedAssignmentImpl)((EvaluatedExclusionTrigger) trigger).getConflictingAssignment()).toHumanReadableString()); + DebugUtil.indentDebugDump(sb, indent + 3); + sb.append("conflict: ") + .append(((EvaluatedAssignmentImpl) ((EvaluatedExclusionTrigger) trigger) + .getConflictingAssignment()).toHumanReadableString()); } } - for (PolicyExceptionType exc: rule.getPolicyExceptions()) { + for (PolicyExceptionType exc : rule.getPolicyExceptions()) { sb.append("\n"); - DebugUtil.indentDebugDump(sb, indent+2); + DebugUtil.indentDebugDump(sb, indent + 2); sb.append("exception: ").append(exc); } } @@ -947,7 +978,8 @@ public String dumpPolicyRules(int indent) { return sb.toString(); } - private void dumpEvaluatedAssignments(StringBuilder sb, String label, Collection> set, int indent) { + private void dumpEvaluatedAssignments(StringBuilder sb, String label, + Collection> set, int indent) { sb.append("\n"); DebugUtil.debugDumpLabel(sb, label, indent); for (EvaluatedAssignmentImpl assignment : set) { @@ -955,12 +987,13 @@ private void dumpEvaluatedAssignments(StringBuilder sb, St DebugUtil.indentDebugDump(sb, indent + 1); sb.append(" -> " + assignment.getTarget()); dumpRules(sb, "focus rules", assignment.getFocusPolicyRules(), null); - dumpRules(sb, "target rules", assignment.getTargetPolicyRules(), assignment.getThisTargetPolicyRules()); + dumpRules(sb, "target rules", assignment.getTargetPolicyRules(), + assignment.getThisTargetPolicyRules()); } } - private void dumpRules(StringBuilder sb, String label, Collection policyRules, - Collection directPolicyRules) { + private void dumpRules(StringBuilder sb, String label, + Collection policyRules, Collection directPolicyRules) { sb.append(" [").append(label).append("(").append(policyRules.size()).append("): "); boolean first = true; for (EvaluatedPolicyRule rule : policyRules) { @@ -969,16 +1002,15 @@ private void dumpRules(StringBuilder sb, String label, Col } else { sb.append("; "); } - if (directPolicyRules != null && directPolicyRules.stream().anyMatch(d -> d==rule)) { - sb.append("L"); // L for Local + if (directPolicyRules != null && directPolicyRules.stream().anyMatch(d -> d == rule)) { + sb.append("L"); // L for Local } sb.append("(").append(PolicyRuleTypeUtil.toShortString(rule.getPolicyConstraints())).append(")"); sb.append("->"); sb.append("(").append(PolicyRuleTypeUtil.toShortString(rule.getActions())).append(")"); if (!rule.getTriggers().isEmpty()) { sb.append("=>T:("); - sb.append(rule.getTriggers().stream() - .map(EvaluatedPolicyRuleTrigger::toDiagShortcut) + sb.append(rule.getTriggers().stream().map(EvaluatedPolicyRuleTrigger::toDiagShortcut) .collect(Collectors.joining(", "))); sb.append(")"); } @@ -991,147 +1023,161 @@ public LensContextType toLensContextType() throws SchemaException { return pc.getValue().asContainerable(); } - public PrismContainer toPrismContainer() throws SchemaException { - - PrismContainer lensContextTypeContainer = PrismContainer.newInstance(getPrismContext(), LensContextType.COMPLEX_TYPE); - LensContextType lensContextType = lensContextTypeContainer.createNewValue().asContainerable(); - - lensContextType.setState(state != null ? state.toModelStateType() : null); - lensContextType.setChannel(channel); - - if (focusContext != null) { - PrismContainer lensFocusContextTypeContainer = lensContextTypeContainer.findOrCreateContainer(LensContextType.F_FOCUS_CONTEXT); - focusContext.addToPrismContainer(lensFocusContextTypeContainer); - } - - PrismContainer lensProjectionContextTypeContainer = lensContextTypeContainer.findOrCreateContainer(LensContextType.F_PROJECTION_CONTEXT); - for (LensProjectionContext lensProjectionContext : projectionContexts) { - lensProjectionContext.addToPrismContainer(lensProjectionContextTypeContainer); - } - lensContextType.setFocusClass(focusClass != null ? focusClass.getName() : null); - lensContextType.setDoReconciliationForAllProjections(doReconciliationForAllProjections); - lensContextType.setProjectionWave(projectionWave); - lensContextType.setExecutionWave(executionWave); - lensContextType.setOptions(options != null ? options.toModelExecutionOptionsType() : null); - lensContextType.setLazyAuditRequest(lazyAuditRequest); - lensContextType.setRequestAudited(requestAudited); - lensContextType.setExecutionAudited(executionAudited); - lensContextType.setStats(stats); - lensContextType.setRequestMetadata(requestMetadata); - - for (LensObjectDeltaOperation executedDelta : rottenExecutedDeltas) { - lensContextType.getRottenExecutedDeltas().add(executedDelta.toLensObjectDeltaOperationType()); - } - - return lensContextTypeContainer; - } - - - public static LensContext fromLensContextType(LensContextType lensContextType, PrismContext prismContext, ProvisioningService provisioningService, OperationResult parentResult) throws SchemaException, ConfigurationException, ObjectNotFoundException, CommunicationException { - - OperationResult result = parentResult.createSubresult(DOT_CLASS + "fromLensContextType"); - - String focusClassString = lensContextType.getFocusClass(); - - if (StringUtils.isEmpty(focusClassString)) { - throw new SystemException("Focus class is undefined in LensContextType"); - } - - LensContext lensContext; - try { - lensContext = new LensContext(Class.forName(focusClassString), prismContext, provisioningService); - } catch (ClassNotFoundException e) { - throw new SystemException("Couldn't instantiate LensContext because focus or projection class couldn't be found", e); - } - - lensContext.setState(ModelState.fromModelStateType(lensContextType.getState())); - lensContext.setChannel(lensContextType.getChannel()); - lensContext.setFocusContext(LensFocusContext.fromLensFocusContextType(lensContextType.getFocusContext(), lensContext, result)); - for (LensProjectionContextType lensProjectionContextType : lensContextType.getProjectionContext()) { - lensContext.addProjectionContext(LensProjectionContext.fromLensProjectionContextType(lensProjectionContextType, lensContext, result)); - } - lensContext.setDoReconciliationForAllProjections(lensContextType.isDoReconciliationForAllProjections() != null ? - lensContextType.isDoReconciliationForAllProjections() : false); - lensContext.setProjectionWave(lensContextType.getProjectionWave() != null ? - lensContextType.getProjectionWave() : 0); - lensContext.setExecutionWave(lensContextType.getExecutionWave() != null ? - lensContextType.getExecutionWave() : 0); - lensContext.setOptions(ModelExecuteOptions.fromModelExecutionOptionsType(lensContextType.getOptions())); - if (lensContextType.isLazyAuditRequest() != null) { - lensContext.setLazyAuditRequest(lensContextType.isLazyAuditRequest()); - } - if (lensContextType.isRequestAudited() != null) { - lensContext.setRequestAudited(lensContextType.isRequestAudited()); - } - if (lensContextType.isExecutionAudited() != null) { - lensContext.setExecutionAudited(lensContextType.isExecutionAudited()); - } - lensContext.setStats(lensContextType.getStats()); - lensContext.setRequestMetadata(lensContextType.getRequestMetadata()); - - for (LensObjectDeltaOperationType eDeltaOperationType : lensContextType.getRottenExecutedDeltas()) { - LensObjectDeltaOperation objectDeltaOperation = LensObjectDeltaOperation.fromLensObjectDeltaOperationType(eDeltaOperationType, lensContext.getPrismContext()); - if (objectDeltaOperation.getObjectDelta() != null) { - lensContext.fixProvisioningTypeInDelta(objectDeltaOperation.getObjectDelta(), result); - } - lensContext.rottenExecutedDeltas.add(objectDeltaOperation); - } - - if (result.isUnknown()) { - result.computeStatus(); - } - return lensContext; - } - - protected void fixProvisioningTypeInDelta(ObjectDelta delta, OperationResult result) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException { - if (delta != null && delta.getObjectTypeClass() != null && (ShadowType.class.isAssignableFrom(delta.getObjectTypeClass()) || ResourceType.class.isAssignableFrom(delta.getObjectTypeClass()))) { - getProvisioningService().applyDefinition(delta, result); - } - } + public PrismContainer toPrismContainer() throws SchemaException { + + PrismContainer lensContextTypeContainer = PrismContainer + .newInstance(getPrismContext(), LensContextType.COMPLEX_TYPE); + LensContextType lensContextType = lensContextTypeContainer.createNewValue().asContainerable(); + + lensContextType.setState(state != null ? state.toModelStateType() : null); + lensContextType.setChannel(channel); + + if (focusContext != null) { + PrismContainer lensFocusContextTypeContainer = lensContextTypeContainer + .findOrCreateContainer(LensContextType.F_FOCUS_CONTEXT); + focusContext.addToPrismContainer(lensFocusContextTypeContainer); + } + + PrismContainer lensProjectionContextTypeContainer = lensContextTypeContainer + .findOrCreateContainer(LensContextType.F_PROJECTION_CONTEXT); + for (LensProjectionContext lensProjectionContext : projectionContexts) { + lensProjectionContext.addToPrismContainer(lensProjectionContextTypeContainer); + } + lensContextType.setFocusClass(focusClass != null ? focusClass.getName() : null); + lensContextType.setDoReconciliationForAllProjections(doReconciliationForAllProjections); + lensContextType.setProjectionWave(projectionWave); + lensContextType.setExecutionWave(executionWave); + lensContextType.setOptions(options != null ? options.toModelExecutionOptionsType() : null); + lensContextType.setLazyAuditRequest(lazyAuditRequest); + lensContextType.setRequestAudited(requestAudited); + lensContextType.setExecutionAudited(executionAudited); + lensContextType.setStats(stats); + lensContextType.setRequestMetadata(requestMetadata); + + for (LensObjectDeltaOperation executedDelta : rottenExecutedDeltas) { + lensContextType.getRottenExecutedDeltas().add(executedDelta.toLensObjectDeltaOperationType()); + } + + return lensContextTypeContainer; + } + + public static LensContext fromLensContextType(LensContextType lensContextType, PrismContext prismContext, + ProvisioningService provisioningService, OperationResult parentResult) + throws SchemaException, ConfigurationException, ObjectNotFoundException, CommunicationException { + + OperationResult result = parentResult.createSubresult(DOT_CLASS + "fromLensContextType"); + + String focusClassString = lensContextType.getFocusClass(); + + if (StringUtils.isEmpty(focusClassString)) { + throw new SystemException("Focus class is undefined in LensContextType"); + } + + LensContext lensContext; + try { + lensContext = new LensContext(Class.forName(focusClassString), prismContext, provisioningService); + } catch (ClassNotFoundException e) { + throw new SystemException( + "Couldn't instantiate LensContext because focus or projection class couldn't be found", + e); + } + + lensContext.setState(ModelState.fromModelStateType(lensContextType.getState())); + lensContext.setChannel(lensContextType.getChannel()); + lensContext.setFocusContext(LensFocusContext + .fromLensFocusContextType(lensContextType.getFocusContext(), lensContext, result)); + for (LensProjectionContextType lensProjectionContextType : lensContextType.getProjectionContext()) { + lensContext.addProjectionContext(LensProjectionContext + .fromLensProjectionContextType(lensProjectionContextType, lensContext, result)); + } + lensContext.setDoReconciliationForAllProjections( + lensContextType.isDoReconciliationForAllProjections() != null + ? lensContextType.isDoReconciliationForAllProjections() : false); + lensContext.setProjectionWave( + lensContextType.getProjectionWave() != null ? lensContextType.getProjectionWave() : 0); + lensContext.setExecutionWave( + lensContextType.getExecutionWave() != null ? lensContextType.getExecutionWave() : 0); + lensContext + .setOptions(ModelExecuteOptions.fromModelExecutionOptionsType(lensContextType.getOptions())); + if (lensContextType.isLazyAuditRequest() != null) { + lensContext.setLazyAuditRequest(lensContextType.isLazyAuditRequest()); + } + if (lensContextType.isRequestAudited() != null) { + lensContext.setRequestAudited(lensContextType.isRequestAudited()); + } + if (lensContextType.isExecutionAudited() != null) { + lensContext.setExecutionAudited(lensContextType.isExecutionAudited()); + } + lensContext.setStats(lensContextType.getStats()); + lensContext.setRequestMetadata(lensContextType.getRequestMetadata()); + + for (LensObjectDeltaOperationType eDeltaOperationType : lensContextType.getRottenExecutedDeltas()) { + LensObjectDeltaOperation objectDeltaOperation = LensObjectDeltaOperation + .fromLensObjectDeltaOperationType(eDeltaOperationType, lensContext.getPrismContext()); + if (objectDeltaOperation.getObjectDelta() != null) { + lensContext.fixProvisioningTypeInDelta(objectDeltaOperation.getObjectDelta(), result); + } + lensContext.rottenExecutedDeltas.add(objectDeltaOperation); + } + + if (result.isUnknown()) { + result.computeStatus(); + } + return lensContext; + } + + protected void fixProvisioningTypeInDelta(ObjectDelta delta, OperationResult result) + throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException { + if (delta != null && delta.getObjectTypeClass() != null + && (ShadowType.class.isAssignableFrom(delta.getObjectTypeClass()) + || ResourceType.class.isAssignableFrom(delta.getObjectTypeClass()))) { + getProvisioningService().applyDefinition(delta, result); + } + } @Override public String toString() { - return "LensContext(s=" + state + ", W(e=" + executionWave + ",p=" + projectionWave + "): "+focusContext+", "+projectionContexts+")"; + return "LensContext(s=" + state + ", W(e=" + executionWave + ",p=" + projectionWave + "): " + + focusContext + ", " + projectionContexts + ")"; } - - - public ValuePolicyType getEffectivePasswordPolicy(){ - if (getFocusContext().getOrgPasswordPolicy() != null){ + + public ValuePolicyType getEffectivePasswordPolicy() { + if (getFocusContext().getOrgPasswordPolicy() != null) { return getFocusContext().getOrgPasswordPolicy(); } return globalPasswordPolicy; } - public void setProgressListeners(Collection progressListeners) { - this.progressListeners = progressListeners; - } - - public Collection getProgressListeners() { - return progressListeners; - } - - @Override - public void reportProgress(ProgressInformation progress) { - if (progressListeners == null) { - return; - } - - for (ProgressListener listener : progressListeners) { - listener.onProgressAchieved(this, progress); - } - } - - public boolean isAbortRequested() { - if (progressListeners == null) { - return false; - } - for (ProgressListener progressListener : progressListeners) { - if (progressListener.isAbortRequested()) { - return true; - } - } - return false; - } + public void setProgressListeners(Collection progressListeners) { + this.progressListeners = progressListeners; + } + + public Collection getProgressListeners() { + return progressListeners; + } + + @Override + public void reportProgress(ProgressInformation progress) { + if (progressListeners == null) { + return; + } + + for (ProgressListener listener : progressListeners) { + listener.onProgressAchieved(this, progress); + } + } + + public boolean isAbortRequested() { + if (progressListeners == null) { + return false; + } + for (ProgressListener progressListener : progressListeners) { + if (progressListener.isAbortRequested()) { + return true; + } + } + return false; + } public Collection getHistoricResourceObjects() { if (historicResourceObjects == null) { @@ -1139,7 +1185,7 @@ public Collection getHistoricResourceObjects() { } return historicResourceObjects; } - + public Map getSequences() { return sequences; } @@ -1147,7 +1193,7 @@ public Map getSequences() { public Long getSequenceCounter(String sequenceOid) { return sequences.get(sequenceOid); } - + public void setSequenceCounter(String sequenceOid, long counter) { sequences.put(sequenceOid, counter); } @@ -1163,9 +1209,9 @@ public void addConflictingProjectionContext(LensProjectionContext conflictingCon public void clearConflictingProjectionContexts() { conflictingProjectionContexts.clear(); } - + public boolean hasExplosiveProjection() throws SchemaException { - for (LensProjectionContext projectionContext: projectionContexts) { + for (LensProjectionContext projectionContext : projectionContexts) { if (projectionContext.getVolatility() == ResourceObjectVolatilityType.EXPLOSIVE) { return true; } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/AssignmentProcessor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/AssignmentProcessor.java index c1d5b3bb7b0..a1fab85f1b3 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/AssignmentProcessor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/AssignmentProcessor.java @@ -892,7 +892,7 @@ public void processOrgAssignments(LensContext context, ItemPath orgRefPath = new ItemPath(FocusType.F_PARENT_ORG_REF); // check if parentOrgRef recon is needed - it is when something inside OrgType assignment has changed - boolean forceRecon = context.isDoReconciliationForAllProjections(); // this is directly influenced by Reconcile model execution option + boolean forceRecon = context.isReconcileFocus(); // this is directly influenced by Reconcile model execution option if (!forceRecon) { for (EvaluatedAssignmentImpl assignment : evaluatedAssignmentTriple.getAllValues()) { if (assignment.isForceRecon() && diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/sync/FocusValidityScannerTaskHandler.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/sync/FocusValidityScannerTaskHandler.java index 6610d249996..36d8769a384 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/sync/FocusValidityScannerTaskHandler.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/sync/FocusValidityScannerTaskHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2014 Evolveum + * 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. @@ -15,6 +15,7 @@ */ package com.evolveum.midpoint.model.impl.sync; +import com.evolveum.midpoint.model.api.ModelExecuteOptions; import com.evolveum.midpoint.model.api.ModelPublicConstants; import com.evolveum.midpoint.model.impl.lens.Clockwork; import com.evolveum.midpoint.model.impl.lens.ContextFactory; @@ -38,6 +39,8 @@ import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentType; import com.evolveum.midpoint.xml.ns._public.common.common_3.FocusType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.PartialProcessingOptionsType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.PartialProcessingTypeType; import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; import org.apache.commons.lang3.Validate; import org.springframework.beans.factory.annotation.Autowired; @@ -177,7 +180,7 @@ protected boolean handleObject(PrismObject object, Task workerTask, Op if (oidAlreadySeen(coordinatorTask, object.getOid())) { LOGGER.trace("Recomputation already executed for {}", ObjectTypeUtil.toShortString(object)); } else { - recomputeUser(object, workerTask, result); + reconcileUser(object, workerTask, result); } return true; } @@ -186,14 +189,15 @@ protected boolean handleObject(PrismObject object, Task workerTask, Op return handler; } - private void recomputeUser(PrismObject user, Task workerTask, OperationResult result) throws SchemaException, + private void reconcileUser(PrismObject user, Task workerTask, OperationResult result) throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ObjectAlreadyExistsException, ConfigurationException, PolicyViolationException, SecurityViolationException { LOGGER.trace("Recomputing user {}", user); - - LensContext syncContext = contextFactory.createRecomputeContext(user, workerTask, result); - LOGGER.trace("Recomputing of user {}: context:\n{}", user, syncContext.debugDump()); - clockwork.run(syncContext, workerTask, result); + // We want reconcile option here. There may be accounts that are in wrong activation state. + // We will not notice that unless we go with reconcile. + LensContext lensContext = contextFactory.createRecomputeContext(user, ModelExecuteOptions.createReconcile(), workerTask, result); + LOGGER.trace("Recomputing of user {}: context:\n{}", user, lensContext.debugDump()); + clockwork.run(lensContext, workerTask, result); LOGGER.trace("Recomputing of user {}: {}", user, result.getStatus()); } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/sync/RecomputeTaskHandler.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/sync/RecomputeTaskHandler.java index dda171d442e..dccc7fbf503 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/sync/RecomputeTaskHandler.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/sync/RecomputeTaskHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2013 Evolveum + * 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. @@ -25,12 +25,14 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import com.evolveum.midpoint.model.api.ModelExecuteOptions; import com.evolveum.midpoint.model.impl.ModelConstants; import com.evolveum.midpoint.model.impl.lens.Clockwork; import com.evolveum.midpoint.model.impl.lens.ContextFactory; import com.evolveum.midpoint.model.impl.lens.LensContext; import com.evolveum.midpoint.model.impl.util.AbstractSearchIterativeResultHandler; import com.evolveum.midpoint.model.impl.util.AbstractSearchIterativeTaskHandler; +import com.evolveum.midpoint.model.impl.util.Utils; import com.evolveum.midpoint.prism.PrismContext; import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.query.ObjectQuery; @@ -110,20 +112,32 @@ protected AbstractSearchIterativeResultHandler createHandler(TaskRunR coordinatorTask, RecomputeTaskHandler.class.getName(), "recompute", "recompute task", taskManager) { @Override protected boolean handleObject(PrismObject object, Task workerTask, OperationResult result) throws CommonException { - recompute(object, workerTask, result); + recompute(object, getOptions(coordinatorTask), workerTask, result); return true; } + }; handler.setStopOnError(false); return handler; } - private void recompute(PrismObject focalObject, Task task, OperationResult result) throws SchemaException, + private ModelExecuteOptions getOptions(Task coordinatorTask) throws SchemaException { + ModelExecuteOptions modelExecuteOptions = Utils.getModelExecuteOptions(coordinatorTask); + if (modelExecuteOptions == null) { + // Make reconcile the default (for compatibility). If there are no options + // then assume reconcile. + modelExecuteOptions = ModelExecuteOptions.createReconcile(); + } + LOGGER.trace("ModelExecuteOptions: {}", modelExecuteOptions); + return modelExecuteOptions; + } + + private void recompute(PrismObject focalObject, ModelExecuteOptions options, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ObjectAlreadyExistsException, ConfigurationException, PolicyViolationException, SecurityViolationException { LOGGER.trace("Recomputing object {}", focalObject); - LensContext syncContext = contextFactory.createRecomputeContext(focalObject, task, result); + LensContext syncContext = contextFactory.createRecomputeContext(focalObject, options, task, result); if (LOGGER.isTraceEnabled()) { LOGGER.trace("Recomputing object {}: context:\n{}", focalObject, syncContext.debugDump()); } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/trigger/RecomputeTriggerHandler.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/trigger/RecomputeTriggerHandler.java index 82bf286955d..ab2f6c6549d 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/trigger/RecomputeTriggerHandler.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/trigger/RecomputeTriggerHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Evolveum + * Copyright (c) 2013-2017 Evolveum * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +21,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import com.evolveum.midpoint.model.api.ModelExecuteOptions; import com.evolveum.midpoint.model.impl.ModelConstants; import com.evolveum.midpoint.model.impl.lens.Clockwork; import com.evolveum.midpoint.model.impl.lens.ContextFactory; @@ -82,11 +83,12 @@ public void handle(PrismObject object, TriggerType tri try { LOGGER.trace("Recomputing {}", object); - LensContext syncContext = contextFactory.createRecomputeContext(object, task, result); + // Reconcile option used for compatibility. TODO: do we need it? + LensContext lensContext = contextFactory.createRecomputeContext(object, ModelExecuteOptions.createReconcile(), task, result); if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Recomputing of {}: context:\n{}", object, syncContext.debugDump()); + LOGGER.trace("Recomputing of {}: context:\n{}", object, lensContext.debugDump()); } - clockwork.run(syncContext, task, result); + clockwork.run(lensContext, task, result); LOGGER.trace("Recomputing of {}: {}", object, result.getStatus()); } catch (SchemaException e) { diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/util/Utils.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/util/Utils.java index 20ca5b59ac7..55347364e37 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/util/Utils.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/util/Utils.java @@ -452,7 +452,7 @@ public static void clearRequestee(Task task) { setRequestee(task, (PrismObject) null); } - public static boolean isDryRun(Task task) throws SchemaException{ + public static boolean isDryRun(Task task) throws SchemaException { Boolean dryRun = isDryRunInternal(task); if (dryRun == null && task.isLightweightAsynchronousTask() && task.getParentForLightweightAsynchronousTask() != null) { dryRun = isDryRunInternal(task.getParentForLightweightAsynchronousTask()); @@ -474,6 +474,30 @@ private static Boolean isDryRunInternal(Task task) throws SchemaException{ } return item.getValues().iterator().next().getValue(); } + + public static ModelExecuteOptions getModelExecuteOptions(Task task) throws SchemaException { + Validate.notNull(task, "Task must not be null."); + if (task.getExtension() == null) { + return null; + } + LOGGER.info("Task:\n{}",task.debugDump(1)); + PrismProperty item = task.getExtensionProperty(SchemaConstants.C_MODEL_EXECUTE_OPTIONS); + if (item == null || item.isEmpty()) { + return null; + } + LOGGER.info("Item:\n{}",item.debugDump(1)); + if (item.getValues().size() > 1) { + throw new SchemaException("Unexpected number of values for option 'modelExecuteOptions'."); + } + ModelExecuteOptionsType modelExecuteOptionsType = item.getValues().iterator().next().getValue(); + if (modelExecuteOptionsType == null) { + return null; + } + LOGGER.info("modelExecuteOptionsType: {}",modelExecuteOptionsType); + ModelExecuteOptions modelExecuteOptions = ModelExecuteOptions.fromModelExecutionOptionsType(modelExecuteOptionsType); + LOGGER.info("modelExecuteOptions: {}",modelExecuteOptions); + return modelExecuteOptions; + } public static ExpressionVariables getDefaultExpressionVariables(@NotNull LensContext context, @Nullable LensProjectionContext projCtx) throws SchemaException { ExpressionVariables variables = new ExpressionVariables(); diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/AbstractConfiguredModelIntegrationTest.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/AbstractConfiguredModelIntegrationTest.java index badd6ff963b..f6b5aeab1a2 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/AbstractConfiguredModelIntegrationTest.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/AbstractConfiguredModelIntegrationTest.java @@ -22,6 +22,8 @@ import com.evolveum.midpoint.prism.PrismContainer; import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.PrismProperty; +import com.evolveum.midpoint.prism.PrismReferenceValue; +import com.evolveum.midpoint.prism.delta.ReferenceDelta; import com.evolveum.midpoint.prism.path.ItemPath; import com.evolveum.midpoint.prism.schema.PrismSchema; import com.evolveum.midpoint.schema.constants.MidPointConstants; @@ -56,6 +58,8 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Collection; import java.util.Date; import javax.xml.datatype.XMLGregorianCalendar; @@ -600,4 +604,21 @@ protected void assertLastRecomputeTimestamp(String taskOid, XMLGregorianCalendar protected void assertPasswordMetadata(PrismObject user, boolean create, XMLGregorianCalendar start, XMLGregorianCalendar end) { assertPasswordMetadata(user, create, start, end, USER_ADMINISTRATOR_OID, SchemaConstants.CHANNEL_GUI_USER_URI); } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + protected void clearUserOrgAndRoleRefs(String userOid) throws ObjectNotFoundException, SchemaException, ObjectAlreadyExistsException, SecurityViolationException, CommunicationException, ConfigurationException { + OperationResult result = new OperationResult("clearUserOrgAndRoleRefs"); + Collection modifications = new ArrayList<>(); + ReferenceDelta parentOrgRefDelta = ReferenceDelta.createModificationReplace( + UserType.F_PARENT_ORG_REF, getUserDefinition(), (PrismReferenceValue)null); + modifications.add(parentOrgRefDelta); + ReferenceDelta roleMembershipRefDelta = ReferenceDelta.createModificationReplace( + UserType.F_ROLE_MEMBERSHIP_REF, getUserDefinition(), (PrismReferenceValue)null); + modifications.add(roleMembershipRefDelta); + repositoryService.modifyObject(UserType.class, userOid, modifications, result); + result.computeStatus(); + TestUtil.assertSuccess(result); + PrismObject userBefore = getUser(userOid); + display("User before", userBefore); + } } diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestActivation.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestActivation.java index d9d7571e1ac..ed2f4110487 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestActivation.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestActivation.java @@ -1508,7 +1508,7 @@ public void test212SeeLargoTomorrow() throws Exception { clock.override(crrentNow); // WHEN - modelService.recompute(UserType.class, USER_LARGO_OID, task, result); + recomputeUser(USER_LARGO_OID, task, result); // THEN PrismObject userLargo = getUser(USER_LARGO_OID); @@ -1551,7 +1551,7 @@ public void test213HastaLaMananaLargo() throws Exception { clock.override(crrentNow); // WHEN - modelService.recompute(UserType.class, USER_LARGO_OID, task, result); + modelService.recompute(UserType.class, USER_LARGO_OID, null, task, result); // THEN PrismObject userLargo = getUser(USER_LARGO_OID); @@ -1651,7 +1651,9 @@ public void test217ModifyLargoRemoveValidFrom() throws Exception { } /** - * Delete assignment from repo. Model should not notice. The change should be applied after recompute. + * Delete assignment from repo. Model should not notice. + * The change should be NOT applied after recompute. + * Accounts are not retrieved, therefore the change is not noticed. */ @Test public void test230JackUnassignRepoRecompute() throws Exception { @@ -1659,7 +1661,6 @@ public void test230JackUnassignRepoRecompute() throws Exception { TestUtil.displayTestTile(this, TEST_NAME); // GIVEN - long startMillis = clock.currentTimeMillis(); Task task = taskManager.createTaskInstance(TestActivation.class.getName() + "." + TEST_NAME); OperationResult result = task.getResult(); @@ -1681,9 +1682,34 @@ public void test230JackUnassignRepoRecompute() throws Exception { result.computeStatus(); TestUtil.assertSuccess(result); + assertDummyAccount(RESOURCE_DUMMY_RED_NAME, ACCOUNT_JACK_DUMMY_USERNAME, "Jack Sparrow", true); + } + + /** + * Deleted assignment from the repo (previous test). Model haven't noticed. + * Now recompute with reconcile. The change should be applied after recompute. + */ + @Test + public void test231JackRecomputeReconcile() throws Exception { + final String TEST_NAME = "test231JackRecomputeReconcile"; + TestUtil.displayTestTile(this, TEST_NAME); + + // GIVEN + Task task = taskManager.createTaskInstance(TestActivation.class.getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + + // WHEN + TestUtil.displayWhen(TEST_NAME); + recomputeUser(USER_JACK_OID, ModelExecuteOptions.createReconcile(), task, result); + + // THEN + TestUtil.displayThen(TEST_NAME); + result.computeStatus(); + TestUtil.assertSuccess(result); + assertDummyAccount(RESOURCE_DUMMY_RED_NAME, ACCOUNT_JACK_DUMMY_USERNAME, "Jack Sparrow", false); } - + /** * Add draft user with a role assignment. * Even though Pirate role gives dummy account the user is in the draft @@ -2256,7 +2282,7 @@ private void test5X1Recompute(final String TEST_NAME, Clas dummyAuditService.clear(); // WHEN - modelService.recompute(type, oid, task, result); + modelService.recompute(type, oid, null, task, result); // THEN result.computeStatus(); @@ -2347,7 +2373,7 @@ public void test5X5Recompute(final String TEST_NAME, Class dummyAuditService.clear(); // WHEN - modelService.recompute(type, oid, task, result); + modelService.recompute(type, oid, null, task, result); // THEN result.computeStatus(); diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestMultiResource.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestMultiResource.java index 5f806ef5e13..af8054d291a 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestMultiResource.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestMultiResource.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Evolveum + * 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. @@ -31,6 +31,7 @@ import com.evolveum.icf.dummy.resource.ConflictException; import com.evolveum.icf.dummy.resource.DummyResource; import com.evolveum.icf.dummy.resource.SchemaViolationException; +import com.evolveum.midpoint.model.api.ModelExecuteOptions; import com.evolveum.midpoint.model.intest.rbac.TestRbac; import com.evolveum.midpoint.prism.PrismContainerValue; import com.evolveum.midpoint.prism.PrismObject; @@ -578,7 +579,7 @@ public void test223JackKillDefaultDummyAccounAndRecompute() throws Exception { /** * Delete account on beige dummy resource (but keep it assigned and keep the shadow). - * The recompute the user. The account should be re-created. + * Then recompute the user. The account should be re-created. * MID-2134, MID-3093 */ @Test @@ -595,7 +596,7 @@ public void test224JackKillBeigeAccounAndRecompute() throws Exception { // WHEN TestUtil.displayWhen(TEST_NAME); - recomputeUser(USER_JACK_OID, task, result); + recomputeUser(USER_JACK_OID, ModelExecuteOptions.createReconcile(), task, result); // THEN TestUtil.displayThen(TEST_NAME); @@ -638,7 +639,7 @@ public void test225JackKillBothAccounsAndRecompute() throws Exception { // WHEN TestUtil.displayWhen(TEST_NAME); - recomputeUser(USER_JACK_OID, task, result); + recomputeUser(USER_JACK_OID, ModelExecuteOptions.createReconcile(), task, result); // THEN TestUtil.displayThen(TEST_NAME); @@ -2109,7 +2110,7 @@ public void test422DavidAndGoliathAssignRoleGoliathUpRecompute() throws Exceptio dummyResourceGoliath.setBreakMode(BreakMode.NONE); // WHEN - modelService.recompute(UserType.class, userBefore.getOid(), task, result); + recomputeUser(userBefore.getOid(), task, result); // THEN TestUtil.displayThen(TEST_NAME); diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/negative/TestAssignmentErrors.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/negative/TestAssignmentErrors.java index f9953280ec1..88719a41208 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/negative/TestAssignmentErrors.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/negative/TestAssignmentErrors.java @@ -505,7 +505,7 @@ public void test220UserAssignAccountDeletedShadowRecomputeSync() throws Exceptio OperationResult result = task.getResult(); // WHEN - modelService.recompute(UserType.class, user.getOid(), task, result); + recomputeUser(user.getOid(), task, result); // THEN result.computeStatus(); @@ -527,7 +527,7 @@ public void test220UserAssignAccountDeletedShadowRecomputeSync() throws Exceptio result = task.getResult(); // WHEN - modelService.recompute(UserType.class, user.getOid(), task, result); + recomputeUser(user.getOid(), task, result); // THEN result.computeStatus(); @@ -561,7 +561,7 @@ public void test222UserAssignAccountDeletedShadowRecomputeNoSync() throws Except try { // WHEN - modelService.recompute(UserType.class, user.getOid(), task, result); + recomputeUser(user.getOid(), task, result); AssertJUnit.fail("Unexpected success"); } catch (ObjectAlreadyExistsException e) { @@ -581,7 +581,7 @@ public void test222UserAssignAccountDeletedShadowRecomputeNoSync() throws Except try { // WHEN - modelService.recompute(UserType.class, user.getOid(), task, result); + recomputeUser(user.getOid(), task, result); AssertJUnit.fail("Unexpected success"); } catch (ObjectAlreadyExistsException e) { @@ -616,7 +616,7 @@ public void test224UserAssignAccountDeletedShadowRecomputeReducedSync() throws E OperationResult result = task.getResult(); // WHEN - modelService.recompute(UserType.class, user.getOid(), task, result); + recomputeUser(user.getOid(), task, result); // THEN result.computeStatus(); @@ -638,7 +638,7 @@ public void test224UserAssignAccountDeletedShadowRecomputeReducedSync() throws E result = task.getResult(); // WHEN - modelService.recompute(UserType.class, user.getOid(), task, result); + recomputeUser(user.getOid(), task, result); // THEN result.computeStatus(); diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/orgstruct/TestOrgStruct.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/orgstruct/TestOrgStruct.java index 937a4bf29c3..35d5ca4c553 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/orgstruct/TestOrgStruct.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/orgstruct/TestOrgStruct.java @@ -23,6 +23,7 @@ import java.util.Collection; import java.util.List; +import com.evolveum.midpoint.model.api.ModelExecuteOptions; import com.evolveum.midpoint.model.impl.expr.ExpressionEnvironment; import com.evolveum.midpoint.model.impl.expr.ModelExpressionThreadLocalHolder; import com.evolveum.midpoint.model.intest.AbstractInitializedModelIntegrationTest; @@ -64,6 +65,8 @@ import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; import com.evolveum.midpoint.xml.ns._public.common.common_3.OrgType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.PartialProcessingOptionsType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.PartialProcessingTypeType; import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; import javax.xml.namespace.QName; @@ -504,8 +507,126 @@ public void test223JackChangeMinistryOfOffenseMemberToManager() throws Exception // Postcondition assertMonkeyIslandOrgSanity(); } + + + /** + * Recompute jack. Make sure nothing is changed. + * MID-3384 + */ + @Test + public void test230JackRecompute() throws Exception { + final String TEST_NAME = "test230JackRecompute"; + TestUtil.displayTestTile(this, TEST_NAME); + + Task task = createTask(TEST_NAME); + OperationResult result = task.getResult(); + rememberShadowFetchOperationCount(); + + // WHEN + TestUtil.displayWhen(TEST_NAME); + recomputeUser(USER_JACK_OID, task, result); + + // THEN + TestUtil.displayThen(TEST_NAME); + result.computeStatus(); + TestUtil.assertSuccess(result); + + assertRefs23x(); + assertShadowFetchOperationCountIncrement(1); + } + + /** + * Destroy parentOrgRef and roleMembershipRef in the repo. Then recompute. + * Make sure that the refs are fixed. + * MID-3384 + */ + @Test + public void test232JackDestroyRefsAndRecompute() throws Exception { + final String TEST_NAME = "test232JackDestroyRefsAndRecompute"; + TestUtil.displayTestTile(this, TEST_NAME); + + Task task = createTask(TEST_NAME); + OperationResult result = task.getResult(); + + clearUserOrgAndRoleRefs(USER_JACK_OID); + + rememberShadowFetchOperationCount(); + rememberConnectorOperationCount(); + + // WHEN + TestUtil.displayWhen(TEST_NAME); + recomputeUser(USER_JACK_OID, ModelExecuteOptions.createReconcile(), task, result); + + // THEN + TestUtil.displayThen(TEST_NAME); + result.computeStatus(); + TestUtil.assertSuccess(result); + + assertRefs23x(); + assertShadowFetchOperationCountIncrement(1); + assertConnectorOperationIncrement(4); + } + + /** + * Destroy parentOrgRef and roleMembershipRef in the repo. Then light recompute. + * Make sure that the refs are fixed and that the resources were not touched. + * MID-3384 + */ + @Test + public void test234JackDestroyRefsAndLightRecompute() throws Exception { + final String TEST_NAME = "test234JackDestroyRefsAndLightRecompute"; + TestUtil.displayTestTile(this, TEST_NAME); + + Task task = createTask(TEST_NAME); + OperationResult result = task.getResult(); + + clearUserOrgAndRoleRefs(USER_JACK_OID); + + rememberShadowFetchOperationCount(); + rememberConnectorOperationCount(); + + PartialProcessingOptionsType partialProcessing = new PartialProcessingOptionsType(); + partialProcessing.setInbound(PartialProcessingTypeType.SKIP); + partialProcessing.setObjectTemplateBeforeAssignments(PartialProcessingTypeType.SKIP); + partialProcessing.setObjectTemplateAfterAssignments(PartialProcessingTypeType.SKIP); + partialProcessing.setProjection(PartialProcessingTypeType.SKIP); + partialProcessing.setApprovals(PartialProcessingTypeType.SKIP); + ModelExecuteOptions options = ModelExecuteOptions.createPartialProcessing(partialProcessing); + options.setReconcileFocus(true); + + // WHEN + TestUtil.displayWhen(TEST_NAME); + modelService.recompute(UserType.class, USER_JACK_OID, options, task, result); + + // THEN + TestUtil.displayThen(TEST_NAME); + result.computeStatus(); + TestUtil.assertSuccess(result); + + assertRefs23x(); + assertShadowFetchOperationCountIncrement(0); + assertConnectorOperationIncrement(0); + } + + + + private void assertRefs23x() throws Exception { + PrismObject userAfter = getUser(USER_JACK_OID); + display("User after", userAfter); + assertAssignedOrgs(userAfter, ORG_MINISTRY_OF_OFFENSE_OID, ORG_SCUMM_BAR_OID, ORG_SAVE_ELAINE_OID); + assertHasOrgs(userAfter, ORG_MINISTRY_OF_OFFENSE_OID, ORG_SCUMM_BAR_OID, ORG_SAVE_ELAINE_OID, ORG_MINISTRY_OF_DEFENSE_OID); + assertAssignedOrg(userAfter, ORG_MINISTRY_OF_OFFENSE_OID, SchemaConstants.ORG_MANAGER); + assertHasOrg(userAfter, ORG_MINISTRY_OF_OFFENSE_OID, SchemaConstants.ORG_MANAGER); + assertAssignedOrg(userAfter, ORG_SCUMM_BAR_OID, null); + assertHasOrg(userAfter, ORG_SCUMM_BAR_OID, null); + assertAssignedOrg(userAfter, ORG_SAVE_ELAINE_OID, null); + assertHasOrg(userAfter, ORG_SAVE_ELAINE_OID, null); + + // Postcondition + assertMonkeyIslandOrgSanity(); + } - private Long findAssignmentIdForTarget(PrismObject user, String targetOid) { + private Long findAssignmentIdForTarget(PrismObject user, String targetOid) { for (AssignmentType assignmentType : user.asObjectable().getAssignment()) { if (assignmentType.getTargetRef() != null && targetOid.equals(assignmentType.getTargetRef().getOid())) { return assignmentType.getId(); diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/orgstruct/TestOrgStructCaribbean.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/orgstruct/TestOrgStructCaribbean.java index 5b0df48712a..9f91726d484 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/orgstruct/TestOrgStructCaribbean.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/orgstruct/TestOrgStructCaribbean.java @@ -19,6 +19,7 @@ import java.io.File; +import com.evolveum.midpoint.model.api.ModelExecuteOptions; import com.evolveum.midpoint.model.intest.AbstractInitializedModelIntegrationTest; import org.springframework.test.annotation.DirtiesContext; @@ -128,7 +129,7 @@ public void test102RecomputeJamaica() throws Exception { // WHEN TestUtil.displayWhen(TEST_NAME); - modelService.recompute(OrgType.class, ORG_CARIBBEAN_JAMAICA_OID, task, result); + modelService.recompute(OrgType.class, ORG_CARIBBEAN_JAMAICA_OID, null, task, result); // THEN TestUtil.displayThen(TEST_NAME); @@ -190,7 +191,7 @@ public void test104RecomputeGovernor() throws Exception { // WHEN TestUtil.displayWhen(TEST_NAME); - modelService.recompute(OrgType.class, ORG_GOVERNOR_OFFICE_OID, task, result); + modelService.recompute(OrgType.class, ORG_GOVERNOR_OFFICE_OID, null, task, result); // THEN TestUtil.displayThen(TEST_NAME); @@ -255,7 +256,8 @@ public void test106RecomputeDoT() throws Exception { // WHEN TestUtil.displayWhen(TEST_NAME); - modelService.recompute(OrgType.class, ORG_CARIBBEAN_DEPARTMENT_OF_THINGS_OID, task, result); + modelService.recompute(OrgType.class, ORG_CARIBBEAN_DEPARTMENT_OF_THINGS_OID, + ModelExecuteOptions.createReconcileFocus(), task, result); // THEN TestUtil.displayThen(TEST_NAME); @@ -331,7 +333,7 @@ public void test110RecomputeDoP() throws Exception { // WHEN TestUtil.displayWhen(TEST_NAME); - modelService.recompute(OrgType.class, ORG_CARIBBEAN_DEPARTMENT_OF_PEOPLE_OID, task, result); + modelService.recompute(OrgType.class, ORG_CARIBBEAN_DEPARTMENT_OF_PEOPLE_OID, null, task, result); // THEN TestUtil.displayThen(TEST_NAME); diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/rbac/TestRbac.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/rbac/TestRbac.java index c6423b69598..b38add2d05b 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/rbac/TestRbac.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/rbac/TestRbac.java @@ -36,6 +36,7 @@ import org.testng.annotations.Test; import com.evolveum.icf.dummy.resource.DummyAccount; +import com.evolveum.midpoint.model.api.ModelExecuteOptions; import com.evolveum.midpoint.model.api.context.EvaluatedAssignment; import com.evolveum.midpoint.model.api.context.EvaluatedAssignmentTarget; import com.evolveum.midpoint.model.api.context.ModelContext; @@ -2185,7 +2186,7 @@ public void test703JackModifyJudgeDeleteInducementHonorabilityRecompute() throws // WHEN TestUtil.displayWhen(TEST_NAME); - recomputeUser(USER_JACK_OID, task, result); + recomputeUser(USER_JACK_OID, ModelExecuteOptions.createReconcile(), task, result); // THEN TestUtil.displayThen(TEST_NAME); @@ -2452,10 +2453,9 @@ public void test755AddProjectAndRecomputeJack() throws Exception { addObject(ORG_PROJECT_RECLAIM_BLACK_PEARL_FILE); - // WHEN TestUtil.displayWhen(TEST_NAME); - recomputeUser(USER_JACK_OID, task, result); + recomputeUser(USER_JACK_OID, ModelExecuteOptions.createReconcile(), task, result); // THEN TestUtil.displayThen(TEST_NAME); diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/sync/TestRecomputeTask.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/sync/TestRecomputeTask.java index 3c0dc725d70..fca47a39ce3 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/sync/TestRecomputeTask.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/sync/TestRecomputeTask.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Evolveum + * Copyright (c) 2013-2017 Evolveum * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -78,6 +78,9 @@ public class TestRecomputeTask extends AbstractInitializedModelIntegrationTest { private static final File TASK_USER_RECOMPUTE_FILE = new File(TEST_DIR, "task-user-recompute.xml"); private static final String TASK_USER_RECOMPUTE_OID = "91919191-76e0-59e2-86d6-3d4f02d3aaaa"; + private static final File TASK_USER_RECOMPUTE_LIGHT_FILE = new File(TEST_DIR, "task-user-recompute-light.xml"); + private static final String TASK_USER_RECOMPUTE_LIGHT_OID = "b7b6af78-fffe-11e6-ac04-2fdd62641ce2"; + private static final File TASK_USER_RECOMPUTE_CAPTAIN_FILE = new File(TEST_DIR, "task-user-recompute-captain.xml"); private static final String TASK_USER_RECOMPUTE_CAPTAIN_OID = "91919191-76e0-59e2-86d6-3d4f02d3aaac"; @@ -97,7 +100,7 @@ public void test100RecomputeAll() throws Exception { TestUtil.displayTestTile(this, TEST_NAME); // GIVEN - Task task = createTask(TestRecomputeTask.class.getName() + "." + TEST_NAME); + Task task = createTask(TEST_NAME); OperationResult result = task.getResult(); // Preconditions @@ -257,7 +260,7 @@ public void test110RecomputeSome() throws Exception { TestUtil.displayTestTile(this, TEST_NAME); // GIVEN - Task task = createTask(TestRecomputeTask.class.getName() + "." + TEST_NAME); + Task task = createTask(TEST_NAME); OperationResult result = task.getResult(); // Preconditions @@ -309,8 +312,6 @@ public void test110RecomputeSome() throws Exception { /** * Here we recompute herman as well. - * - * @throws Exception */ @Test public void test120RecomputeByExpression() throws Exception { @@ -318,7 +319,7 @@ public void test120RecomputeByExpression() throws Exception { TestUtil.displayTestTile(this, TEST_NAME); // GIVEN - Task task = createTask(TestRecomputeTask.class.getName() + "." + TEST_NAME); + Task task = createTask(TEST_NAME); OperationResult result = task.getResult(); // Preconditions @@ -366,5 +367,93 @@ public void test120RecomputeByExpression() throws Exception { assertUsers(6); } + + /** + * Light recompute. Very efficient, no resource operations, just fix the focus. + * MID-3384 + */ + @Test + public void test130RecomputeLight() throws Exception { + final String TEST_NAME = "test130RecomputeLight"; + TestUtil.displayTestTile(this, TEST_NAME); + + // GIVEN + Task task = createTask(TEST_NAME); + OperationResult result = task.getResult(); + + // Preconditions + assertUsers(6); + + PrismObject usetJackBefore = getUser(USER_JACK_OID); + display("User jack before", usetJackBefore); + assertAssignedRole(usetJackBefore, ROLE_JUDGE_OID); + assertRoleMembershipRef(usetJackBefore, ROLE_JUDGE_OID); + + assignOrg(USER_GUYBRUSH_OID, ORG_MINISTRY_OF_OFFENSE_OID, null); + PrismObject usetGuybrushBefore = getUser(USER_GUYBRUSH_OID); + display("User guybrush before", usetGuybrushBefore); + assertAssignedRole(usetGuybrushBefore, ROLE_PIRATE_OID); + assertRoleMembershipRef(usetGuybrushBefore, ROLE_PIRATE_OID, ORG_MINISTRY_OF_OFFENSE_OID); + assertAssignedOrgs(usetGuybrushBefore, ORG_MINISTRY_OF_OFFENSE_OID); + assertHasOrgs(usetGuybrushBefore, ORG_MINISTRY_OF_OFFENSE_OID); + + clearUserOrgAndRoleRefs(USER_JACK_OID); + clearUserOrgAndRoleRefs(USER_GUYBRUSH_OID); + + rememberShadowFetchOperationCount(); + rememberConnectorOperationCount(); + + // WHEN + TestUtil.displayWhen(TEST_NAME); + addObject(TASK_USER_RECOMPUTE_LIGHT_FILE); + + dummyAuditService.clear(); + + waitForTaskStart(TASK_USER_RECOMPUTE_LIGHT_OID, false); + + // WHEN + TestUtil.displayWhen(TEST_NAME); + + waitForTaskFinish(TASK_USER_RECOMPUTE_LIGHT_OID, true, 40000); + + // THEN + TestUtil.displayThen(TEST_NAME); + + List> users = modelService.searchObjects(UserType.class, null, null, task, result); + display("Users after recompute", users); + + assertShadowFetchOperationCountIncrement(0); + assertConnectorOperationIncrement(0); + + assertDummyAccount(null, ACCOUNT_GUYBRUSH_DUMMY_USERNAME, "Guybrush Threepwood", true); + assertDummyAccountAttribute(null, ACCOUNT_GUYBRUSH_DUMMY_USERNAME, + DummyResourceContoller.DUMMY_ACCOUNT_ATTRIBUTE_WEAPON_NAME, "cutlass", "dagger"); + assertNoDummyAccount(RESOURCE_DUMMY_RED_NAME, ACCOUNT_GUYBRUSH_DUMMY_USERNAME); + + // Red resource does not delete accounts on deprovision, it disables them + assertDummyAccount(RESOURCE_DUMMY_RED_NAME, ACCOUNT_JACK_DUMMY_USERNAME, "Jack Sparrow", false); + + // Herman should be recomputed now + assertDummyAccount(RESOURCE_DUMMY_RED_NAME, USER_HERMAN_USERNAME, "Herman Toothrot", false); + + TaskType recomputeTask = getTask(TASK_USER_RECOMPUTE_LIGHT_OID).asObjectable(); + assertEquals("Wrong success count", 6, recomputeTask.getOperationStats().getIterativeTaskInformation().getTotalSuccessCount()); + assertEquals("Wrong failure count", 0, recomputeTask.getOperationStats().getIterativeTaskInformation().getTotalFailureCount()); + + PrismObject usetJackAfter = getUser(USER_JACK_OID); + display("User jack after", usetJackAfter); + assertAssignedRole(usetJackAfter, ROLE_JUDGE_OID); + assertRoleMembershipRef(usetJackAfter, ROLE_JUDGE_OID); + + PrismObject usetGuybrushAfter = getUser(USER_GUYBRUSH_OID); + display("User guybrush after", usetGuybrushAfter); + assertAssignedRole(usetGuybrushAfter, ROLE_PIRATE_OID); + assertRoleMembershipRef(usetGuybrushAfter, ROLE_PIRATE_OID, ORG_MINISTRY_OF_OFFENSE_OID); + assertAssignedOrgs(usetGuybrushAfter, ORG_MINISTRY_OF_OFFENSE_OID); + assertHasOrgs(usetGuybrushAfter, ORG_MINISTRY_OF_OFFENSE_OID); + + assertUsers(6); + + } } diff --git a/model/model-intest/src/test/resources/logback-test.xml b/model/model-intest/src/test/resources/logback-test.xml index d5f2661ee10..a3724a26a1b 100644 --- a/model/model-intest/src/test/resources/logback-test.xml +++ b/model/model-intest/src/test/resources/logback-test.xml @@ -47,14 +47,14 @@ - + - + @@ -89,6 +89,7 @@ + diff --git a/model/model-intest/src/test/resources/sync/task-user-recompute-light.xml b/model/model-intest/src/test/resources/sync/task-user-recompute-light.xml new file mode 100644 index 00000000000..750e5b3771e --- /dev/null +++ b/model/model-intest/src/test/resources/sync/task-user-recompute-light.xml @@ -0,0 +1,48 @@ + + + + + + + + User Light Recompute + + + + true + + skip + skip + skip + skip + skip + + + + + + + runnable + + http://midpoint.evolveum.com/xml/ns/public/model/synchronization/task/recompute/handler-3 + single + tight + + diff --git a/model/model-test/src/main/java/com/evolveum/midpoint/model/test/AbstractModelIntegrationTest.java b/model/model-test/src/main/java/com/evolveum/midpoint/model/test/AbstractModelIntegrationTest.java index 567da59d3db..c82da0bd85c 100644 --- a/model/model-test/src/main/java/com/evolveum/midpoint/model/test/AbstractModelIntegrationTest.java +++ b/model/model-test/src/main/java/com/evolveum/midpoint/model/test/AbstractModelIntegrationTest.java @@ -814,7 +814,11 @@ protected void renameObject(Class type, String oid, St } protected void recomputeUser(String userOid, Task task, OperationResult result) throws SchemaException, PolicyViolationException, ExpressionEvaluationException, ObjectNotFoundException, ObjectAlreadyExistsException, CommunicationException, ConfigurationException, SecurityViolationException { - modelService.recompute(UserType.class, userOid, task, result); + modelService.recompute(UserType.class, userOid, null, task, result); + } + + protected void recomputeUser(String userOid, ModelExecuteOptions options, Task task, OperationResult result) throws SchemaException, PolicyViolationException, ExpressionEvaluationException, ObjectNotFoundException, ObjectAlreadyExistsException, CommunicationException, ConfigurationException, SecurityViolationException { + modelService.recompute(UserType.class, userOid, options, task, result); } protected void assignRole(String userOid, String roleOid) throws ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException, ObjectAlreadyExistsException, PolicyViolationException, SecurityViolationException { @@ -3896,7 +3900,7 @@ protected String addAndRecomputeUser(File file, Task initTask, OperationResult i protected String addAndRecompute(File file, Task task, OperationResult result) throws Exception { PrismObject object = repoAddObjectFromFile(file, result); - modelService.recompute(object.asObjectable().getClass(), object.getOid(), task, result); + modelService.recompute(object.asObjectable().getClass(), object.getOid(), null, task, result); display("Object: " + file, getObject(object.asObjectable().getClass(), object.getOid())); return object.getOid(); }