From 80501d9cf2b45144420f9d95b332595466c21356 Mon Sep 17 00:00:00 2001 From: "Katarina Valalikova (katkav)" Date: Mon, 29 Sep 2014 10:02:15 +0200 Subject: [PATCH 01/19] loading full shadow for dependency computation (if specified) --- .../schema/util/ResourceTypeUtil.java | 9 +++++++++ .../xml/ns/public/common/common-3.xsd | 8 ++++++++ .../lens/projector/DependencyProcessor.java | 19 ++++++++++++++++--- .../model/impl/lens/projector/Projector.java | 4 ++-- 4 files changed, 35 insertions(+), 5 deletions(-) diff --git a/infra/schema/src/main/java/com/evolveum/midpoint/schema/util/ResourceTypeUtil.java b/infra/schema/src/main/java/com/evolveum/midpoint/schema/util/ResourceTypeUtil.java index 90c66dd5c4a..5067a6ea812 100644 --- a/infra/schema/src/main/java/com/evolveum/midpoint/schema/util/ResourceTypeUtil.java +++ b/infra/schema/src/main/java/com/evolveum/midpoint/schema/util/ResourceTypeUtil.java @@ -447,6 +447,15 @@ public static ResourceObjectTypeDependencyStrictnessType getDependencyStrictness } } + public static boolean isForceLoadDependentShadow(ResourceObjectTypeDependencyType dependency){ + Boolean force = dependency.isForceLoad(); + if (force == null){ + return false; + } + + return force; + } + public static boolean isDown(ResourceType resource){ return (resource.getOperationalState() != null && AvailabilityStatusType.DOWN == resource.getOperationalState().getLastAvailabilityStatus()); } diff --git a/infra/schema/src/main/resources/xml/ns/public/common/common-3.xsd b/infra/schema/src/main/resources/xml/ns/public/common/common-3.xsd index ac1f922f9cd..efc41fac072 100644 --- a/infra/schema/src/main/resources/xml/ns/public/common/common-3.xsd +++ b/infra/schema/src/main/resources/xml/ns/public/common/common-3.xsd @@ -3425,6 +3425,14 @@ + + + + Specifies if the shadow on which we depends has to be load. By default we do + not force to load full dependent shadow. + + + diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/DependencyProcessor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/DependencyProcessor.java index 01be826b487..1c0fe8abc9c 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/DependencyProcessor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/DependencyProcessor.java @@ -38,6 +38,7 @@ import com.evolveum.midpoint.model.impl.lens.LensUtil; import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.xml.XmlTypeConverter; +import com.evolveum.midpoint.provisioning.api.ProvisioningService; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.schema.util.ResourceTypeUtil; import com.evolveum.midpoint.task.api.Task; @@ -65,6 +66,9 @@ public class DependencyProcessor { private static final Trace LOGGER = TraceManager.getTrace(DependencyProcessor.class); + @Autowired + private ProvisioningService provisioningService; + public void resetWaves(LensContext context) throws PolicyViolationException { } @@ -333,7 +337,7 @@ private LensProjectionContext createAnotherContext(LensCo * and stuff like that. */ public boolean checkDependencies(LensContext context, - LensProjectionContext projContext) throws PolicyViolationException { + LensProjectionContext projContext, OperationResult result) throws PolicyViolationException { if (projContext.isDelete()) { // It is OK if we depend on something that is not there if we are being removed ... for now return true; @@ -402,6 +406,15 @@ public boolean checkDependencies(LensContext context, || strictness == ResourceObjectTypeDependencyStrictnessType.RELAXED) { if (wasProvisioned(dependencyAccountContext, context.getExecutionWave())) { // everything OK + if (ResourceTypeUtil.isForceLoadDependentShadow(dependency) && !dependencyAccountContext.isFullShadow()){ + try { + LensUtil.loadFullAccount(context, dependencyAccountContext, provisioningService, result); + } catch (ObjectNotFoundException | CommunicationException | SchemaException + | ConfigurationException | SecurityViolationException e) { + // this is not fatal error. we can continue without full account..the incosinstencies will be treaten later, by reconciliation + LOGGER.warn("Could not load dependent shadow, continue with the shadow loaded before."); + } + } } else { // We do not want to throw exception here. That will stop entire projection. // Let's just mark the projection as broken and skip it. @@ -425,10 +438,10 @@ public boolean checkDependencies(LensContext context, * Finally checks for all the dependencies. Some dependencies cannot be checked during wave computations as * we might not have all activation decisions yet. */ - public void checkDependenciesFinal(LensContext context) throws PolicyViolationException { + public void checkDependenciesFinal(LensContext context, OperationResult result) throws PolicyViolationException { for (LensProjectionContext accountContext: context.getProjectionContexts()) { - checkDependencies(context, accountContext); + checkDependencies(context, accountContext, result); } for (LensProjectionContext accountContext: context.getProjectionContexts()) { diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/Projector.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/Projector.java index dc23bdde740..65b2cad2fa6 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/Projector.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/Projector.java @@ -211,7 +211,7 @@ public void project(LensContext context, String activi if (consistencyChecks) context.checkConsistence(); - if (!dependencyProcessor.checkDependencies(context, projectionContext)) { + if (!dependencyProcessor.checkDependencies(context, projectionContext, result)) { continue; } @@ -255,7 +255,7 @@ public void project(LensContext context, String activi // We can do this only when computation of all the waves is finished. Before that we do not know // activation of every account and therefore cannot decide what is OK and what is not - dependencyProcessor.checkDependenciesFinal(context); + dependencyProcessor.checkDependenciesFinal(context, result); if (consistencyChecks) context.checkConsistence(); From d4896e7330502b299da5322b22f998074fc5dd67 Mon Sep 17 00:00:00 2001 From: "Katarina Valalikova (katkav)" Date: Thu, 2 Oct 2014 09:27:02 +0200 Subject: [PATCH 02/19] fixing inbound - outbound processing for dependency.. --- .../dummy/connector/DummyConfiguration.java | 14 +++ .../icf/dummy/connector/DummyConnector.java | 5 +- .../icf/dummy/resource/DummyAccount.java | 1 + .../icf/dummy/resource/DummyObject.java | 3 +- .../icf/dummy/resource/DummyResource.java | 27 +++++- .../midpoint/model/impl/lens/LensUtil.java | 2 +- .../lens/projector/AssignmentProcessor.java | 15 ++++ .../lens/projector/DependencyProcessor.java | 85 ++++++++++++++++--- .../model/impl/lens/projector/Projector.java | 5 +- .../test/AbstractModelIntegrationTest.java | 9 ++ .../midpoint/test/DummyResourceContoller.java | 2 +- .../midpoint/testing/story/TestTrafo.java | 16 +++- .../story/src/test/resources/schema/trafo.xsd | 7 ++ .../resources/trafo/resource-dummy-ad.xml | 10 +++ .../resources/trafo/resource-dummy-mail.xml | 11 +++ 15 files changed, 190 insertions(+), 22 deletions(-) diff --git a/icf-connectors/dummy-connector/src/main/java/com/evolveum/icf/dummy/connector/DummyConfiguration.java b/icf-connectors/dummy-connector/src/main/java/com/evolveum/icf/dummy/connector/DummyConfiguration.java index 0e511873e44..d5740c1cf09 100644 --- a/icf-connectors/dummy-connector/src/main/java/com/evolveum/icf/dummy/connector/DummyConfiguration.java +++ b/icf-connectors/dummy-connector/src/main/java/com/evolveum/icf/dummy/connector/DummyConfiguration.java @@ -44,6 +44,7 @@ public class DummyConfiguration extends AbstractConfiguration { private boolean requireExplicitEnable = false; private boolean caseIgnoreId = false; private boolean caseIgnoreValues = false; + private boolean generateDefaultValues = false; private boolean tolerateDuplicateValues = true; private String uselessString; private GuardedString uselessGuardedString; @@ -160,6 +161,19 @@ public boolean getCaseIgnoreId() { public void setCaseIgnoreId(boolean caseIgnoreId) { this.caseIgnoreId = caseIgnoreId; } + + /** + * If set to true then the "home dir" will be generated + */ + @ConfigurationProperty(displayMessageKey = "UI_GENERATE_DEFAULT_VALUES", + helpMessageKey = "UI_GENERATE_DEFAULT_VALUES") + public boolean isGenerateDefaultValues() { + return generateDefaultValues; + } + + public void setGenerateDefaultValues(boolean generateDefaultValues) { + this.generateDefaultValues = generateDefaultValues; + } /** * If set to true then the attribute values will be considered case-insensitive diff --git a/icf-connectors/dummy-connector/src/main/java/com/evolveum/icf/dummy/connector/DummyConnector.java b/icf-connectors/dummy-connector/src/main/java/com/evolveum/icf/dummy/connector/DummyConnector.java index 296ef2419fa..26963cfc080 100644 --- a/icf-connectors/dummy-connector/src/main/java/com/evolveum/icf/dummy/connector/DummyConnector.java +++ b/icf-connectors/dummy-connector/src/main/java/com/evolveum/icf/dummy/connector/DummyConnector.java @@ -144,6 +144,7 @@ public void init(Configuration configuration) { resource.setCaseIgnoreValues(this.configuration.getCaseIgnoreValues()); resource.setEnforceUniqueName(this.configuration.isEnforceUniqueName()); resource.setTolerateDuplicateValues(this.configuration.getTolerateDuplicateValues()); + resource.setGenerateDefaultValues(this.configuration.isGenerateDefaultValues()); resource.setUselessString(this.configuration.getUselessString()); GuardedString uselessGuardedString = this.configuration.getUselessGuardedString(); @@ -227,6 +228,8 @@ public Uid create(final ObjectClass objectClass, final Set createAttr throw new ConnectionFailedException(e.getMessage(), e); } catch (FileNotFoundException e) { throw new ConnectorIOException(e.getMessage(), e); + } catch (SchemaViolationException e) { + throw new ConnectorException(e); } String id; @@ -1065,7 +1068,7 @@ private ConnectorObjectBuilder createConnectorObjectBuilderCommon(DummyObject du (attributesToGet == null || attributesToGet.contains(OperationalAttributes.DISABLE_DATE_NAME))) { builder.addAttribute(OperationalAttributes.DISABLE_DATE_NAME, convertToLong(dummyObject.getValidTo())); } - } + } return builder; } diff --git a/icf-connectors/dummy-resource/src/main/java/com/evolveum/icf/dummy/resource/DummyAccount.java b/icf-connectors/dummy-resource/src/main/java/com/evolveum/icf/dummy/resource/DummyAccount.java index a6bffeb440c..a3f201ee035 100644 --- a/icf-connectors/dummy-resource/src/main/java/com/evolveum/icf/dummy/resource/DummyAccount.java +++ b/icf-connectors/dummy-resource/src/main/java/com/evolveum/icf/dummy/resource/DummyAccount.java @@ -38,6 +38,7 @@ public class DummyAccount extends DummyObject { public static final String ATTR_DESCRIPTION_NAME = "description"; public static final String ATTR_INTERESTS_NAME = "interests"; public static final String ATTR_PRIVILEGES_NAME = "privileges"; + public static final String ATTR_INTERNAL_ID = "internalId"; private String password = null; private Boolean lockout = null; diff --git a/icf-connectors/dummy-resource/src/main/java/com/evolveum/icf/dummy/resource/DummyObject.java b/icf-connectors/dummy-resource/src/main/java/com/evolveum/icf/dummy/resource/DummyObject.java index 49facb282d2..87dbb7f80aa 100644 --- a/icf-connectors/dummy-resource/src/main/java/com/evolveum/icf/dummy/resource/DummyObject.java +++ b/icf-connectors/dummy-resource/src/main/java/com/evolveum/icf/dummy/resource/DummyObject.java @@ -41,6 +41,7 @@ public abstract class DummyObject implements DebugDumpable { private String id; +// private int internalId = -1; private String name; private Map> attributes = new HashMap>(); private boolean enabled = true; @@ -60,7 +61,7 @@ public String getId() { public void setId(String id) { this.id = id; } - + public DummyObject(String name) { this.name = name; } diff --git a/icf-connectors/dummy-resource/src/main/java/com/evolveum/icf/dummy/resource/DummyResource.java b/icf-connectors/dummy-resource/src/main/java/com/evolveum/icf/dummy/resource/DummyResource.java index fb39b6081b0..535021a0b6f 100644 --- a/icf-connectors/dummy-resource/src/main/java/com/evolveum/icf/dummy/resource/DummyResource.java +++ b/icf-connectors/dummy-resource/src/main/java/com/evolveum/icf/dummy/resource/DummyResource.java @@ -77,6 +77,7 @@ public class DummyResource implements DebugDumpable { private List deltas; private int latestSyncToken; private boolean tolerateDuplicateValues = false; + private boolean generateDefaultValues = false; private boolean enforceUniqueName = true; private boolean enforceSchema = true; private boolean caseIgnoreId = false; @@ -88,6 +89,7 @@ public class DummyResource implements DebugDumpable { private BreakMode modifyBreakMode = BreakMode.NONE; private BreakMode deleteBreakMode = BreakMode.NONE; + // Following two properties are just copied from the connector // configuration and can be checked later. They are otherwise // completely useless. @@ -149,6 +151,14 @@ public void setTolerateDuplicateValues(boolean tolerateDuplicateValues) { this.tolerateDuplicateValues = tolerateDuplicateValues; } + public boolean isGenerateDefaultValues() { + return generateDefaultValues; + } + + public void setGenerateDefaultValues(boolean generateDefaultValues) { + this.generateDefaultValues = generateDefaultValues; + } + public boolean isEnforceUniqueName() { return enforceUniqueName; } @@ -418,7 +428,7 @@ public Collection listPrivileges() throws ConnectException, File } } - private synchronized String addObject(Map map, T newObject) throws ObjectAlreadyExistsException, ConnectException, FileNotFoundException { + private synchronized String addObject(Map map, T newObject) throws ObjectAlreadyExistsException, ConnectException, FileNotFoundException, SchemaViolationException { if (addBreakMode == BreakMode.NONE) { // just go on } else if (addBreakMode == BreakMode.NETWORK) { @@ -446,6 +456,13 @@ private synchronized String addObject(Map map, throw new IllegalStateException("The hell is frozen over. The impossible has happened. ID "+newId+" already exists ("+ type.getSimpleName()+" with identifier "+normalName+")"); } + //this is "resource-generated" attribute (used to simulate resource which generate by default attributes which we need to sync) + if (generateDefaultValues){ + int internalId = allObjects.size(); + newObject.addAttributeValue(DummyAccount.ATTR_INTERNAL_ID, internalId++); + } + + String mapKey; if (enforceUniqueName) { mapKey = normalName; @@ -470,6 +487,7 @@ private synchronized String addObject(Map map, return newObject.getName(); } + private synchronized void deleteObjectByName(Class type, Map map, String name) throws ObjectDoesNotExistException, ConnectException, FileNotFoundException { if (deleteBreakMode == BreakMode.NONE) { // go on @@ -615,7 +633,7 @@ private void renameObject(Class type, Map m existingObject.setName(newName); } - public String addAccount(DummyAccount newAccount) throws ObjectAlreadyExistsException, ConnectException, FileNotFoundException { + public String addAccount(DummyAccount newAccount) throws ObjectAlreadyExistsException, ConnectException, FileNotFoundException, SchemaViolationException { return addObject(accounts, newAccount); } @@ -627,7 +645,7 @@ public void renameAccount(String id, String oldUsername, String newUsername) thr renameObject(DummyAccount.class, accounts, id, oldUsername, newUsername); } - public String addGroup(DummyGroup newGroup) throws ObjectAlreadyExistsException, ConnectException, FileNotFoundException { + public String addGroup(DummyGroup newGroup) throws ObjectAlreadyExistsException, ConnectException, FileNotFoundException, SchemaViolationException { return addObject(groups, newGroup); } @@ -639,7 +657,7 @@ public void renameGroup(String id, String oldName, String newName) throws Object renameObject(DummyGroup.class, groups, id, oldName, newName); } - public String addPrivilege(DummyPrivilege newGroup) throws ObjectAlreadyExistsException, ConnectException, FileNotFoundException { + public String addPrivilege(DummyPrivilege newGroup) throws ObjectAlreadyExistsException, ConnectException, FileNotFoundException, SchemaViolationException { return addObject(privileges, newGroup); } @@ -692,6 +710,7 @@ public void runScript(String language, String scriptCode, Map pa public void populateWithDefaultSchema() { accountObjectClass.clear(); accountObjectClass.addAttributeDefinition(DummyAccount.ATTR_FULLNAME_NAME, String.class, true, false); + accountObjectClass.addAttributeDefinition(DummyAccount.ATTR_INTERNAL_ID, String.class, false, false); accountObjectClass.addAttributeDefinition(DummyAccount.ATTR_DESCRIPTION_NAME, String.class, false, false); accountObjectClass.addAttributeDefinition(DummyAccount.ATTR_INTERESTS_NAME, String.class, false, true); accountObjectClass.addAttributeDefinition(DummyAccount.ATTR_PRIVILEGES_NAME, String.class, false, true); diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensUtil.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensUtil.java index 8053df1baf3..2715a86f8ca 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensUtil.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensUtil.java @@ -595,7 +595,7 @@ public static void loadFullAccount(LensContext context // already loaded return; } - if (accCtx.isAdd()) { + if (accCtx.isAdd() && accCtx.getOid() == null) { // nothing to load yet return; } 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 8eaf23a22aa..c8c29906a8a 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 @@ -215,6 +215,7 @@ private void processAssignmentsProjectionsWithFocus(LensCo LOGGER.trace("Current assignments {}", SchemaDebugUtil.prettyPrint(assignmentsCurrent)); LOGGER.trace("Changed assignments {}", SchemaDebugUtil.prettyPrint(changedAssignments)); +// ObjectType source = determineSource(focusContext); ObjectType source = null; if (focusContext.getObjectCurrent() != null) { source = focusContext.getObjectCurrent().asObjectable(); @@ -635,6 +636,20 @@ private void processAssignmentsProjectionsWithFocus(LensCo } + private ObjectType determineSource(LensFocusContext focusContext) + throws SchemaException { + ObjectDelta delta = focusContext.getWaveDelta(focusContext.getLensContext().getExecutionWave()); + if (delta != null && !delta.isEmpty()) { + return focusContext.getObjectNew().asObjectable(); + } + + if (focusContext.getObjectCurrent() != null) { + return focusContext.getObjectCurrent().asObjectable(); + } + + return focusContext.getObjectNew().asObjectable(); + } + private void collectToZero(DeltaSetTriple> evaluatedAssignmentTriple, EvaluatedAssignment evaluatedAssignment, boolean forceRecon) { evaluatedAssignment.setForceRecon(forceRecon); diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/DependencyProcessor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/DependencyProcessor.java index 1c0fe8abc9c..87d98aeda4e 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/DependencyProcessor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/DependencyProcessor.java @@ -30,6 +30,7 @@ import com.evolveum.midpoint.common.Clock; import com.evolveum.midpoint.common.refinery.ResourceShadowDiscriminator; import com.evolveum.midpoint.model.api.PolicyViolationException; +import com.evolveum.midpoint.model.api.context.ModelState; import com.evolveum.midpoint.model.api.context.SynchronizationPolicyDecision; import com.evolveum.midpoint.model.impl.lens.LensContext; import com.evolveum.midpoint.model.impl.lens.LensFocusContext; @@ -406,15 +407,20 @@ public boolean checkDependencies(LensContext context, || strictness == ResourceObjectTypeDependencyStrictnessType.RELAXED) { if (wasProvisioned(dependencyAccountContext, context.getExecutionWave())) { // everything OK - if (ResourceTypeUtil.isForceLoadDependentShadow(dependency) && !dependencyAccountContext.isFullShadow()){ - try { - LensUtil.loadFullAccount(context, dependencyAccountContext, provisioningService, result); - } catch (ObjectNotFoundException | CommunicationException | SchemaException - | ConfigurationException | SecurityViolationException e) { - // this is not fatal error. we can continue without full account..the incosinstencies will be treaten later, by reconciliation - LOGGER.warn("Could not load dependent shadow, continue with the shadow loaded before."); - } - } +// if (ResourceTypeUtil.isForceLoadDependentShadow(dependency) && !dependencyAccountContext.isDelete()){ +// LOGGER.info("FORCE TO LOAD FULL ACCOUNT " + dependencyAccountContext); +// try { +// LensUtil.loadFullAccount(context, dependencyAccountContext, provisioningService, result); +// dependencyAccountContext.setDoReconciliation(true); +// if (dependencyAccountContext.getExecutedDeltas() != null && !dependencyAccountContext.getExecutedDeltas().isEmpty()){ +// context.resetProjectionWave(); +// } +// } catch (ObjectNotFoundException | CommunicationException | SchemaException +// | ConfigurationException | SecurityViolationException e) { +// // this is not fatal error. we can continue without full account..the incosinstencies will be treaten later, by reconciliation +// LOGGER.warn("Could not load dependent shadow, continue with the shadow loaded before."); +// } +// } } else { // We do not want to throw exception here. That will stop entire projection. // Let's just mark the projection as broken and skip it. @@ -434,6 +440,45 @@ public boolean checkDependencies(LensContext context, return true; } + public void preprocessDependencies(LensContext context){ + + //in the first wave we do not have enougth information to preprocess connetxts + if (context.getExecutionWave() == 0){ + return; + } + + for (LensProjectionContext projContext : context.getProjectionContexts()){ + + for (ResourceObjectTypeDependencyType dependency: projContext.getDependencies()) { + ResourceShadowDiscriminator refRat = new ResourceShadowDiscriminator(dependency, + projContext.getResource().getOid(), projContext.getKind()); + LOGGER.trace("LOOKING FOR {}", refRat); + LensProjectionContext dependencyAccountContext = context.findProjectionContext(refRat); + ResourceObjectTypeDependencyStrictnessType strictness = ResourceTypeUtil.getDependencyStrictness(dependency); + if (dependencyAccountContext != null){ + // We have the context of the object that we depend on. We need to check if it was provisioned. + if (strictness == ResourceObjectTypeDependencyStrictnessType.STRICT + || strictness == ResourceObjectTypeDependencyStrictnessType.RELAXED) { + if (wasExecuted(dependencyAccountContext)) { + // everything OK + if (ResourceTypeUtil.isForceLoadDependentShadow(dependency) && !dependencyAccountContext.isDelete()){ + LOGGER.info("FORCE TO LOAD FULL ACCOUNT " + dependencyAccountContext); + dependencyAccountContext.setDoReconciliation(true); + projContext.setDoReconciliation(true); +// if (dependencyAccountContext.getExecutedDeltas() != null && !dependencyAccountContext.getExecutedDeltas().isEmpty()){ +// if (context.getProjectionWave() < context.getExecutionWave()){ +// context.resetProjectionWave(); +// } +// } + } + } + } + } + } + } + + } + /** * Finally checks for all the dependencies. Some dependencies cannot be checked during wave computations as * we might not have all activation decisions yet. @@ -484,14 +529,18 @@ private boolean wasProvisioned(LensProjectionContext acco || accountContext.getSynchronizationPolicyDecision() == SynchronizationPolicyDecision.IGNORE) { return false; } + + PrismObject objectCurrent = accountContext.getObjectCurrent(); if (objectCurrent != null && objectCurrent.asObjectable().getFailedOperationType() != null) { // There is unfinished operation in the shadow. We cannot continue. return false; - } + } + if (accountContext.isExists()) { return true; } + if (accountContext.isAdd()) { List> executedDeltas = accountContext.getExecutedDeltas(); if (executedDeltas == null || executedDeltas.isEmpty()) { @@ -505,8 +554,24 @@ private boolean wasProvisioned(LensProjectionContext acco } return true; } + return false; } + + private boolean wasExecuted(LensProjectionContext accountContext){ + if (accountContext.isAdd()) { + + if (accountContext.getOid() == null){ + return false; + } + + List> executedDeltas = accountContext.getExecutedDeltas(); + if (executedDeltas == null || executedDeltas.isEmpty()) { + return false; + } + } + return true; + } class DependencyAndSource { ResourceObjectTypeDependencyType dependency; diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/Projector.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/Projector.java index 65b2cad2fa6..b322d04c870 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/Projector.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/Projector.java @@ -152,12 +152,15 @@ public void project(LensContext context, String activi LOGGER.trace("WAVE: Starting the waves."); context.setProjectionWave(0); while (context.getProjectionWave() < maxWaves) { - + context.checkAbortRequested(); LOGGER.trace("WAVE {} (maxWaves={}, executionWave={})", new Object[]{ context.getProjectionWave(), maxWaves, context.getExecutionWave()}); + //just make sure everythink is loaded and set as needed + dependencyProcessor.preprocessDependencies(context); + // Process the focus-related aspects of the context. That means inbound, focus activation, // object template and assignments. focusProcessor.processFocus(context, activityDescription, now, task, result); 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 afbb3e95935..2d3953105c4 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 @@ -2189,6 +2189,15 @@ protected void assertDummyAccountAttribute(String dummyInstanceName, String user } } } + + protected void assertDummyAccountAttributeGenerated(String dummyInstanceName, String username) { + DummyAccount account = getDummyAccount(dummyInstanceName, username); + assertNotNull("No dummy account for username "+username, account); + Integer generated = account.getAttributeValue(DummyAccount.ATTR_INTERNAL_ID, Integer.class); + if (generated == null) { + AssertJUnit.fail("No value in generated attribute dir of " + dummyInstanceName + " dummy account " + username); + } + } protected DummyGroup getDummyGroup(String dummyInstanceName, String name) { DummyResource dummyResource = DummyResource.getInstance(dummyInstanceName); diff --git a/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/DummyResourceContoller.java b/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/DummyResourceContoller.java index 795fe002511..c1eb84f3617 100644 --- a/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/DummyResourceContoller.java +++ b/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/DummyResourceContoller.java @@ -239,7 +239,7 @@ public void assertDummyResourceSchemaSanityExtended(ResourceSchema resourceSchem assertDummyResourceSchemaSanity(resourceSchema, resourceType); ObjectClassComplexTypeDefinition accountDef = resourceSchema.findDefaultObjectClassDefinition(ShadowKindType.ACCOUNT); - assertEquals("Unexpected number of defnitions", 16, accountDef.getDefinitions().size()); + assertEquals("Unexpected number of defnitions", 17, accountDef.getDefinitions().size()); ResourceAttributeDefinition treasureDef = accountDef.findAttributeDefinition(DUMMY_ACCOUNT_ATTRIBUTE_TREASURE_NAME); assertFalse("Treasure IS returned by default and should not be", treasureDef.isReturnedByDefault()); } diff --git a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestTrafo.java b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestTrafo.java index ffa425662f0..25c0b51ebb0 100644 --- a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestTrafo.java +++ b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestTrafo.java @@ -127,6 +127,7 @@ public class TestTrafo extends AbstractStoryTest { public static final String NS_TRAFO_EXT = "http://midpoint.evolveum.com/xml/ns/story/trafo/ext"; private static final File TRAFO_SCHEMA_EXTENSION_FILE = new File(TEST_DIR, "extension.xsd"); private static final QName TRAFO_EXTENSION_HOMEDIR_QNAME = new QName(NS_TRAFO_EXT, "homedir"); + private static final QName TRAFO_EXTENSION_UID_QNAME = new QName(NS_TRAFO_EXT, "uid"); private static final ItemPath TRAFO_EXTENSION_HOMEDIR_PATH = new ItemPath(UserType.F_EXTENSION, TRAFO_EXTENSION_HOMEDIR_QNAME); private static final String TRAFO_MAIL_DOMAIN = "trafo.xx"; @@ -232,6 +233,7 @@ public void initSystem(Task initTask, OperationResult initResult) throws Excepti dummyResourceCtlAd.setResource(resourceDummyAd); dummyResourceCtlMail = DummyResourceContoller.create(RESOURCE_DUMMY_MAIL_ID, resourceDummyMail); + dummyResourceCtlMail.populateWithDefaultSchema(); DummyObjectClass dummyAdAccountObjectClass = dummyResourceCtlMail.getDummyResource().getAccountObjectClass(); dummyResourceCtlMail.addAttrDef(dummyAdAccountObjectClass, DUMMY_ACCOUNT_ATTRIBUTE_MAIL_FIRST_NAME_NAME, String.class, false, false); dummyResourceCtlMail.addAttrDef(dummyAdAccountObjectClass, DUMMY_ACCOUNT_ATTRIBUTE_MAIL_LAST_NAME_NAME, String.class, false, false); @@ -622,7 +624,7 @@ public void test129JackAccountMailGone() throws Exception { display("Audit", dummyAuditService); dummyAuditService.assertRecords(2); dummyAuditService.assertSimpleRecordSanity(); - dummyAuditService.assertExecutionDeltas(2); + dummyAuditService.assertExecutionDeltas(3); dummyAuditService.asserHasDelta(ChangeType.MODIFY, UserType.class); dummyAuditService.asserHasDelta(ChangeType.DELETE, ShadowType.class); dummyAuditService.assertExecutionSuccess(); @@ -692,6 +694,7 @@ public void test150JackAssignRoleEmployee() throws Exception { assertDummyAccountAttribute(RESOURCE_DUMMY_AD_ID, ACCOUNT_JACK_AD_DN, DummyResourceContoller.DUMMY_ACCOUNT_ATTRIBUTE_AD_TELEPHONE_NUMBER_NAME, "555-1234"); + // MAIL ACCOUNT // Check shadow @@ -724,11 +727,18 @@ public void test150JackAssignRoleEmployee() throws Exception { DUMMY_ACCOUNT_ATTRIBUTE_MAIL_MAIL_FILE_NAME_NAME, "mail\\"+USER_JACK_USERNAME); assertDummyAccountAttribute(RESOURCE_DUMMY_MAIL_ID, ACCOUNT_JACK_MAIL_USERNAME, DUMMY_ACCOUNT_ATTRIBUTE_MAIL_MAIL_DOMAIN_NAME, "TRAFO"); - + assertDummyAccountAttributeGenerated(RESOURCE_DUMMY_MAIL_ID, ACCOUNT_JACK_MAIL_USERNAME); + + PrismProperty generatedValue = userJack.findExtensionItem(TRAFO_EXTENSION_UID_QNAME); + assertNotNull("Generated id value must not be null", generatedValue); + // Set by inbound mappings PrismAsserts.assertPropertyValue(userJack, UserType.F_EMAIL_ADDRESS, "Jack.Sparrow@" + TRAFO_MAIL_DOMAIN); PrismAsserts.assertPropertyValue(userJack, new ItemPath(UserType.F_EXTENSION, TRAFO_EXTENSION_HOMEDIR_QNAME), "c:\\install\\test-id-folder"); + // set to AD from mail resource - attribute was generated by mail resource and synced to the AD + assertDummyAccountAttribute(RESOURCE_DUMMY_AD_ID, ACCOUNT_JACK_AD_DN, + DummyResourceContoller.DUMMY_ACCOUNT_ATTRIBUTE_AD_DESCRIPTION_NAME, String.valueOf(generatedValue.getRealValue())); // Check audit display("Audit", dummyAuditService); @@ -738,7 +748,7 @@ public void test150JackAssignRoleEmployee() throws Exception { dummyAuditService.assertExecutionDeltas(0,3); dummyAuditService.asserHasDelta(0,ChangeType.MODIFY, UserType.class); // primary, link (2 deltas) dummyAuditService.asserHasDelta(0,ChangeType.ADD, ShadowType.class); // AD account - dummyAuditService.assertExecutionDeltas(1,2); + dummyAuditService.assertExecutionDeltas(1,3); dummyAuditService.asserHasDelta(1,ChangeType.MODIFY, UserType.class); // link dummyAuditService.asserHasDelta(1,ChangeType.ADD, ShadowType.class); // Mail account dummyAuditService.assertExecutionDeltas(2,2); diff --git a/testing/story/src/test/resources/schema/trafo.xsd b/testing/story/src/test/resources/schema/trafo.xsd index 742e55353d7..5333780bacb 100644 --- a/testing/story/src/test/resources/schema/trafo.xsd +++ b/testing/story/src/test/resources/schema/trafo.xsd @@ -37,6 +37,13 @@ + + + + true + + + diff --git a/testing/story/src/test/resources/trafo/resource-dummy-ad.xml b/testing/story/src/test/resources/trafo/resource-dummy-ad.xml index 0ff09830624..db6dceedfe1 100644 --- a/testing/story/src/test/resources/trafo/resource-dummy-ad.xml +++ b/testing/story/src/test/resources/trafo/resource-dummy-ad.xml @@ -319,6 +319,15 @@ if (basic.stringify(employeeType) == 'T' || basic.stringify(employeeType) == 'R' $user/title + + extension/trafo:uid + extensionUid + + + + weak @@ -377,6 +386,7 @@ midPoint --> relaxed 10 + true 10 diff --git a/testing/story/src/test/resources/trafo/resource-dummy-mail.xml b/testing/story/src/test/resources/trafo/resource-dummy-mail.xml index 3a5cdd268c8..94792385537 100644 --- a/testing/story/src/test/resources/trafo/resource-dummy-mail.xml +++ b/testing/story/src/test/resources/trafo/resource-dummy-mail.xml @@ -48,6 +48,7 @@ mail true uuid + true @@ -187,6 +188,16 @@ basic.norm(basic.stringify(familyName))?.replaceAll(/\w+/, { it[0].toUpperCase() $user/familyName + + + + ri:internalId + Generated ID by resource + + + $user/extension/trafo:uid + + ri:ShortName From c258841dfe04849e4b2fa8c35d7e0c6c3367a7a9 Mon Sep 17 00:00:00 2001 From: "Katarina Valalikova (katkav)" Date: Thu, 2 Oct 2014 09:27:49 +0200 Subject: [PATCH 03/19] improving searching conflicting shadow (already exists situation) --- .../impl/ObjectAlreadyExistHandler.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/consistency/impl/ObjectAlreadyExistHandler.java b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/consistency/impl/ObjectAlreadyExistHandler.java index 6f0375b0a92..400e58b1e88 100644 --- a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/consistency/impl/ObjectAlreadyExistHandler.java +++ b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/consistency/impl/ObjectAlreadyExistHandler.java @@ -17,6 +17,7 @@ package com.evolveum.midpoint.provisioning.consistency.impl; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import javax.xml.namespace.QName; @@ -38,7 +39,9 @@ import com.evolveum.midpoint.provisioning.ucf.api.GenericFrameworkException; import com.evolveum.midpoint.schema.ResultHandler; import com.evolveum.midpoint.schema.constants.SchemaConstants; +import com.evolveum.midpoint.schema.processor.ResourceAttribute; import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.schema.util.ShadowUtil; import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.util.QNameUtil; import com.evolveum.midpoint.util.exception.CommunicationException; @@ -120,8 +123,15 @@ public T handleError(T shadow, FailedOperation op, Except private ObjectQuery createQueryByIcfName(ShadowType shadow) throws SchemaException { // TODO: error handling TODO TODO TODO set matching rule instead of null in equlas filter - PrismProperty nameProperty = shadow.getAttributes().asPrismContainerValue() - .findProperty(new QName(SchemaConstants.NS_ICF_SCHEMA, "name")); + Collection> secondaryIdentifiers = ShadowUtil.getSecondaryIdentifiers(shadow); + PrismProperty nameProperty = null; + if (secondaryIdentifiers.size() != 1){ + nameProperty = shadow.getAttributes().asPrismContainerValue() + .findProperty(new QName(SchemaConstants.NS_ICF_SCHEMA, "name")); + } else { + nameProperty = secondaryIdentifiers.iterator().next(); + } + EqualFilter nameFilter = EqualFilter.createEqual(new ItemPath(ShadowType.F_ATTRIBUTES, nameProperty.getDefinition().getName()),nameProperty); RefFilter resourceRefFilter = RefFilter.createReferenceEqual(ShadowType.F_RESOURCE_REF, ShadowType.class, prismContext, shadow.getResourceRef().getOid()); From fefc840422692d46008d366dcd7f8973ec2d5cc8 Mon Sep 17 00:00:00 2001 From: Erik Suta Date: Thu, 2 Oct 2014 14:22:19 +0200 Subject: [PATCH 04/19] Adding tooltip information to dumpInterval input field - shows value type (minutes) --- .../component/LoggingConfigPanel.html | 2 + .../component/LoggingConfigPanel.java | 48 ++++++++++--------- .../component/LoggingConfigPanel.properties | 2 + .../component/SystemConfigPanel.java | 3 -- 4 files changed, 29 insertions(+), 26 deletions(-) diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/component/LoggingConfigPanel.html b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/component/LoggingConfigPanel.html index 69890a0cde0..7e69a3c32e1 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/component/LoggingConfigPanel.html +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/component/LoggingConfigPanel.html @@ -120,6 +120,8 @@

+ + diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/component/LoggingConfigPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/component/LoggingConfigPanel.java index f6a022a1894..c0eda5b04da 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/component/LoggingConfigPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/component/LoggingConfigPanel.java @@ -20,7 +20,6 @@ import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.web.component.AjaxButton; -import com.evolveum.midpoint.web.component.DropDownMultiChoice; import com.evolveum.midpoint.web.component.data.TablePanel; import com.evolveum.midpoint.web.component.data.column.*; import com.evolveum.midpoint.web.component.input.DropDownChoicePanel; @@ -31,8 +30,8 @@ import com.evolveum.midpoint.web.component.util.ListDataProvider; import com.evolveum.midpoint.web.component.util.LoadableModel; import com.evolveum.midpoint.web.component.util.SimplePanel; -import com.evolveum.midpoint.web.page.admin.configuration.PageSystemConfiguration; import com.evolveum.midpoint.web.page.admin.configuration.dto.*; +import com.evolveum.midpoint.web.util.InfoTooltipBehavior; import com.evolveum.midpoint.web.util.WebMiscUtil; import com.evolveum.midpoint.xml.ns._public.common.common_3.*; @@ -45,13 +44,12 @@ import org.apache.wicket.behavior.AttributeAppender; import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn; import org.apache.wicket.extensions.markup.html.repeater.data.table.ISortableDataProvider; +import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.form.*; import org.apache.wicket.model.AbstractReadOnlyModel; import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; import org.apache.wicket.model.PropertyModel; -import org.w3c.dom.html.HTMLTableElement; - import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -64,7 +62,6 @@ public class LoggingConfigPanel extends SimplePanel { private static final String DOT_CLASS = LoggingConfigPanel.class.getName() + "."; private static final String OPERATION_LOAD_LOGGING_CONFIGURATION = DOT_CLASS + "loadLoggingConfiguration"; - private static final String OPERATION_UPDATE_LOGGING_CONFIGURATION = DOT_CLASS + "updateLoggingConfiguration"; private static final String ID_LOGGERS_TABLE = "loggersTable"; private static final String ID_ROOT_LEVEL = "rootLevel"; @@ -74,6 +71,7 @@ public class LoggingConfigPanel extends SimplePanel { private static final String ID_BUTTON_ADD_FILE_APPENDER = "addFileAppender"; private static final String ID_BUTTON_DELETE_APPENDER = "deleteAppender"; private static final String ID_BUTTON_ADD_STANDARD_LOGGER = "addStandardLogger"; + private static final String ID_DUMP_INTERVAL_TOOLTIP = "dumpIntervalTooltip"; public LoggingConfigPanel(String id) { super(id, null); @@ -130,9 +128,9 @@ protected void initLayout() { private void initLoggers() { initRoot(); - ISortableDataProvider provider = new ListDataProvider(this, + ISortableDataProvider provider = new ListDataProvider<>(this, new PropertyModel>(getModel(), "loggers")); - TablePanel table = new TablePanel(ID_LOGGERS_TABLE, provider, initLoggerColumns()); + TablePanel table = new TablePanel<>(ID_LOGGERS_TABLE, provider, initLoggerColumns()); table.setOutputMarkupId(true); table.setShowPaging(false); add(table); @@ -181,13 +179,13 @@ public void onClick(AjaxRequestTarget target) { } private void initRoot() { - DropDownChoice rootLevel = new DropDownChoice(ID_ROOT_LEVEL, + DropDownChoice rootLevel = new DropDownChoice<>(ID_ROOT_LEVEL, new PropertyModel(getModel(), LoggingDto.F_ROOT_LEVEL), WebMiscUtil.createReadonlyModelFromEnum(LoggingLevelType.class)); add(rootLevel); - DropDownChoice rootAppender = new DropDownChoice(ID_ROOT_APPENDER, + DropDownChoice rootAppender = new DropDownChoice<>(ID_ROOT_APPENDER, new PropertyModel(getModel(), LoggingDto.F_ROOT_APPENDER), createAppendersListModel()); rootAppender.setNullValid(true); rootAppender.add(new OnChangeAjaxBehavior() { @@ -207,7 +205,7 @@ private void initAudit(){ CheckBox auditDetails = new CheckBox("auditDetails", new PropertyModel(getModel(), "auditDetails")); add(auditDetails); - DropDownChoice auditAppender = new DropDownChoice("auditAppender", new PropertyModel( + DropDownChoice auditAppender = new DropDownChoice<>("auditAppender", new PropertyModel( getModel(), "auditAppender"), createAppendersListModel()); auditAppender.setNullValid(true); add(auditAppender); @@ -215,13 +213,13 @@ private void initAudit(){ private void initProfiling(){ //Entry-Exit profiling init - DropDownChoice profilingLevel = new DropDownChoice("profilingLevel", + DropDownChoice profilingLevel = new DropDownChoice<>("profilingLevel", new PropertyModel(getModel(), "profilingLevel"), WebMiscUtil.createReadonlyModelFromEnum(ProfilingLevel.class), - new EnumChoiceRenderer(this)); + new EnumChoiceRenderer(this)); add(profilingLevel); - DropDownChoice profilingAppender = new DropDownChoice("profilingAppender", + DropDownChoice profilingAppender = new DropDownChoice<>("profilingAppender", new PropertyModel(getModel(), "profilingAppender"), createAppendersListModel()); profilingAppender.setNullValid(true); add(profilingAppender); @@ -246,9 +244,13 @@ private void initProfiling(){ add(subsystemTaskManager); add(subsystemWorkflow); - TextField dumpInterval = new TextField("dumpInterval", new PropertyModel(getModel(), + TextField dumpInterval = new TextField<>("dumpInterval", new PropertyModel(getModel(), "dumpInterval")); add(dumpInterval); + + Label dumpIntervalTooltip = new Label(ID_DUMP_INTERVAL_TOOLTIP); + dumpIntervalTooltip.add(new InfoTooltipBehavior()); + add(dumpIntervalTooltip); } private void addStandardLoggerPerformed(AjaxRequestTarget target){ @@ -287,7 +289,7 @@ private TablePanel getAppendersTable(){ } private List> initLoggerColumns() { - List> columns = new ArrayList>(); + List> columns = new ArrayList<>(); IColumn column = new CheckBoxHeaderColumn(); columns.add(column); @@ -342,7 +344,7 @@ public String getIdValue(LoggingComponentType item, int index) { return dropDownChoicePanel; } else { - TextPanel textPanel = new TextPanel(componentId, new PropertyModel(model, getPropertyExpression())); + TextPanel textPanel = new TextPanel<>(componentId, new PropertyModel(model, getPropertyExpression())); FormComponent input = textPanel.getBaseFormComponent(); input.add(new AttributeAppender("style", "width: 100%")); input.add(new EmptyOnBlurAjaxFormUpdatingBehaviour()); @@ -415,7 +417,7 @@ protected String load() { @Override protected InputPanel createInputPanel(String componentId, IModel model) { IModel> options = new Model(null); - ListMultipleChoicePanel panel = new ListMultipleChoicePanel(componentId, + ListMultipleChoicePanel panel = new ListMultipleChoicePanel<>(componentId, new PropertyModel>(model, getPropertyExpression()), createNewLoggerAppendersListModel(), new IChoiceRenderer() { @@ -454,7 +456,7 @@ private IModel> createNewLoggerAppendersListModel(){ @Override public List getObject() { - List list = new ArrayList(); + List list = new ArrayList<>(); LoggingDto dto = getModel().getObject(); @@ -476,7 +478,7 @@ private IModel> createAppendersListModel() { @Override public List getObject() { - List list = new ArrayList(); + List list = new ArrayList<>(); LoggingDto dto = getModel().getObject(); for (AppenderConfiguration appender : dto.getAppenders()) { @@ -500,10 +502,10 @@ private void deleteLoggerPerformed(AjaxRequestTarget target) { } private void initAppenders(){ - ISortableDataProvider provider = new ListDataProvider( + ISortableDataProvider provider = new ListDataProvider<>( this, new PropertyModel>(getModel(), LoggingDto.F_APPENDERS)); - TablePanel table = new TablePanel(ID_TABLE_APPENDERS, provider, initAppenderColumns()); + TablePanel table = new TablePanel<>(ID_TABLE_APPENDERS, provider, initAppenderColumns()); table.setOutputMarkupId(true); table.setShowPaging(false); add(table); @@ -593,7 +595,7 @@ protected InputPanel createInputPanel(String componentId, IModel model) { @Override protected InputPanel createInputPanel(String componentId, IModel model) { - TextPanel panel = new TextPanel(componentId, new PropertyModel(model, getPropertyExpression())); + TextPanel panel = new TextPanel<>(componentId, new PropertyModel(model, getPropertyExpression())); FormComponent component = panel.getBaseFormComponent(); component.add(new AttributeModifier("size", 5)); component.add(new EmptyOnBlurAjaxFormUpdatingBehaviour()); @@ -608,7 +610,7 @@ protected InputPanel createInputPanel(String componentId, IModel model) { @Override protected InputPanel createInputPanel(String componentId, IModel model) { - TextPanel panel = new TextPanel(componentId, new PropertyModel(model, + TextPanel panel = new TextPanel<>(componentId, new PropertyModel(model, getPropertyExpression())); FormComponent component = panel.getBaseFormComponent(); component.add(new AttributeModifier("size", 5)); diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/component/LoggingConfigPanel.properties b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/component/LoggingConfigPanel.properties index b6b967b65bf..0d7f741e3db 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/component/LoggingConfigPanel.properties +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/component/LoggingConfigPanel.properties @@ -63,6 +63,8 @@ LoggingConfigPanel.profiling.dumpInterval=Dump interval LoggingConfigPanel.profiling.dumpInterval.placeholder=Dump interval LoggingConfigPanel.profiling.entryExit=Profiling entry/exit +LoggingConfigPanel.profiling.dumpInterval.tooltip=Specify value in minutes (Default is 30 min.) + StandardLoggerType.MAPPING=Mapping (c.e.m.common.mapping.Mapping) StandardLoggerType.EXPRESSION=Expression (c.e.m.common.expression.Expression) StandardLoggerType.SCRIPT_EXPRESSION=Script expression (c.e.m.common.expression.script.ScriptExpression) diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/component/SystemConfigPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/component/SystemConfigPanel.java index 7f13b35290f..a067ec19f60 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/component/SystemConfigPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/component/SystemConfigPanel.java @@ -16,8 +16,6 @@ package com.evolveum.midpoint.web.page.admin.configuration.component; -import com.evolveum.midpoint.util.logging.Trace; -import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.web.component.ObjectPolicyConfigurationEditor; import com.evolveum.midpoint.web.component.form.DropDownFormGroup; import com.evolveum.midpoint.web.component.util.SimplePanel; @@ -35,7 +33,6 @@ import org.apache.wicket.markup.html.form.TextField; import org.apache.wicket.markup.html.form.CheckBox; import org.apache.wicket.markup.html.form.PasswordTextField; -import org.apache.wicket.markup.html.form.IChoiceRenderer; import org.apache.wicket.markup.html.form.EnumChoiceRenderer; import org.apache.wicket.model.IModel; import org.apache.wicket.model.PropertyModel; From 47bc4e6e27b22cb70bb6956a5fc8a047d5936912 Mon Sep 17 00:00:00 2001 From: Erik Suta Date: Thu, 2 Oct 2014 14:23:36 +0200 Subject: [PATCH 05/19] Resource Wizard bugFix - Synchronization Editor - fix for correlation filterClause serialization and deserialization --- .../component/input/SearchFilterPanel.html | 2 +- .../input/dto/SearchFilterTypeDto.java | 13 ++++------ .../ns/_public/query_3/SearchFilterType.java | 25 +++++++++++++++++++ 3 files changed, 31 insertions(+), 9 deletions(-) diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/input/SearchFilterPanel.html b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/input/SearchFilterPanel.html index 3df821c4095..6fbfa9a6b01 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/input/SearchFilterPanel.html +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/input/SearchFilterPanel.html @@ -42,7 +42,7 @@
- +
diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/input/dto/SearchFilterTypeDto.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/input/dto/SearchFilterTypeDto.java index 7ef5804debc..cc78730dfb8 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/input/dto/SearchFilterTypeDto.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/input/dto/SearchFilterTypeDto.java @@ -56,13 +56,12 @@ public SearchFilterTypeDto(SearchFilterType filter, PrismContext prismContext){ } private String loadFilterClause(PrismContext prismContext){ - MapXNode clause = filterObject.getFilterClauseXNode(); String fClause; try { - //TODO - fix the problem with RootElement - RootXNode rootClause = new RootXNode(new QName("fixMe"), clause); - fClause = prismContext.serializeXNodeToString(rootClause, PrismContext.LANG_XML); + RootXNode clause = filterObject.getFilterClauseAsRootXNode(); + + fClause = prismContext.serializeXNodeToString(clause, PrismContext.LANG_XML); } catch (SchemaException e){ LoggingUtils.logException(LOGGER, "Could not load filterClause from SearchFilterType object.", e); @@ -84,11 +83,9 @@ public void updateFilterClause(PrismContext context) throws SchemaException{ LOGGER.trace("Filter Clause to serialize: " + filterClause); } - XNode filterClauseNode = context.parseToXNode(filterClause, PrismContext.LANG_XML); + RootXNode filterClauseNode = (RootXNode) context.parseToXNode(filterClause, PrismContext.LANG_XML); - MapXNode newClause = new MapXNode(); - newClause.setParent(filterClauseNode); - filterObject.setFilterClauseXNode(newClause); + filterObject.setFilterClauseXNode(filterClauseNode); } } diff --git a/infra/prism/src/main/java/com/evolveum/prism/xml/ns/_public/query_3/SearchFilterType.java b/infra/prism/src/main/java/com/evolveum/prism/xml/ns/_public/query_3/SearchFilterType.java index 51a3cdb91fc..7846eae9180 100644 --- a/infra/prism/src/main/java/com/evolveum/prism/xml/ns/_public/query_3/SearchFilterType.java +++ b/infra/prism/src/main/java/com/evolveum/prism/xml/ns/_public/query_3/SearchFilterType.java @@ -46,6 +46,7 @@ import com.evolveum.midpoint.prism.util.PrismUtil; import com.evolveum.midpoint.prism.xnode.MapXNode; import com.evolveum.midpoint.prism.xnode.PrimitiveXNode; +import com.evolveum.midpoint.prism.xnode.RootXNode; import com.evolveum.midpoint.prism.xnode.XNode; import com.evolveum.midpoint.util.DOMUtil; import com.evolveum.midpoint.util.DebugDumpable; @@ -126,6 +127,15 @@ public void setFilterClauseXNode(MapXNode filterClauseXNode) { this.filterClauseXNode = filterClauseXNode; } + public void setFilterClauseXNode(RootXNode filterClauseNode) { + if (filterClauseNode == null) { + this.filterClauseXNode = null; + } else { + this.filterClauseXNode = new MapXNode(); + this.filterClauseXNode.put(filterClauseNode.getRootElementName(), filterClauseNode.getSubnode()); + } + } + @Deprecated // use the version without prismContext instead public MapXNode getFilterClauseXNode(PrismContext prismContext) throws SchemaException { return getFilterClauseXNode(); @@ -139,6 +149,20 @@ public MapXNode getFilterClauseXNode() { } } + public RootXNode getFilterClauseAsRootXNode() throws SchemaException { + MapXNode clause = getFilterClauseXNode(); + if (clause == null) { + return null; + } + + Entry singleEntry = clause.getSingleSubEntry("getFilterClauseAsRootXNode"); + if (singleEntry == null) { + return null; + } + + return new RootXNode(singleEntry.getKey(), singleEntry.getValue()); + } + public Element getFilterClauseAsElement() throws SchemaException { if (filterClauseXNode == null) { return null; @@ -672,4 +696,5 @@ public String debugDump(int indent) { } return sb.toString(); } + } From 87c5d5362c14cc0687db58181ccb07477a049c17 Mon Sep 17 00:00:00 2001 From: Pavol Mederly Date: Thu, 2 Oct 2014 17:28:34 +0200 Subject: [PATCH 06/19] Fixed a couple of issues preventing schemadist from running. --- .../tools/schemadist/SchemaDistMojo.java | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/tools/schema-dist-maven-plugin/src/main/java/com/evolveum/midpoint/tools/schemadist/SchemaDistMojo.java b/tools/schema-dist-maven-plugin/src/main/java/com/evolveum/midpoint/tools/schemadist/SchemaDistMojo.java index bd25a14dbb2..a4e2309db10 100644 --- a/tools/schema-dist-maven-plugin/src/main/java/com/evolveum/midpoint/tools/schemadist/SchemaDistMojo.java +++ b/tools/schema-dist-maven-plugin/src/main/java/com/evolveum/midpoint/tools/schemadist/SchemaDistMojo.java @@ -203,7 +203,7 @@ public void execute() throws MojoExecutionException, MojoFailureException { for (ArtifactItem artifactItem: artifactItems) { Artifact artifact = artifactItem.getArtifact(); getLog().info( "SchemaDist unpacking artifact " + artifact); - File workDir = new File(workDirectory, artifact.toString()); + File workDir = new File(workDirectory, artifact.getArtifactId()); initializeOutDir(workDir); artifactItem.setWorkDir(workDir); unpack(artifactItem, workDir); @@ -215,7 +215,18 @@ public void execute() throws MojoExecutionException, MojoFailureException { Catalog catalog = new Catalog(catalogManager); catalog.setupReaders(); try { - catalog.parseCatalog(catalogFile.getPath()); + // UGLY HACK. On Windows, file names like d:\abc\def\catalog.xml eventually get treated very strangely + // (resulting in names like "file:d:\abc\def\catalog.xml" that are obviously wrong) + // Prefixing such names with "file:/" helps. + String prefix; + if (catalogFile.isAbsolute() && !catalogFile.getPath().startsWith("/")) { + prefix = "/"; + } else { + prefix = ""; + } + String fileName = "file:" + prefix + catalogFile.getPath(); + getLog().debug("Calling parseCatalog with: " + fileName); + catalog.parseCatalog(fileName); } catch (MalformedURLException e) { throw new MojoExecutionException("Error parsing catalog file "+catalogPath+" in artifact "+artifact, e); } catch (IOException e) { @@ -340,7 +351,11 @@ private void processWsdl(Path filePath, File workDir, File outDir) throws MojoEx private String resolveSchemaLocation(String namespace, Path filePath, File workDir) throws MojoExecutionException, IOException { for(ArtifactItem artifactItem: artifactItems) { Catalog catalog = artifactItem.getResolveCatalog(); - String resolvedString = catalog.resolveEntity(filePath.toString(), namespace, namespace); + String publicId = namespace; + if (publicId.endsWith("#")) { + publicId = publicId.substring(0, publicId.length()-1); + } + String resolvedString = catalog.resolveEntity(filePath.toString(), publicId, publicId); if (resolvedString != null) { getLog().debug("-------------------"); getLog().debug("Resolved namespace "+namespace+" to "+resolvedString+" using catalog "+catalog); From c02ba2a2e0d8d2ed5a5c2b3d3974992337f1f528 Mon Sep 17 00:00:00 2001 From: Pavol Mederly Date: Thu, 2 Oct 2014 17:54:19 +0200 Subject: [PATCH 07/19] Upgrading CXF to 3.0.1.e2 (fixes problems with generated WSDL). --- build-system/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build-system/pom.xml b/build-system/pom.xml index e1e4881b4cc..257bd306589 100644 --- a/build-system/pom.xml +++ b/build-system/pom.xml @@ -45,7 +45,7 @@ 2.0.1 2.6 1.2 - 3.0.1.e1 + 3.0.1.e2 3.0.1 2.4.7 2.2.9 From 2c1c0203126956d68ac8fb8e9107eb748b4d30fc Mon Sep 17 00:00:00 2001 From: Pavol Mederly Date: Thu, 2 Oct 2014 18:29:38 +0200 Subject: [PATCH 08/19] Fixing MID-2045 (add changes text formatter for generalNotifier). --- .../schema/constants/SchemaConstants.java | 1 + .../impl/notifiers/GeneralNotifier.java | 16 ++++++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) 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 42f46d1b5b7..06a2a88c0e0 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 @@ -209,6 +209,7 @@ public abstract class SchemaConstants { public static final QName SE_EXECUTE_SCRIPT = new QName(SCRIPTING_EXTENSION_NS, "executeScript"); public static final QName C_EVENT = new QName(NS_C, "event"); + public static final QName C_TEXT_FORMATTER = new QName(NS_C, "textFormatter"); public static final QName C_TRANSPORT_NAME = new QName(NS_C, "transportName"); public static final QName C_FROM = new QName(NS_C, "from"); diff --git a/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/notifiers/GeneralNotifier.java b/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/notifiers/GeneralNotifier.java index f5e2d001587..f46c4dbb609 100644 --- a/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/notifiers/GeneralNotifier.java +++ b/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/notifiers/GeneralNotifier.java @@ -49,6 +49,7 @@ import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; import static com.evolveum.midpoint.model.api.ProgressInformation.ActivityType.NOTIFICATIONS; @@ -74,7 +75,7 @@ public class GeneralNotifier extends BaseHandler { @Autowired protected AggregatedEventHandler aggregatedEventHandler; - protected static final List auxiliaryPaths = Arrays.asList( + protected static final List auxiliaryPaths = Collections.unmodifiableList(Arrays.asList( new ItemPath(ShadowType.F_METADATA), new ItemPath(ShadowType.F_ACTIVATION, ActivationType.F_VALIDITY_STATUS), // works for user activation as well new ItemPath(ShadowType.F_ACTIVATION, ActivationType.F_VALIDITY_CHANGE_TIMESTAMP), @@ -85,7 +86,7 @@ public class GeneralNotifier extends BaseHandler { new ItemPath(ShadowType.F_ITERATION), new ItemPath(ShadowType.F_ITERATION_TOKEN), new ItemPath(UserType.F_LINK_REF), - new ItemPath(ShadowType.F_TRIGGER) + new ItemPath(ShadowType.F_TRIGGER)) ); @@ -339,4 +340,15 @@ private String formatPath(ItemDelta itemDelta) { } return sb.toString(); } + + @Override + protected ExpressionVariables getDefaultVariables(Event event, OperationResult result) { + ExpressionVariables variables = super.getDefaultVariables(event, result); + variables.addVariableDefinition(SchemaConstants.C_TEXT_FORMATTER, textFormatter); + return variables; + } + + public static List getAuxiliaryPaths() { + return auxiliaryPaths; + } } From a20ecdb7e7c199885517b8cecb276aaf2fa911dd Mon Sep 17 00:00:00 2001 From: Pavol Mederly Date: Thu, 2 Oct 2014 22:02:23 +0200 Subject: [PATCH 09/19] SimpleFocalObjectNotifier and FocusType filter (MID-2044). --- .../xml/ns/public/common/common-3.xsd | 20 +- .../model/api/context/ModelContext.java | 3 + .../notifications/api/events/ModelEvent.java | 37 +++- .../impl/formatters/TextFormatter.java | 1 + .../impl/handlers/AggregatedEventHandler.java | 10 + .../impl/helpers/FocusTypeFilterHelper.java | 68 +++++++ .../notifiers/SimpleFocalObjectNotifier.java | 188 ++++++++++++++++++ .../impl/notifiers/SimpleUserNotifier.java | 126 +----------- .../impl/notifiers/UserPasswordNotifier.java | 13 +- 9 files changed, 335 insertions(+), 131 deletions(-) create mode 100644 model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/helpers/FocusTypeFilterHelper.java create mode 100644 model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/notifiers/SimpleFocalObjectNotifier.java diff --git a/infra/schema/src/main/resources/xml/ns/public/common/common-3.xsd b/infra/schema/src/main/resources/xml/ns/public/common/common-3.xsd index 65438f27272..fa265764157 100644 --- a/infra/schema/src/main/resources/xml/ns/public/common/common-3.xsd +++ b/infra/schema/src/main/resources/xml/ns/public/common/common-3.xsd @@ -8784,7 +8784,6 @@ Focus types supported by this handler. (Default: all) Types not listed are filtered out: not handled by this handler nor any of its successors. (Relevant only for model-generated events.) - NOT IMPLEMENTED YET. @@ -8816,6 +8815,13 @@ + + + + TODO + + + @@ -9075,6 +9081,18 @@ + + + TODO + + + + + + + + + TODO diff --git a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/context/ModelContext.java b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/context/ModelContext.java index 6a19a6be091..4281eaed521 100644 --- a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/context/ModelContext.java +++ b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/context/ModelContext.java @@ -20,6 +20,7 @@ import com.evolveum.midpoint.common.refinery.ResourceShadowDiscriminator; import com.evolveum.midpoint.model.api.ProgressInformation; +import com.evolveum.midpoint.prism.PrismContext; import com.evolveum.midpoint.util.DebugDumpable; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; @@ -40,4 +41,6 @@ public interface ModelContext extends Serializable, DebugD Class getFocusClass(); void reportProgress(ProgressInformation progress); + + PrismContext getPrismContext(); // use with care } diff --git a/model/notifications-api/src/main/java/com/evolveum/midpoint/notifications/api/events/ModelEvent.java b/model/notifications-api/src/main/java/com/evolveum/midpoint/notifications/api/events/ModelEvent.java index 7550bfabc93..6fa8d6f7e84 100644 --- a/model/notifications-api/src/main/java/com/evolveum/midpoint/notifications/api/events/ModelEvent.java +++ b/model/notifications-api/src/main/java/com/evolveum/midpoint/notifications/api/events/ModelEvent.java @@ -19,6 +19,8 @@ import com.evolveum.midpoint.model.api.context.ModelContext; import com.evolveum.midpoint.model.api.context.ModelElementContext; import com.evolveum.midpoint.model.api.context.ModelProjectionContext; +import com.evolveum.midpoint.prism.PrismContainerDefinition; +import com.evolveum.midpoint.prism.PrismContext; import com.evolveum.midpoint.prism.delta.ChangeType; import com.evolveum.midpoint.prism.delta.ObjectDelta; import com.evolveum.midpoint.schema.ObjectDeltaOperation; @@ -29,8 +31,9 @@ import com.evolveum.midpoint.xml.ns._public.common.common_3.EventCategoryType; import com.evolveum.midpoint.xml.ns._public.common.common_3.EventOperationType; import com.evolveum.midpoint.xml.ns._public.common.common_3.EventStatusType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.FocusType; +import javax.xml.namespace.QName; import java.util.ArrayList; import java.util.List; @@ -140,10 +143,10 @@ public boolean isCategoryType(EventCategoryType eventCategoryType) { return eventCategoryType == EventCategoryType.MODEL_EVENT; } - public List> getUserDeltas() { - List> retval = new ArrayList>(); + public List> getFocusDeltas() { + List> retval = new ArrayList<>(); Class c = modelContext.getFocusClass(); - if (c != null && UserType.class.isAssignableFrom(c)) { + if (c != null && FocusType.class.isAssignableFrom(c)) { for (Object o : getFocusExecutedDeltas()) { ObjectDeltaOperation objectDeltaOperation = (ObjectDeltaOperation) o; retval.add(objectDeltaOperation.getObjectDelta()); @@ -152,7 +155,29 @@ public List> getUserDeltas() { return retval; } - public ObjectDelta getSummarizedUserDeltas() throws SchemaException { - return ObjectDelta.summarize(getUserDeltas()); + public ObjectDelta getSummarizedFocusDeltas() throws SchemaException { + return ObjectDelta.summarize(getFocusDeltas()); + } + + public boolean hasFocusOfType(Class clazz) { + return clazz.isAssignableFrom(getFocusContext().getObjectTypeClass()); + } + + public boolean hasFocusOfType(QName focusType) { + PrismContext prismContext = getModelContext().getPrismContext(); + if (prismContext == null) { + throw new IllegalStateException("No prismContext in model context"); + } + PrismContainerDefinition pcd = prismContext.getSchemaRegistry().findContainerDefinitionByType(focusType); + if (pcd == null) { + LOGGER.warn("Couldn't find definition for type " + focusType); + return false; + } + Class expectedClass = pcd.getCompileTimeClass(); + if (expectedClass == null) { + LOGGER.warn("Couldn't find class for type " + focusType); + return false; + } + return hasFocusOfType(expectedClass); } } diff --git a/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/formatters/TextFormatter.java b/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/formatters/TextFormatter.java index 3dba4cb25a5..bae7a6ea59d 100644 --- a/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/formatters/TextFormatter.java +++ b/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/formatters/TextFormatter.java @@ -178,6 +178,7 @@ private void formatContainerValue(StringBuilder sb, String prefix, PrismContaine String prefixSubContainer = prefix + " "; formatContainerValue(sb, prefixSubContainer, subContainerValue, mightBeRemoved, hiddenPaths, showOperationalAttributes); } + sb.append("\n"); } else { sb.append("Unexpected Item type: "); sb.append(item); diff --git a/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/handlers/AggregatedEventHandler.java b/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/handlers/AggregatedEventHandler.java index 368d4dd74ba..a9f3fd7c37c 100644 --- a/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/handlers/AggregatedEventHandler.java +++ b/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/handlers/AggregatedEventHandler.java @@ -22,6 +22,7 @@ import com.evolveum.midpoint.notifications.impl.helpers.CategoryFilterHelper; import com.evolveum.midpoint.notifications.impl.helpers.ChainHelper; import com.evolveum.midpoint.notifications.impl.helpers.ExpressionFilterHelper; +import com.evolveum.midpoint.notifications.impl.helpers.FocusTypeFilterHelper; import com.evolveum.midpoint.notifications.impl.helpers.ForkHelper; import com.evolveum.midpoint.notifications.impl.helpers.KindIntentFilterHelper; import com.evolveum.midpoint.notifications.impl.helpers.OperationFilterHelper; @@ -29,6 +30,7 @@ import com.evolveum.midpoint.notifications.impl.notifiers.AccountPasswordNotifier; import com.evolveum.midpoint.notifications.impl.notifiers.GeneralNotifier; import com.evolveum.midpoint.notifications.impl.notifiers.SimpleResourceObjectNotifier; +import com.evolveum.midpoint.notifications.impl.notifiers.SimpleFocalObjectNotifier; import com.evolveum.midpoint.notifications.impl.notifiers.SimpleUserNotifier; import com.evolveum.midpoint.notifications.impl.notifiers.SimpleWorkflowNotifier; import com.evolveum.midpoint.notifications.impl.notifiers.UserPasswordNotifier; @@ -71,6 +73,9 @@ public class AggregatedEventHandler extends BaseHandler { @Autowired private KindIntentFilterHelper kindIntentFilter; + @Autowired + private FocusTypeFilterHelper focusTypeFilterHelper; + @Autowired private ExpressionFilterHelper expressionFilter; @@ -80,6 +85,9 @@ public class AggregatedEventHandler extends BaseHandler { @Autowired private ForkHelper forkHelper; + @Autowired + protected SimpleFocalObjectNotifier simpleFocalObjectNotifier; + @Autowired protected SimpleUserNotifier simpleUserNotifier; @@ -114,11 +122,13 @@ public boolean processEvent(Event event, EventHandlerType eventHandlerType, Noti operationFilter.processEvent(event, eventHandlerType, notificationManager, task, result) && statusFilter.processEvent(event, eventHandlerType, notificationManager, task, result) && kindIntentFilter.processEvent(event, eventHandlerType, notificationManager, task, result) && + focusTypeFilterHelper.processEvent(event, eventHandlerType, notificationManager, task, result) && expressionFilter.processEvent(event, eventHandlerType, notificationManager, task, result) && chainHelper.processEvent(event, eventHandlerType, notificationManager, task, result) && forkHelper.processEvent(event, eventHandlerType, notificationManager, task, result); shouldContinue = shouldContinue && processNotifiers(event, eventHandlerType.getSimpleUserNotifier(), notificationManager, task, result); + shouldContinue = shouldContinue && processNotifiers(event, eventHandlerType.getSimpleFocalObjectNotifier(), notificationManager, task, result); shouldContinue = shouldContinue && processNotifiers(event, eventHandlerType.getSimpleResourceObjectNotifier(), notificationManager, task, result); shouldContinue = shouldContinue && processNotifiers(event, eventHandlerType.getSimpleWorkflowNotifier(), notificationManager, task, result); shouldContinue = shouldContinue && processNotifiers(event, eventHandlerType.getUserPasswordNotifier(), notificationManager, task, result); diff --git a/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/helpers/FocusTypeFilterHelper.java b/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/helpers/FocusTypeFilterHelper.java new file mode 100644 index 00000000000..343ece6b195 --- /dev/null +++ b/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/helpers/FocusTypeFilterHelper.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2010-2014 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.evolveum.midpoint.notifications.impl.helpers; + +import com.evolveum.midpoint.notifications.api.NotificationManager; +import com.evolveum.midpoint.notifications.api.events.Event; +import com.evolveum.midpoint.notifications.api.events.ModelEvent; +import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.task.api.Task; +import com.evolveum.midpoint.util.logging.Trace; +import com.evolveum.midpoint.util.logging.TraceManager; +import com.evolveum.midpoint.xml.ns._public.common.common_3.EventHandlerType; +import org.springframework.stereotype.Component; + +import javax.xml.namespace.QName; + +/** + * @author mederly + */ +@Component +public class FocusTypeFilterHelper extends BaseHelper { + + private static final Trace LOGGER = TraceManager.getTrace(FocusTypeFilterHelper.class); + + @Override + public boolean processEvent(Event event, EventHandlerType eventHandlerType, NotificationManager notificationManager, + Task task, OperationResult result) { + + if (eventHandlerType.getFocusType().isEmpty()) { + return true; + } + + if (!(event instanceof ModelEvent)) { + return true; // or should we return false? + } + ModelEvent modelEvent = (ModelEvent) event; + + logStart(LOGGER, event, eventHandlerType, eventHandlerType.getStatus()); + + boolean retval = false; + + for (QName focusType : eventHandlerType.getFocusType()) { + if (focusType == null) { + LOGGER.warn("Filtering on null focusType; filter = " + eventHandlerType); + } else if (modelEvent.hasFocusOfType(focusType)) { + retval = true; + break; + } + } + + logEnd(LOGGER, event, eventHandlerType, retval); + return retval; + } +} diff --git a/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/notifiers/SimpleFocalObjectNotifier.java b/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/notifiers/SimpleFocalObjectNotifier.java new file mode 100644 index 00000000000..a5915d3ffc3 --- /dev/null +++ b/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/notifiers/SimpleFocalObjectNotifier.java @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2010-2013 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.evolveum.midpoint.notifications.impl.notifiers; + +import com.evolveum.midpoint.model.api.context.ModelContext; +import com.evolveum.midpoint.model.api.context.ModelElementContext; +import com.evolveum.midpoint.notifications.api.events.Event; +import com.evolveum.midpoint.notifications.api.events.ModelEvent; +import com.evolveum.midpoint.prism.PrismObject; +import com.evolveum.midpoint.prism.delta.ObjectDelta; +import com.evolveum.midpoint.prism.path.ItemPath; +import com.evolveum.midpoint.prism.polystring.PolyString; +import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.util.exception.SchemaException; +import com.evolveum.midpoint.util.logging.Trace; +import com.evolveum.midpoint.util.logging.TraceManager; +import com.evolveum.midpoint.xml.ns._public.common.common_3.*; + +import org.apache.commons.lang.StringUtils; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * @author mederly + */ +@Component +public class SimpleFocalObjectNotifier extends GeneralNotifier { + + private static final Trace LOGGER = TraceManager.getTrace(SimpleFocalObjectNotifier.class); + + @PostConstruct + public void init() { + register(SimpleFocalObjectNotifierType.class); + } + + @Override + protected boolean quickCheckApplicability(Event event, GeneralNotifierType generalNotifierType, OperationResult result) { + if (!(event instanceof ModelEvent)) { + LOGGER.trace("{} is not applicable for this kind of event, continuing in the handler chain; event class = {}", getClass().getSimpleName(), event.getClass()); + return false; + } + ModelEvent modelEvent = (ModelEvent) event; + if (modelEvent.getFocusContext() == null || !FocusType.class.isAssignableFrom(modelEvent.getFocusContext().getObjectTypeClass())) { + LOGGER.trace("{} is not applicable to non-focus related model operations, continuing in the handler chain", getClass().getSimpleName()); + return false; + } + return true; + } + + @Override + protected boolean checkApplicability(Event event, GeneralNotifierType generalNotifierType, OperationResult result) { + List> deltas = ((ModelEvent) event).getFocusDeltas(); + if (deltas.isEmpty()) { + return false; + } + + if (isWatchAuxiliaryAttributes(generalNotifierType)) { + return true; + } + + for (ObjectDelta delta : deltas) { + if (!delta.isModify() || deltaContainsOtherPathsThan(delta, auxiliaryPaths)) { + return true; + } + } + + return false; + } + + @Override + protected String getSubject(Event event, GeneralNotifierType generalNotifierType, String transport, OperationResult result) { + + String typeName = getFocusTypeName(event); + + if (event.isAdd()) { + return typeName + " creation notification"; + } else if (event.isModify()) { + return typeName + " modification notification"; + } else if (event.isDelete()) { + return typeName + " deletion notification"; + } else { + return "(unknown " + typeName.toLowerCase() + " operation)"; + } + } + + // assuming the quick availability check was passed + private String getFocusTypeName(Event event) { + String simpleName = ((ModelEvent) event).getFocusContext().getObjectTypeClass().getSimpleName(); + return StringUtils.substringBeforeLast(simpleName, "Type"); // should usually work ;) + } + + @Override + protected String getBody(Event event, GeneralNotifierType generalNotifierType, String transport, OperationResult result) throws SchemaException { + + String typeName = getFocusTypeName(event); + String typeNameLower = typeName.toLowerCase(); + + boolean techInfo = Boolean.TRUE.equals(generalNotifierType.isShowTechnicalInformation()); + + ModelContext modelContext = (ModelContext) ((ModelEvent) event).getModelContext(); + ModelElementContext focusContext = modelContext.getFocusContext(); + PrismObject focus = focusContext.getObjectNew() != null ? focusContext.getObjectNew() : focusContext.getObjectOld(); + FocusType userType = focus.asObjectable(); + String oid = focusContext.getOid(); + + String fullName; + if (userType instanceof UserType) { + fullName = PolyString.getOrig(((UserType) userType).getFullName()); + } else if (userType instanceof AbstractRoleType) { + fullName = PolyString.getOrig(((AbstractRoleType) userType).getDisplayName()); + } else { + fullName = ""; // TODO (currently it's not possible to get here) + } + + ObjectDelta delta = ObjectDelta.summarize(((ModelEvent) event).getFocusDeltas()); + + StringBuilder body = new StringBuilder(); + + String status; + if (event.isSuccess()) { + status = "SUCCESS"; + } else if (event.isOnlyFailure()) { + status = "FAILURE"; + } else if (event.isFailure()) { + status = "PARTIAL FAILURE"; + } else if (event.isInProgress()) { + status = "IN PROGRESS"; + } else { + status = "UNKNOWN"; + } + + String attemptedTo = event.isSuccess() ? "" : "(attempted to be) "; + + body.append("Notification about ").append(typeNameLower).append("-related operation (status: " + status + ")\n\n"); + body.append(typeName).append(": " + fullName + " (" + userType.getName() + ", oid " + oid + ")\n"); + body.append("Notification created on: " + new Date() + "\n\n"); + + List hiddenPaths = isWatchAuxiliaryAttributes(generalNotifierType) ? new ArrayList() : auxiliaryPaths; + if (delta.isAdd()) { + body.append("The ").append(typeNameLower).append(" record was " + attemptedTo + "created with the following data:\n"); + body.append(textFormatter.formatObject(delta.getObjectToAdd(), hiddenPaths, isWatchAuxiliaryAttributes(generalNotifierType))); + body.append("\n"); + } else if (delta.isModify()) { + body.append("The ").append(typeNameLower).append(" record was " + attemptedTo + "modified. Modified attributes are:\n"); + body.append(textFormatter.formatObjectModificationDelta(delta, hiddenPaths, isWatchAuxiliaryAttributes(generalNotifierType))); + body.append("\n"); + } else if (delta.isDelete()) { + body.append("The ").append(typeNameLower).append(" record was " + attemptedTo + "removed.\n\n"); + } + + if (!event.isSuccess()) { + body.append("More information about the status of the request was displayed and/or is present in log files.\n\n"); + } + + if (techInfo) { + body.append("----------------------------------------\n"); + body.append("Technical information:\n\n"); + body.append(modelContext.debugDump(2)); + } + + return body.toString(); + } + + @Override + protected Trace getLogger() { + return LOGGER; + } + +} diff --git a/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/notifiers/SimpleUserNotifier.java b/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/notifiers/SimpleUserNotifier.java index ff822cad675..b60c9167492 100644 --- a/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/notifiers/SimpleUserNotifier.java +++ b/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/notifiers/SimpleUserNotifier.java @@ -1,11 +1,11 @@ /* - * Copyright (c) 2010-2013 Evolveum + * Copyright (c) 2010-2014 Evolveum * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,32 +16,23 @@ package com.evolveum.midpoint.notifications.impl.notifiers; -import com.evolveum.midpoint.model.api.context.ModelContext; -import com.evolveum.midpoint.model.api.context.ModelElementContext; import com.evolveum.midpoint.notifications.api.events.Event; import com.evolveum.midpoint.notifications.api.events.ModelEvent; -import com.evolveum.midpoint.prism.PrismObject; -import com.evolveum.midpoint.prism.delta.ObjectDelta; -import com.evolveum.midpoint.prism.path.ItemPath; import com.evolveum.midpoint.schema.result.OperationResult; -import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; -import com.evolveum.midpoint.xml.ns._public.common.common_3.*; - +import com.evolveum.midpoint.xml.ns._public.common.common_3.GeneralNotifierType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.SimpleUserNotifierType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; - /** * @author mederly */ @Component -public class SimpleUserNotifier extends GeneralNotifier { +public class SimpleUserNotifier extends SimpleFocalObjectNotifier { private static final Trace LOGGER = TraceManager.getTrace(SimpleUserNotifier.class); @@ -52,115 +43,14 @@ public void init() { @Override protected boolean quickCheckApplicability(Event event, GeneralNotifierType generalNotifierType, OperationResult result) { - if (!(event instanceof ModelEvent)) { - LOGGER.trace("SimpleUserNotifier is not applicable for this kind of event, continuing in the handler chain; event class = " + event.getClass()); - return false; - } - ModelEvent modelEvent = (ModelEvent) event; - if (modelEvent.getFocusContext() == null || !UserType.class.isAssignableFrom(modelEvent.getFocusContext().getObjectTypeClass())) { - LOGGER.trace("SimpleUserNotifier is not applicable to non-user related model operations, continuing in the handler chain"); - return false; - } - return true; - } - - @Override - protected boolean checkApplicability(Event event, GeneralNotifierType generalNotifierType, OperationResult result) { - List> deltas = ((ModelEvent) event).getUserDeltas(); - if (deltas.isEmpty()) { + if (!super.quickCheckApplicability(event, generalNotifierType, result)) { return false; } - - if (isWatchAuxiliaryAttributes(generalNotifierType)) { - return true; - } - - for (ObjectDelta delta : deltas) { - if (!delta.isModify() || deltaContainsOtherPathsThan(delta, auxiliaryPaths)) { - return true; - } - } - - return false; - } - - @Override - protected String getSubject(Event event, GeneralNotifierType generalNotifierType, String transport, OperationResult result) { - - if (event.isAdd()) { - return "User creation notification"; - } else if (event.isModify()) { - return "User modification notification"; - } else if (event.isDelete()) { - return "User deletion notification"; - } else { - return "(unknown user operation)"; - } - } - - @Override - protected String getBody(Event event, GeneralNotifierType generalNotifierType, String transport, OperationResult result) throws SchemaException { - - boolean techInfo = Boolean.TRUE.equals(generalNotifierType.isShowTechnicalInformation()); - - ModelContext modelContext = (ModelContext) ((ModelEvent) event).getModelContext(); - ModelElementContext focusContext = modelContext.getFocusContext(); - PrismObject user = focusContext.getObjectNew() != null ? focusContext.getObjectNew() : focusContext.getObjectOld(); - UserType userType = user.asObjectable(); - String oid = focusContext.getOid(); - - ObjectDelta delta = ObjectDelta.summarize(((ModelEvent) event).getUserDeltas()); - - StringBuilder body = new StringBuilder(); - - String status; - if (event.isSuccess()) { - status = "SUCCESS"; - } else if (event.isOnlyFailure()) { - status = "FAILURE"; - } else if (event.isFailure()) { - status = "PARTIAL FAILURE"; - } else if (event.isInProgress()) { - status = "IN PROGRESS"; - } else { - status = "UNKNOWN"; - } - - String attemptedTo = event.isSuccess() ? "" : "(attempted to be) "; - - body.append("Notification about user-related operation (status: " + status + ")\n\n"); - body.append("User: " + userType.getFullName() + " (" + userType.getName() + ", oid " + oid + ")\n"); - body.append("Notification created on: " + new Date() + "\n\n"); - - List hiddenPaths = isWatchAuxiliaryAttributes(generalNotifierType) ? new ArrayList() : auxiliaryPaths; - if (delta.isAdd()) { - body.append("The user record was " + attemptedTo + "created with the following data:\n"); - body.append(textFormatter.formatObject(delta.getObjectToAdd(), hiddenPaths, isWatchAuxiliaryAttributes(generalNotifierType))); - body.append("\n"); - } else if (delta.isModify()) { - body.append("The user record was " + attemptedTo + "modified. Modified attributes are:\n"); - body.append(textFormatter.formatObjectModificationDelta(delta, hiddenPaths, isWatchAuxiliaryAttributes(generalNotifierType))); - body.append("\n"); - } else if (delta.isDelete()) { - body.append("The user record was " + attemptedTo + "removed.\n\n"); - } - - if (!event.isSuccess()) { - body.append("More information about the status of the request was displayed and/or is present in log files.\n\n"); - } - - if (techInfo) { - body.append("----------------------------------------\n"); - body.append("Technical information:\n\n"); - body.append(modelContext.debugDump(2)); - } - - return body.toString(); + return UserType.class.isAssignableFrom(((ModelEvent) event).getFocusContext().getObjectTypeClass()); } @Override protected Trace getLogger() { return LOGGER; } - } diff --git a/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/notifiers/UserPasswordNotifier.java b/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/notifiers/UserPasswordNotifier.java index 0799a010c68..c3282afcedd 100644 --- a/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/notifiers/UserPasswordNotifier.java +++ b/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/notifiers/UserPasswordNotifier.java @@ -27,6 +27,7 @@ import com.evolveum.midpoint.util.logging.LoggingUtils; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; +import com.evolveum.midpoint.xml.ns._public.common.common_3.FocusType; import com.evolveum.midpoint.xml.ns._public.common.common_3.GeneralNotifierType; import com.evolveum.midpoint.xml.ns._public.common.common_3.UserPasswordNotifierType; import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; @@ -59,7 +60,7 @@ public void init() { @Override protected boolean quickCheckApplicability(Event event, GeneralNotifierType generalNotifierType, OperationResult result) { - if (!(event instanceof ModelEvent)) { + if (!(event instanceof ModelEvent) || !((ModelEvent) event).hasFocusOfType(UserType.class)) { LOGGER.trace("UserPasswordNotifier is not applicable for this kind of event, continuing in the handler chain; event class = " + event.getClass()); return false; } else { @@ -76,11 +77,11 @@ protected boolean checkApplicability(Event event, GeneralNotifierType generalNot } ModelEvent modelEvent = (ModelEvent) event; - if (modelEvent.getUserDeltas().isEmpty()) { + if (modelEvent.getFocusDeltas().isEmpty()) { LOGGER.trace("No user deltas in event, exiting."); return false; } - if (getPasswordFromDeltas(modelEvent.getUserDeltas()) != null) { + if (getPasswordFromDeltas(modelEvent.getFocusDeltas()) != null) { LOGGER.trace("Found password in user delta(s), continuing."); return true; } else { @@ -89,9 +90,9 @@ protected boolean checkApplicability(Event event, GeneralNotifierType generalNot } } - private String getPasswordFromDeltas(List> deltas) { + private String getPasswordFromDeltas(List> deltas) { try { - return midpointFunctions.getPlaintextUserPasswordFromDeltas(deltas); + return midpointFunctions.getPlaintextUserPasswordFromDeltas((List) deltas); } catch (EncryptionException e) { LoggingUtils.logException(LOGGER, "Couldn't decrypt password from user deltas: {}", e, DebugUtil.debugDump(deltas)); return null; @@ -107,7 +108,7 @@ protected String getSubject(Event event, GeneralNotifierType generalNotifierType protected String getBody(Event event, GeneralNotifierType generalNotifierType, String transport, OperationResult result) { ModelEvent modelEvent = (ModelEvent) event; - List> deltas = modelEvent.getUserDeltas(); + List> deltas = modelEvent.getFocusDeltas(); return "Password for user " + notificationsUtil.getObjectType(event.getRequestee(), result).getName() + " is: " + getPasswordFromDeltas(deltas); } From 1daa59654ac59646a50aa73d7c58fd08b49cc2f7 Mon Sep 17 00:00:00 2001 From: Erik Suta Date: Fri, 3 Oct 2014 10:07:53 +0200 Subject: [PATCH 10/19] Resource Wizard update: - Fixed bug with incorrect and mapping handling - improving getting information label for mappings in wizard - small fix for condition labels in correlation editor --- .../assignment/AssignmentTablePanel.java | 8 ++--- .../input/ExpressionEditorPanel.html | 4 +-- .../input/ExpressionEditorPanel.java | 22 +++++++++++++ .../input/ExpressionEditorPanel.properties | 2 +- .../ResourceActivationEditor.java | 21 ++++++++++-- .../ResourceAssociationEditor.java | 9 +++-- .../ResourceAttributeEditor.java | 33 +++++++++++++++++-- .../ResourceCredentialsEditor.java | 9 +++-- .../ConditionalSearchFilterEditor.java | 10 ++++++ .../ConditionalSearchFilterEditor.properties | 4 ++- .../wizard/resource/dto/MappingTypeDto.java | 6 ++++ .../security/MidPointApplication.properties | 3 +- 12 files changed, 112 insertions(+), 19 deletions(-) diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentTablePanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentTablePanel.java index 8f5646564b6..c2c0fda2168 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentTablePanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentTablePanel.java @@ -101,7 +101,7 @@ public List getAssignmentTypeList(){ } public List loadFromAssignmentTypeList(List asgList, OperationResult result){ - List list = new ArrayList(); + List list = new ArrayList<>(); for (AssignmentType assignment : asgList) { ObjectType targetObject = null; @@ -221,7 +221,7 @@ public ObjectQuery getProviderQuery(){ return null; } else { ObjectQuery query = new ObjectQuery(); - List oids = new ArrayList(); + List oids = new ArrayList<>(); oids.add(getExcludeOid()); ObjectFilter oidFilter = InOidFilter.createInOid(oids); @@ -253,7 +253,7 @@ public void yesPerformed(AjaxRequestTarget target){ } private List createAssignmentMenu(){ - List items = new ArrayList(); + List items = new ArrayList<>(); InlineMenuItem item = new InlineMenuItem(createStringResource("AssignmentTablePanel.menu.assign"), new InlineMenuItemAction(){ @@ -300,7 +300,7 @@ public void onClick(AjaxRequestTarget target) { } private List getSelectedAssignments(){ - List selected = new ArrayList(); + List selected = new ArrayList<>(); List all = assignmentModel.getObject(); diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/input/ExpressionEditorPanel.html b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/input/ExpressionEditorPanel.html index 74113fb83f9..aa6a1b3ebf9 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/input/ExpressionEditorPanel.html +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/input/ExpressionEditorPanel.html @@ -20,7 +20,7 @@
- +
@@ -47,7 +47,7 @@
- +
diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/input/ExpressionEditorPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/input/ExpressionEditorPanel.java index a84964ecbcb..e1ad66dcefd 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/input/ExpressionEditorPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/input/ExpressionEditorPanel.java @@ -36,6 +36,7 @@ import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior; import org.apache.wicket.ajax.markup.html.AjaxLink; import org.apache.wicket.markup.html.WebMarkupContainer; +import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.form.DropDownChoice; import org.apache.wicket.markup.html.form.EnumChoiceRenderer; import org.apache.wicket.markup.html.form.IChoiceRenderer; @@ -66,6 +67,8 @@ public class ExpressionEditorPanel extends SimplePanel{ private static final String ID_LANGUAGE_CONTAINER = "languageContainer"; private static final String ID_POLICY_CONTAINER = "policyRefContainer"; private static final String ID_BUTTON_UPDATE = "update"; + private static final String ID_LABEL_TYPE = "typeLabel"; + private static final String ID_LABEL_EXPRESSION = "expressionLabel"; private IModel model; private Map policyMap = new HashMap<>(); @@ -94,6 +97,9 @@ protected ExpressionTypeDto load() { protected void initLayout(){ loadModel(); + Label typeLabel = new Label(ID_LABEL_TYPE, createStringResource(getTypeLabelKey())); + add(typeLabel); + DropDownChoice type = new DropDownChoice<>(ID_TYPE, new PropertyModel(model, ExpressionTypeDto.F_TYPE), WebMiscUtil.createReadonlyModelFromEnum(ExpressionUtil.ExpressionEvaluatorType.class), @@ -180,6 +186,9 @@ protected void onUpdate(AjaxRequestTarget target) { policyRef.setNullValid(true); policyContainer.add(policyRef); + Label expressionLabel = new Label(ID_LABEL_EXPRESSION, createStringResource(getExpressionLabelKey())); + add(expressionLabel); + TextArea expression = new TextArea<>(ID_EXPRESSION, new PropertyModel(model, ExpressionTypeDto.F_EXPRESSION)); expression.setOutputMarkupId(true); add(expression); @@ -250,4 +259,17 @@ public void performExpressionHook(AjaxRequestTarget target){ } + /** + * Provide key for expression type label + * */ + public String getTypeLabelKey(){ + return "ExpressionEditorPanel.label.type"; + } + + /** + * Provide key for expression label + * */ + public String getExpressionLabelKey(){ + return "ExpressionEditorPanel.label.expression"; + } } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/input/ExpressionEditorPanel.properties b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/input/ExpressionEditorPanel.properties index c0581680787..bb1b1076045 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/input/ExpressionEditorPanel.properties +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/input/ExpressionEditorPanel.properties @@ -15,7 +15,7 @@ # ExpressionEditorPanel.label.type=Expression Type -ExpressionEditorPanel.label.language=Expression Language +ExpressionEditorPanel.label.language=Language ExpressionEditorPanel.label.valuePolicyRef=Policy Ref. ExpressionEditorPanel.label.expression=Expression ExpressionEditorPanel.button.expressionSave=Update Expression diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/resource/component/schemahandling/ResourceActivationEditor.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/resource/component/schemahandling/ResourceActivationEditor.java index ed9bc602e07..378766b0eab 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/resource/component/schemahandling/ResourceActivationEditor.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/resource/component/schemahandling/ResourceActivationEditor.java @@ -24,6 +24,7 @@ import com.evolveum.midpoint.xml.ns._public.common.common_3.MappingType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceActivationDefinitionType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceBidirectionalMappingType; +import org.apache.commons.lang.StringUtils; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow; import org.apache.wicket.markup.html.form.DropDownChoice; @@ -119,7 +120,17 @@ protected IModel createTextModel(final IModel model) { @Override public String getObject() { - return model.getObject().getName(); + MappingType mapping = model.getObject(); + + if(mapping == null){ + return null; + } + + if(mapping.getName() != null && StringUtils.isNotEmpty(mapping.getName())){ + return mapping.getName(); + } else { + return getString("MultiValueField.nameNotSpecified"); + } } }; } @@ -147,10 +158,14 @@ protected IModel createTextModel(final IModel model) { public String getObject() { MappingType mapping = model.getObject(); - if(mapping != null){ + if(mapping == null){ + return null; + } + + if(mapping.getName() != null && StringUtils.isNotEmpty(mapping.getName())){ return mapping.getName(); } else { - return null; + return getString("MultiValueField.nameNotSpecified"); } } }; diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/resource/component/schemahandling/ResourceAssociationEditor.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/resource/component/schemahandling/ResourceAssociationEditor.java index c3fd7569a1a..7ce51098326 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/resource/component/schemahandling/ResourceAssociationEditor.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/resource/component/schemahandling/ResourceAssociationEditor.java @@ -35,6 +35,7 @@ import com.evolveum.midpoint.web.page.admin.resources.PageResources; import com.evolveum.midpoint.web.util.WebMiscUtil; import com.evolveum.midpoint.xml.ns._public.common.common_3.*; +import org.apache.commons.lang.StringUtils; import org.apache.wicket.RestartResponseException; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior; @@ -323,10 +324,14 @@ protected IModel createTextModel(final IModel model) { public String getObject() { MappingType mapping = model.getObject(); - if(mapping != null){ + if(mapping == null){ + return null; + } + + if(mapping.getName() != null && StringUtils.isNotEmpty(mapping.getName())){ return mapping.getName(); } else { - return null; + return getString("MultiValueField.nameNotSpecified"); } } }; diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/resource/component/schemahandling/ResourceAttributeEditor.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/resource/component/schemahandling/ResourceAttributeEditor.java index e92edc131d1..915b7126042 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/resource/component/schemahandling/ResourceAttributeEditor.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/resource/component/schemahandling/ResourceAttributeEditor.java @@ -33,6 +33,7 @@ import com.evolveum.midpoint.web.page.admin.resources.PageResources; import com.evolveum.midpoint.web.util.WebMiscUtil; import com.evolveum.midpoint.xml.ns._public.common.common_3.*; +import org.apache.commons.lang.StringUtils; import org.apache.wicket.RestartResponseException; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior; @@ -221,7 +222,29 @@ public String getIdValue(QName object, int index) { add(matchingRule); TextField outboundLabel = new TextField<>(ID_OUTBOUND_LABEL, - new PropertyModel(getModel(), "outbound.name")); + new AbstractReadOnlyModel() { + + @Override + public String getObject() { + ResourceAttributeDefinitionType attributeDefinition = getModel().getObject(); + + if(attributeDefinition == null){ + return null; + } + + MappingType outbound = attributeDefinition.getOutbound(); + + if(outbound == null){ + return null; + } + + if(outbound.getName() != null && StringUtils.isNotEmpty(outbound.getName())){ + return outbound.getName(); + } else { + return getString("MultiValueField.nameNotSpecified"); + } + } + }); outboundLabel.setEnabled(false); outboundLabel.setOutputMarkupId(true); add(outboundLabel); @@ -247,10 +270,14 @@ protected IModel createTextModel(final IModel model) { public String getObject() { MappingType mapping = model.getObject(); - if(mapping != null){ + if(mapping == null){ + return null; + } + + if(mapping.getName() != null && StringUtils.isNotEmpty(mapping.getName())){ return mapping.getName(); } else { - return null; + return getString("MultiValueField.nameNotSpecified"); } } }; diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/resource/component/schemahandling/ResourceCredentialsEditor.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/resource/component/schemahandling/ResourceCredentialsEditor.java index 355a67f12c2..a83f1590ce4 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/resource/component/schemahandling/ResourceCredentialsEditor.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/resource/component/schemahandling/ResourceCredentialsEditor.java @@ -28,6 +28,7 @@ import com.evolveum.midpoint.web.component.wizard.resource.component.schemahandling.modal.MappingEditorDialog; import com.evolveum.midpoint.web.util.WebMiscUtil; import com.evolveum.midpoint.xml.ns._public.common.common_3.*; +import org.apache.commons.lang.StringUtils; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.markup.html.form.AjaxSubmitLink; import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow; @@ -115,10 +116,14 @@ protected IModel createTextModel(final IModel model) { public String getObject() { MappingType mapping = model.getObject(); - if(mapping != null){ + if(mapping == null){ + return null; + } + + if(mapping.getName() != null && StringUtils.isNotEmpty(mapping.getName())){ return mapping.getName(); } else { - return null; + return getString("MultiValueField.nameNotSpecified"); } } }; diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/resource/component/synchronization/ConditionalSearchFilterEditor.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/resource/component/synchronization/ConditionalSearchFilterEditor.java index dbada75106e..611937c3707 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/resource/component/synchronization/ConditionalSearchFilterEditor.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/resource/component/synchronization/ConditionalSearchFilterEditor.java @@ -90,6 +90,16 @@ public void performExpressionHook(AjaxRequestTarget target){ ConditionalSearchFilterEditor.this.getModel().getObject().setCondition(expression); } } + + @Override + public String getTypeLabelKey() { + return "ConditionalSearchFilterEditor.condition.type.label"; + } + + @Override + public String getExpressionLabelKey() { + return "ConditionalSearchFilterEditor.condition.label"; + } }; add(expressionEditor); diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/resource/component/synchronization/ConditionalSearchFilterEditor.properties b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/resource/component/synchronization/ConditionalSearchFilterEditor.properties index f3ba48a819e..cc48b954e45 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/resource/component/synchronization/ConditionalSearchFilterEditor.properties +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/resource/component/synchronization/ConditionalSearchFilterEditor.properties @@ -15,4 +15,6 @@ # ConditionalSearchFilterEditor.label=Edit Synchronization Correlation -ConditionalSearchFilterEditor.description=Description \ No newline at end of file +ConditionalSearchFilterEditor.description=Description +ConditionalSearchFilterEditor.condition.type.label=Condition Type +ConditionalSearchFilterEditor.condition.label=Condition \ No newline at end of file diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/resource/dto/MappingTypeDto.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/resource/dto/MappingTypeDto.java index fb00b63f592..8c0d97dae62 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/resource/dto/MappingTypeDto.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/resource/dto/MappingTypeDto.java @@ -65,6 +65,12 @@ public class MappingTypeDto implements Serializable { public MappingTypeDto(MappingType mapping, PrismContext prismContext){ + if(mapping != null && mapping.equals(new MappingType())){ + mappingObject = mapping; + expression = ExpressionUtil.EXPRESSION_AS_IS; + expressionType = ExpressionUtil.ExpressionEvaluatorType.AS_IS; + } + if(mapping == null){ mappingObject = new MappingType(); } else { diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/security/MidPointApplication.properties b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/security/MidPointApplication.properties index 28902433c18..bac8df89fe8 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/security/MidPointApplication.properties +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/security/MidPointApplication.properties @@ -538,4 +538,5 @@ operation.com.evolveum.midpoint.model.controller.ModelController.searchObjects=S operation.com.evolveum.midpoint.model.impl.controller.ModelDiagController.repositorySelfTest.user=Repository self test, user (Model) operation.com.evolveum.midpoint.common.crypto.CryptoUtil.securitySelfTest=Security self test -TextField.universal.placeholder=Insert value \ No newline at end of file +TextField.universal.placeholder=Insert value +MultiValueField.nameNotSpecified=(Name not specified) \ No newline at end of file From ebd4500ef7be52f3ba9d98f335f5dcbd5eafa67a Mon Sep 17 00:00:00 2001 From: Pavol Mederly Date: Fri, 3 Oct 2014 11:06:51 +0200 Subject: [PATCH 11/19] MID-2047 (identifying changed container values). Fixed useless delete+add of tenantRef. Added a couple of display names to schema. --- .../assignment/AssignmentEditorDto.java | 1 + .../midpoint/prism/path/ItemPath.java | 30 ++- .../xml/ns/public/common/common-3.xsd | 16 ++ .../impl/formatters/TextFormatter.java | 225 ++++++++++++++---- .../notifiers/SimpleFocalObjectNotifier.java | 2 +- .../SimpleResourceObjectNotifier.java | 8 +- .../notifications/impl/TestTextFormatter.java | 112 +++++---- .../changes/user-jack-modification.xml | 43 ++-- .../src/test/resources/objects/user-jack.xml | 17 ++ 9 files changed, 340 insertions(+), 114 deletions(-) diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentEditorDto.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentEditorDto.java index a6667d6dee4..be164d60d98 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentEditorDto.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentEditorDto.java @@ -233,6 +233,7 @@ public PrismContainerValue getNewValue() throws SchemaException { } else { ObjectReferenceType ref = new ObjectReferenceType(); ref.setOid(this.tenantRef.getOid()); + ref.setType(OrgType.COMPLEX_TYPE); newAssignment.setTenantRef(ref); } } diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/path/ItemPath.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/path/ItemPath.java index 58a7d9aa8de..ed4b9139dbb 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/path/ItemPath.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/path/ItemPath.java @@ -211,10 +211,28 @@ public ItemPath allUpTo(ItemPathSegment segment) { if (i < 0) { return EMPTY_PATH; } else { - return new ItemPath(segments.subList(0, i-1)); + return new ItemPath(segments.subList(0, i)); } } + /** + * Returns a path containing all segments up to (including) the specified one; + * counted from backwards. + * If the segment is not present, returns empty path. + */ + public ItemPath allUpToIncluding(ItemPathSegment segment) { + int i = segments.lastIndexOf(segment); + if (i < 0) { + return EMPTY_PATH; + } else { + return allUpToIncluding(i); + } + } + + public ItemPath allUpToIncluding(int i) { + return new ItemPath(segments.subList(0, i+1)); + } + public int size() { return segments.size(); } @@ -277,6 +295,16 @@ public static boolean containsEquivalent(Collection paths, ItemPath pa return false; } + public static boolean containsSubpathOrEquivalent(Collection paths, ItemPath pathToBeFound) { + for (ItemPath path : paths) { + CompareResult r = pathToBeFound.compareComplex(path); + if (r == CompareResult.SUBPATH || r == CompareResult.EQUIVALENT) { + return true; + } + } + return false; + } + public enum CompareResult { EQUIVALENT, SUPERPATH, diff --git a/infra/schema/src/main/resources/xml/ns/public/common/common-3.xsd b/infra/schema/src/main/resources/xml/ns/public/common/common-3.xsd index fa265764157..1322670f293 100644 --- a/infra/schema/src/main/resources/xml/ns/public/common/common-3.xsd +++ b/infra/schema/src/main/resources/xml/ns/public/common/common-3.xsd @@ -764,6 +764,7 @@ true + Metadata @@ -1900,6 +1901,9 @@ a desired state of things (cf. linkRef).

+ + Assignment + @@ -2518,6 +2522,7 @@ + Assignment @@ -2543,6 +2548,7 @@ tns:targetRef + Target @@ -2552,6 +2558,9 @@ TODO: target ref + + Target + @@ -2560,6 +2569,9 @@ TODO + + Construction + @@ -2590,6 +2602,7 @@ tns:OrgType + Tenant reference @@ -6084,6 +6097,9 @@ TODO + + Inducement + diff --git a/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/formatters/TextFormatter.java b/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/formatters/TextFormatter.java index bae7a6ea59d..65a21f836d2 100644 --- a/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/formatters/TextFormatter.java +++ b/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/formatters/TextFormatter.java @@ -20,6 +20,7 @@ import com.evolveum.midpoint.prism.*; import com.evolveum.midpoint.prism.delta.ItemDelta; import com.evolveum.midpoint.prism.delta.ObjectDelta; +import com.evolveum.midpoint.prism.path.IdItemPathSegment; import com.evolveum.midpoint.prism.path.ItemPath; import com.evolveum.midpoint.prism.path.ItemPathSegment; import com.evolveum.midpoint.prism.path.NameItemPathSegment; @@ -59,10 +60,25 @@ public class TextFormatter { private static final Trace LOGGER = TraceManager.getTrace(TextFormatter.class); public String formatObjectModificationDelta(ObjectDelta objectDelta, List hiddenPaths, boolean showOperationalAttributes) { + return formatObjectModificationDelta(objectDelta, hiddenPaths, showOperationalAttributes, null, null); + } + // objectOld and objectNew are used for explaining changed container values, e.g. assignment[1]/tenantRef (see MID-2047) + // if null, they are ignored + public String formatObjectModificationDelta(ObjectDelta objectDelta, List hiddenPaths, boolean showOperationalAttributes, + PrismObject objectOld, PrismObject objectNew) { Validate.notNull(objectDelta, "objectDelta is null"); Validate.isTrue(objectDelta.isModify(), "objectDelta is not a modification delta"); + PrismObjectDefinition objectDefinition; + if (objectNew != null && objectNew.getDefinition() != null) { + objectDefinition = objectNew.getDefinition(); + } else if (objectOld != null && objectOld.getDefinition() != null) { + objectDefinition = objectOld.getDefinition(); + } else { + objectDefinition = null; + } + if (LOGGER.isTraceEnabled()) { LOGGER.trace("formatObjectModificationDelta: objectDelta = " + objectDelta.debugDump() + ", hiddenPaths = " + PrettyPrinter.prettyPrint(hiddenPaths)); } @@ -70,17 +86,68 @@ public String formatObjectModificationDelta(ObjectDelta ob StringBuilder retval = new StringBuilder(); List toBeDisplayed = filterAndOrderItemDeltas(objectDelta, hiddenPaths, showOperationalAttributes); - for (ItemDelta itemDelta : toBeDisplayed) { retval.append(" - "); - retval.append(getItemDeltaLabel(itemDelta)); + retval.append(getItemDeltaLabel(itemDelta, objectDefinition)); retval.append(":\n"); formatItemDeltaContent(retval, itemDelta, hiddenPaths, showOperationalAttributes); } + explainPaths(retval, toBeDisplayed, objectDefinition, objectOld, objectNew, hiddenPaths, showOperationalAttributes); + return retval.toString(); } + private void explainPaths(StringBuilder sb, List deltas, PrismObjectDefinition objectDefinition, PrismObject objectOld, PrismObject objectNew, List hiddenPaths, boolean showOperationalAttributes) { + if (objectOld == null && objectNew == null) { + return; // no data - no point in trying + } + boolean first = true; + List alreadyExplained = new ArrayList<>(); + for (ItemDelta itemDelta : deltas) { + ItemPath pathToExplain = getPathToExplain(itemDelta); + if (pathToExplain == null || ItemPath.containsSubpathOrEquivalent(alreadyExplained, pathToExplain)) { + continue; // null or already processed + } + PrismObject source = null; + Object item = null; + if (objectNew != null) { + item = objectNew.find(pathToExplain); + source = objectNew; + } + if (item == null && objectOld != null) { + item = objectOld.find(pathToExplain); + source = objectOld; + } + if (item == null) { + LOGGER.warn("Couldn't find {} in {} nor {}, no explanation could be created.", new Object[] {pathToExplain, objectNew, objectOld}); + continue; + } + if (first) { + sb.append("\nNotes:\n"); + first = false; + } + String label = getItemPathLabel(pathToExplain, itemDelta.getDefinition(), objectDefinition); + // the item should be a PrismContainerValue + if (item instanceof PrismContainerValue) { + sb.append(" - ").append(label).append(":\n"); + formatContainerValue(sb, " ", (PrismContainerValue) item, false, hiddenPaths, showOperationalAttributes); + } else { + LOGGER.warn("{} in {} was expected to be a PrismContainerValue; it is {} instead", new Object[]{pathToExplain, source, item.getClass()}); + if (item instanceof PrismContainer) { + formatPrismContainer(sb, " ", (PrismContainer) item, false, hiddenPaths, showOperationalAttributes); + } else if (item instanceof PrismReference) { + formatPrismReference(sb, " ", (PrismReference) item, false); + } else if (item instanceof PrismProperty) { + formatPrismProperty(sb, " ", (PrismProperty) item); + } else { + sb.append("Unexpected item: ").append(item).append("\n"); + } + } + alreadyExplained.add(pathToExplain); + } + } + private void formatItemDeltaContent(StringBuilder sb, ItemDelta itemDelta, List hiddenPaths, boolean showOperationalAttributes) { formatItemDeltaValues(sb, "ADD", itemDelta.getValuesToAdd(), false, hiddenPaths, showOperationalAttributes); formatItemDeltaValues(sb, "DELETE", itemDelta.getValuesToDelete(), true, hiddenPaths, showOperationalAttributes); @@ -93,7 +160,9 @@ private void formatItemDeltaValues(StringBuilder sb, String type, Collection toBeDisplayed = filterAndOrderItems(containerValue.getItems(), hiddenPaths, showOperationalAttributes); for (Item item : toBeDisplayed) { - sb.append(prefix); - sb.append(" - "); - sb.append(getItemLabel(item)); - sb.append(": "); if (item instanceof PrismProperty) { - if (item.size() > 1) { - for (PrismPropertyValue propertyValue : ((PrismProperty) item).getValues()) { - sb.append("\n"); - sb.append(prefix + " - "); - sb.append(ValueDisplayUtil.toStringValue(propertyValue)); - } - } else if (item.size() == 1) { - sb.append(ValueDisplayUtil.toStringValue(((PrismProperty) item).getValue(0))); - } - sb.append("\n"); + formatPrismProperty(sb, prefix, item); } else if (item instanceof PrismReference) { - if (item.size() > 1) { - for (PrismReferenceValue referenceValue : ((PrismReference) item).getValues()) { - sb.append("\n"); - sb.append(prefix + " - "); - sb.append(formatReferenceValue(referenceValue, mightBeRemoved)); - } - } else if (item.size() == 1) { - sb.append(formatReferenceValue(((PrismReference) item).getValue(0), mightBeRemoved)); - } - sb.append("\n"); + formatPrismReference(sb, prefix, item, mightBeRemoved); } else if (item instanceof PrismContainer) { - for (PrismContainerValue subContainerValue : ((PrismContainer) item).getValues()) { - sb.append("\n"); - String prefixSubContainer = prefix + " "; - formatContainerValue(sb, prefixSubContainer, subContainerValue, mightBeRemoved, hiddenPaths, showOperationalAttributes); - } - sb.append("\n"); + formatPrismContainer(sb, prefix, item, mightBeRemoved, hiddenPaths, showOperationalAttributes); } else { sb.append("Unexpected Item type: "); sb.append(item); @@ -188,6 +230,54 @@ private void formatContainerValue(StringBuilder sb, String prefix, PrismContaine } } + private void formatPrismContainer(StringBuilder sb, String prefix, Item item, boolean mightBeRemoved, List hiddenPaths, boolean showOperationalAttributes) { + for (PrismContainerValue subContainerValue : ((PrismContainer) item).getValues()) { + sb.append(prefix); + sb.append(" - "); + sb.append(getItemLabel(item)); + if (subContainerValue.getId() != null) { + sb.append(" #").append(subContainerValue.getId()); + } + sb.append(":\n"); + String prefixSubContainer = prefix + " "; + formatContainerValue(sb, prefixSubContainer, subContainerValue, mightBeRemoved, hiddenPaths, showOperationalAttributes); + } + } + + private void formatPrismReference(StringBuilder sb, String prefix, Item item, boolean mightBeRemoved) { + sb.append(prefix); + sb.append(" - "); + sb.append(getItemLabel(item)); + sb.append(": "); + if (item.size() > 1) { + for (PrismReferenceValue referenceValue : ((PrismReference) item).getValues()) { + sb.append("\n"); + sb.append(prefix + " - "); + sb.append(formatReferenceValue(referenceValue, mightBeRemoved)); + } + } else if (item.size() == 1) { + sb.append(formatReferenceValue(((PrismReference) item).getValue(0), mightBeRemoved)); + } + sb.append("\n"); + } + + private void formatPrismProperty(StringBuilder sb, String prefix, Item item) { + sb.append(prefix); + sb.append(" - "); + sb.append(getItemLabel(item)); + sb.append(": "); + if (item.size() > 1) { + for (PrismPropertyValue propertyValue : ((PrismProperty) item).getValues()) { + sb.append("\n"); + sb.append(prefix + " - "); + sb.append(ValueDisplayUtil.toStringValue(propertyValue)); + } + } else if (item.size() == 1) { + sb.append(ValueDisplayUtil.toStringValue(((PrismProperty) item).getValue(0))); + } + sb.append("\n"); + } + private String formatReferenceValue(PrismReferenceValue value, boolean mightBeRemoved) { OperationResult result = new OperationResult("dummy"); @@ -255,21 +345,62 @@ private String localPart(QName qname) { } // we call this on filtered list of item deltas - all of they have definition set - private String getItemDeltaLabel(ItemDelta itemDelta) { - if (itemDelta.getDefinition().getDisplayName() != null) { - return itemDelta.getDefinition().getDisplayName(); - } else { - String retval = ""; - for (ItemPathSegment segment : itemDelta.getPath().getSegments()) { - if (segment instanceof NameItemPathSegment) { - if (!retval.isEmpty()) { - retval += "/"; - } - retval += ((NameItemPathSegment) segment).getName().getLocalPart(); - } + private String getItemDeltaLabel(ItemDelta itemDelta, PrismObjectDefinition objectDefinition) { + return getItemPathLabel(itemDelta.getPath(), itemDelta.getDefinition(), objectDefinition); + } + + private String getItemPathLabel(ItemPath path, Definition deltaDefinition, PrismObjectDefinition objectDefinition) { + + NameItemPathSegment lastNamedSegment = path.lastNamed(); + + StringBuilder sb = new StringBuilder(); + for (ItemPathSegment segment : path.getSegments()) { + if (segment instanceof NameItemPathSegment) { + if (sb.length() > 0) { + sb.append("/"); + } + Definition itemDefinition; + if (objectDefinition == null) { + if (segment == lastNamedSegment) { // definition for last segment is the definition taken from delta + itemDefinition = deltaDefinition; // this may be null but we don't care + } else { + itemDefinition = null; // definitions for previous segments are unknown + } + } else { + // todo we could make this iterative (resolving definitions while walking down the path); but this is definitely simpler to implement and debug :) + itemDefinition = objectDefinition.findItemDefinition(path.allUpToIncluding(segment)); + } + if (itemDefinition != null && itemDefinition.getDisplayName() != null) { + sb.append(itemDefinition.getDisplayName()); + } else { + sb.append(((NameItemPathSegment) segment).getName().getLocalPart()); + } + } else if (segment instanceof IdItemPathSegment) { + sb.append("[").append(((IdItemPathSegment) segment).getId()).append("]"); } - return retval; } + return sb.toString(); + } + + // we call this on filtered list of item deltas - all of they have definition set + private ItemPath getPathToExplain(ItemDelta itemDelta) { + ItemPath path = itemDelta.getPath(); + + for (int i = 0; i < path.size(); i++) { + ItemPathSegment segment = path.getSegments().get(i); + if (segment instanceof IdItemPathSegment) { + if (i < path.size()-1 || itemDelta.isDelete()) { + return path.allUpToIncluding(i); + } else { + // this means that the path ends with [id] segment *and* the value(s) are + // only added and deleted, i.e. they are shown in the delta anyway + // (actually it is questionable whether path in delta can end with [id] segment, + // but we test for this case just to be sure) + return null; + } + } + } + return null; } private List filterAndOrderItemDeltas(ObjectDelta objectDelta, List hiddenPaths, boolean showOperationalAttributes) { @@ -302,7 +433,7 @@ public int compare(ItemDelta delta1, ItemDelta delta2) { return toBeDisplayed; } - // we call this on filtered list of items - all of they have definition set + // we call this on filtered list of items - all of them have definition set private String getItemLabel(Item item) { return item.getDefinition().getDisplayName() != null ? item.getDefinition().getDisplayName() : item.getElementName().getLocalPart(); diff --git a/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/notifiers/SimpleFocalObjectNotifier.java b/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/notifiers/SimpleFocalObjectNotifier.java index a5915d3ffc3..9b2d3dd59de 100644 --- a/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/notifiers/SimpleFocalObjectNotifier.java +++ b/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/notifiers/SimpleFocalObjectNotifier.java @@ -161,7 +161,7 @@ protected String getBody(Event event, GeneralNotifierType generalNotifierType, S body.append("\n"); } else if (delta.isModify()) { body.append("The ").append(typeNameLower).append(" record was " + attemptedTo + "modified. Modified attributes are:\n"); - body.append(textFormatter.formatObjectModificationDelta(delta, hiddenPaths, isWatchAuxiliaryAttributes(generalNotifierType))); + body.append(textFormatter.formatObjectModificationDelta(delta, hiddenPaths, isWatchAuxiliaryAttributes(generalNotifierType), focusContext.getObjectOld(), focusContext.getObjectNew())); body.append("\n"); } else if (delta.isDelete()) { body.append("The ").append(typeNameLower).append(" record was " + attemptedTo + "removed.\n\n"); diff --git a/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/notifiers/SimpleResourceObjectNotifier.java b/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/notifiers/SimpleResourceObjectNotifier.java index e589e1460d3..717458aa6fb 100644 --- a/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/notifiers/SimpleResourceObjectNotifier.java +++ b/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/notifiers/SimpleResourceObjectNotifier.java @@ -185,7 +185,10 @@ protected String getBody(Event event, GeneralNotifierType generalNotifierType, S } if (resourceObjectEvent.getOperationStatus() != OperationStatus.IN_PROGRESS) { - body.append(textFormatter.formatObjectModificationDelta(delta, hiddenPaths, isWatchAuxiliaryAttributes(generalNotifierType))); + // todo we do not have objectOld + objectNew, only the current status + // it is used to explain modified containers with identifiers -- however, currently I don't know of use of such containers in shadows, which would be visible in notifications + body.append(textFormatter.formatObjectModificationDelta(delta, hiddenPaths, isWatchAuxiliaryAttributes(generalNotifierType), + resourceObjectEvent.getAccountOperationDescription().getCurrentShadow(), null)); } else { // special case - here the attributes are 'result', 'failedOperationType', 'objectChange', 'attemptNumber' // we have to unwrap attributes that are to be modified from the objectChange item @@ -206,7 +209,8 @@ protected String getBody(Event event, GeneralNotifierType generalNotifierType, S deltas.add((ObjectDelta) DeltaConvertor.createObjectDelta(change.getValue(), prismContext)); } ObjectDelta shadowDelta = ObjectDelta.summarize(deltas); - body.append(textFormatter.formatObjectModificationDelta(shadowDelta, hiddenPaths, isWatchAuxiliaryAttributes(generalNotifierType))); + body.append(textFormatter.formatObjectModificationDelta(shadowDelta, hiddenPaths, isWatchAuxiliaryAttributes(generalNotifierType), + resourceObjectEvent.getAccountOperationDescription().getCurrentShadow(), null)); } catch (SchemaException e) { LoggingUtils.logException(LOGGER, "Unable to determine the shadow change; operation = {}", e, resourceObjectEvent.getAccountOperationDescription().debugDump()); body.append("(unable to determine the change because of schema exception: ").append(e.getMessage()).append(")\n"); diff --git a/model/notifications-impl/src/test/java/com/evolveum/midpoint/notifications/impl/TestTextFormatter.java b/model/notifications-impl/src/test/java/com/evolveum/midpoint/notifications/impl/TestTextFormatter.java index bdeb20a6d27..1f60579dce2 100644 --- a/model/notifications-impl/src/test/java/com/evolveum/midpoint/notifications/impl/TestTextFormatter.java +++ b/model/notifications-impl/src/test/java/com/evolveum/midpoint/notifications/impl/TestTextFormatter.java @@ -32,6 +32,9 @@ import java.util.Arrays; import java.util.List; +import static org.testng.AssertJUnit.assertFalse; +import static org.testng.AssertJUnit.assertTrue; + /** * @author mederly */ @@ -91,7 +94,7 @@ public void setup() throws SchemaException, SAXException, IOException { } - @Test(enabled = false) + @Test(enabled = true) public void test010FormatUser() throws Exception { // GIVEN @@ -114,71 +117,92 @@ public void test010FormatUser() throws Exception { // THEN - AssertJUnit.assertTrue("hidden operational attribute when it should be shown ('hide none')", jackFormattedHideNone.contains("createTimestamp:")); - AssertJUnit.assertTrue("hidden auxiliary attribute (effective status) when it should be shown ('hide none')", jackFormattedHideNone.contains("Effective Status: ENABLED")); - AssertJUnit.assertTrue("hidden auxiliary attribute (family name) when it should be shown ('hide none')", jackFormattedHideNone.contains("Family Name: Sparrow")); - AssertJUnit.assertTrue("hidden standard attribute when it should be shown ('hide none')", jackFormattedHideNone.contains("ship: Black Pearl")); + assertTrue("hidden operational attribute when it should be shown ('hide none')", jackFormattedHideNone.contains("createTimestamp:")); + assertTrue("hidden auxiliary attribute (effective status) when it should be shown ('hide none')", jackFormattedHideNone.contains("Effective Status: ENABLED")); + assertTrue("hidden auxiliary attribute (family name) when it should be shown ('hide none')", jackFormattedHideNone.contains("Family Name: Sparrow")); + assertTrue("hidden standard attribute when it should be shown ('hide none')", jackFormattedHideNone.contains("ship: Black Pearl")); - AssertJUnit.assertTrue("shown operational attribute when it should be hidden ('hide oper')", !jackFormattedHideOper.contains("createTimestamp:")); - AssertJUnit.assertTrue("hidden auxiliary attribute when it should be shown ('hide oper')", jackFormattedHideOper.contains("Effective Status: ENABLED")); - AssertJUnit.assertTrue("hidden auxiliary attribute (family name) when it should be shown ('hide oper')", jackFormattedHideOper.contains("Family Name: Sparrow")); - AssertJUnit.assertTrue("hidden standard attribute when it should be shown ('hide oper')", jackFormattedHideOper.contains("ship: Black Pearl")); + assertTrue("shown operational attribute when it should be hidden ('hide oper')", !jackFormattedHideOper.contains("createTimestamp:")); + assertTrue("hidden auxiliary attribute when it should be shown ('hide oper')", jackFormattedHideOper.contains("Effective Status: ENABLED")); + assertTrue("hidden auxiliary attribute (family name) when it should be shown ('hide oper')", jackFormattedHideOper.contains("Family Name: Sparrow")); + assertTrue("hidden standard attribute when it should be shown ('hide oper')", jackFormattedHideOper.contains("ship: Black Pearl")); - AssertJUnit.assertTrue("shown auxiliary attribute (metadata) when it should be hidden ('hide aux')", !jackFormattedHideAux.contains("createTimestamp:")); - AssertJUnit.assertTrue("shown auxiliary attribute (family name) when it should be hidden ('hide aux')", !jackFormattedHideAux.contains("Family Name: Sparrow")); - AssertJUnit.assertTrue("shown auxiliary attribute (effective status) when it should be hidden ('hide aux')", !jackFormattedHideAux.contains("Effective Status: ENABLED")); - AssertJUnit.assertTrue("hidden standard attribute when it should be shown ('hide aux')", jackFormattedHideAux.contains("ship: Black Pearl")); + assertTrue("shown auxiliary attribute (metadata) when it should be hidden ('hide aux')", !jackFormattedHideAux.contains("createTimestamp:")); + assertTrue("shown auxiliary attribute (family name) when it should be hidden ('hide aux')", !jackFormattedHideAux.contains("Family Name: Sparrow")); + assertTrue("shown auxiliary attribute (effective status) when it should be hidden ('hide aux')", !jackFormattedHideAux.contains("Effective Status: ENABLED")); + assertTrue("hidden standard attribute when it should be shown ('hide aux')", jackFormattedHideAux.contains("ship: Black Pearl")); - AssertJUnit.assertTrue("shown operational attribute when it should be hidden ('hide aux and oper')", !jackFormattedHideAuxAndOper.contains("createTimestamp:")); - AssertJUnit.assertTrue("shown auxiliary attribute (effective status) when it should be hidden ('hide aux and oper')", !jackFormattedHideAuxAndOper.contains("Effective Status: ENABLED")); - AssertJUnit.assertTrue("shown auxiliary attribute (family name) when it should be hidden ('hide aux and oper')", !jackFormattedHideAuxAndOper.contains("Family Name: Sparrow")); - AssertJUnit.assertTrue("hidden standard attribute when it should be shown ('hide aux and oper')", jackFormattedHideAuxAndOper.contains("ship: Black Pearl")); + assertTrue("shown operational attribute when it should be hidden ('hide aux and oper')", !jackFormattedHideAuxAndOper.contains("createTimestamp:")); + assertTrue("shown auxiliary attribute (effective status) when it should be hidden ('hide aux and oper')", !jackFormattedHideAuxAndOper.contains("Effective Status: ENABLED")); + assertTrue("shown auxiliary attribute (family name) when it should be hidden ('hide aux and oper')", !jackFormattedHideAuxAndOper.contains("Family Name: Sparrow")); + assertTrue("hidden standard attribute when it should be shown ('hide aux and oper')", jackFormattedHideAuxAndOper.contains("ship: Black Pearl")); } - @Test(enabled = false) + @Test(enabled = true) public void test020FormatUserModification() throws Exception { // GIVEN ObjectDelta delta = parseDelta(USER_JACK_MODIFICATION_FILE); + PrismObject jack = PrismTestUtil.parseObject(new File(USER_JACK_FILE)); System.out.println(delta.debugDump()); // WHEN - String deltaFormattedHideNone = textFormatter.formatObjectModificationDelta(delta, null, true); + String deltaFormattedHideNone = textFormatter.formatObjectModificationDelta(delta, null, true, jack, null); System.out.println("no hidden paths + show operational attributes: " + deltaFormattedHideNone); - String deltaFormattedHideOper = textFormatter.formatObjectModificationDelta(delta, null, false); + String deltaFormattedHideOper = textFormatter.formatObjectModificationDelta(delta, null, false, jack, null); System.out.println("no hidden paths + hide operational attributes: " + deltaFormattedHideOper); - String deltaFormattedHideAux = textFormatter.formatObjectModificationDelta(delta, auxiliaryPaths, true); + String deltaFormattedHideAux = textFormatter.formatObjectModificationDelta(delta, auxiliaryPaths, true, jack, null); System.out.println("hide auxiliary paths + show operational attributes: " + deltaFormattedHideAux); - String deltaFormattedHideAuxAndOper = textFormatter.formatObjectModificationDelta(delta, auxiliaryPaths, false); + String deltaFormattedHideAuxAndOper = textFormatter.formatObjectModificationDelta(delta, auxiliaryPaths, false, jack, null); System.out.println("hide auxiliary paths + hide operational attributes: " + deltaFormattedHideAuxAndOper); // THEN - AssertJUnit.assertTrue("hidden operational attribute when it should be shown ('hide none')", deltaFormattedHideNone.contains("createTimestamp:")); - AssertJUnit.assertTrue("hidden auxiliary attribute (family name) when it should be shown ('hide none')", deltaFormattedHideNone.contains("SPARROW")); - AssertJUnit.assertTrue("hidden password change when it should be shown ('hide none')", deltaFormattedHideNone.contains("(protected string)")); - AssertJUnit.assertTrue("hidden standard attribute when it should be shown ('hide none')", deltaFormattedHideNone.contains("BLACK PEARL")); + checkNotes(deltaFormattedHideAux); + checkNotes(deltaFormattedHideAuxAndOper); + checkNotes(deltaFormattedHideNone); + checkNotes(deltaFormattedHideOper); - AssertJUnit.assertTrue("shown operational attribute when it should be hidden ('hide oper')", !deltaFormattedHideOper.contains("createTimestamp:")); - AssertJUnit.assertTrue("hidden auxiliary attribute (family name) when it should be shown ('hide oper')", deltaFormattedHideOper.contains("SPARROW")); - AssertJUnit.assertTrue("hidden password change when it should be shown ('hide oper')", deltaFormattedHideOper.contains("(protected string)")); - AssertJUnit.assertTrue("hidden standard attribute when it should be shown ('hide oper')", deltaFormattedHideOper.contains("BLACK PEARL")); + assertTrue("hidden operational attribute when it should be shown ('hide none')", deltaFormattedHideNone.contains("createTimestamp:")); + assertTrue("hidden auxiliary attribute (family name) when it should be shown ('hide none')", deltaFormattedHideNone.contains("SPARROW")); + assertTrue("hidden password change when it should be shown ('hide none')", deltaFormattedHideNone.contains("(protected string)")); + assertTrue("hidden standard attribute when it should be shown ('hide none')", deltaFormattedHideNone.contains("BLACK PEARL")); - AssertJUnit.assertTrue("shown auxiliary attribute (metadata) when it should be hidden ('hide aux')", !deltaFormattedHideAux.contains("createTimestamp:")); - AssertJUnit.assertTrue("shown auxiliary attribute (family name) when it should be hidden ('hide aux')", !deltaFormattedHideAux.contains("SPARROW")); - AssertJUnit.assertTrue("hidden standard attribute when it should be shown ('hide aux')", deltaFormattedHideAux.contains("BLACK PEARL")); + assertTrue("shown operational attribute when it should be hidden ('hide oper')", !deltaFormattedHideOper.contains("createTimestamp:")); + assertTrue("hidden auxiliary attribute (family name) when it should be shown ('hide oper')", deltaFormattedHideOper.contains("SPARROW")); + assertTrue("hidden password change when it should be shown ('hide oper')", deltaFormattedHideOper.contains("(protected string)")); + assertTrue("hidden standard attribute when it should be shown ('hide oper')", deltaFormattedHideOper.contains("BLACK PEARL")); - AssertJUnit.assertTrue("shown operational attribute when it should be hidden ('hide aux and oper')", !deltaFormattedHideAuxAndOper.contains("createTimestamp:")); - AssertJUnit.assertTrue("shown auxiliary attribute (family name) when it should be hidden ('hide aux and oper')", !deltaFormattedHideAuxAndOper.contains("SPARROW")); - AssertJUnit.assertTrue("hidden standard attribute when it should be shown ('hide aux and oper')", deltaFormattedHideAuxAndOper.contains("BLACK PEARL")); + assertTrue("shown auxiliary attribute (metadata) when it should be hidden ('hide aux')", !deltaFormattedHideAux.contains("createTimestamp:")); + assertTrue("shown auxiliary attribute (family name) when it should be hidden ('hide aux')", !deltaFormattedHideAux.contains("SPARROW")); + assertTrue("hidden standard attribute when it should be shown ('hide aux')", deltaFormattedHideAux.contains("BLACK PEARL")); + + assertTrue("shown operational attribute when it should be hidden ('hide aux and oper')", !deltaFormattedHideAuxAndOper.contains("createTimestamp:")); + assertTrue("shown auxiliary attribute (family name) when it should be hidden ('hide aux and oper')", !deltaFormattedHideAuxAndOper.contains("SPARROW")); + assertTrue("hidden standard attribute when it should be shown ('hide aux and oper')", deltaFormattedHideAuxAndOper.contains("BLACK PEARL")); + + } + private void checkNotes(String notification) { + String NOTES_DELIMITER = "Notes:"; + int i = notification.indexOf(NOTES_DELIMITER); + if (i == -1) { + throw new AssertionError("No Notes section in " + notification); + } + String notes = notification.substring(i); + assertFalse(notes.contains("Assignment #1")); + assertFalse(notes.contains("Assignment #2")); + assertFalse(notes.contains("Assignment #3")); + assertTrue(notes.contains("Assignment[1]")); + assertTrue(notes.contains("Assignment[2]")); + assertFalse(notes.contains("Assignment[3]")); } @Test(enabled = true) @@ -198,15 +222,15 @@ public void test030FormatAccount() throws Exception { // THEN - AssertJUnit.assertTrue("account name is not shown", jackFormattedHideNone.contains("name: jack")); - AssertJUnit.assertTrue("account password is not shown", jackFormattedHideNone.contains("(protected string)")); - AssertJUnit.assertTrue("administrative status is not shown", jackFormattedHideNone.contains("Administrative Status: ENABLED")); - AssertJUnit.assertTrue("effective status is not shown", jackFormattedHideNone.contains("Effective Status: ENABLED")); + assertTrue("account name is not shown", jackFormattedHideNone.contains("name: jack")); + assertTrue("account password is not shown", jackFormattedHideNone.contains("(protected string)")); + assertTrue("administrative status is not shown", jackFormattedHideNone.contains("Administrative Status: ENABLED")); + assertTrue("effective status is not shown", jackFormattedHideNone.contains("Effective Status: ENABLED")); - AssertJUnit.assertTrue("account name is not shown", jackFormattedHideAux.contains("name: jack")); - AssertJUnit.assertTrue("account password is not shown", jackFormattedHideAux.contains("(protected string)")); - AssertJUnit.assertTrue("administrative status is not shown", jackFormattedHideAux.contains("Administrative Status: ENABLED")); - AssertJUnit.assertTrue("effective status is shown although it should be hidden", !jackFormattedHideAux.contains("Effective Status: ENABLED")); + assertTrue("account name is not shown", jackFormattedHideAux.contains("name: jack")); + assertTrue("account password is not shown", jackFormattedHideAux.contains("(protected string)")); + assertTrue("administrative status is not shown", jackFormattedHideAux.contains("Administrative Status: ENABLED")); + assertTrue("effective status is shown although it should be hidden", !jackFormattedHideAux.contains("Effective Status: ENABLED")); // AssertJUnit.assertTrue("hidden operational attribute when it should be shown ('hide none')", jackFormattedHideNone.contains("createTimestamp:")); // AssertJUnit.assertTrue("hidden auxiliary attribute (effective status) when it should be shown ('hide none')", jackFormattedHideNone.contains("Effective Status: ENABLED")); diff --git a/model/notifications-impl/src/test/resources/changes/user-jack-modification.xml b/model/notifications-impl/src/test/resources/changes/user-jack-modification.xml index fee366bdf63..46a9f80e5ee 100644 --- a/model/notifications-impl/src/test/resources/changes/user-jack-modification.xml +++ b/model/notifications-impl/src/test/resources/changes/user-jack-modification.xml @@ -20,7 +20,7 @@ xmlns:c='http://midpoint.evolveum.com/xml/ns/public/common/common-3' xmlns:t="http://prism.evolveum.com/xml/ns/public/types-3"> c0c010c0-d34d-b33f-f00d-111111111111 - + replace c:credentials/c:password @@ -28,26 +28,31 @@ jack123456 - - + + replace - - SPARROW - - - + familyName + SPARROW + + replace - c:metadata - - 2013-12-01T11:22:33.44 - - - + c:metadata/c:createTimestamp + 2013-12-01T11:22:33.44 + + + replace + c:extension/piracy:ship + BLACK PEARL + + + replace + assignment[1]/activation/validTo + 2013-12-01T11:22:33.44 + + replace - c:extension - - BLACK PEARL - - + assignment[2]/activation/validTo + 2014-10-03T11:22:33.44 + diff --git a/model/notifications-impl/src/test/resources/objects/user-jack.xml b/model/notifications-impl/src/test/resources/objects/user-jack.xml index a5c58fd46f1..2cd621cc402 100644 --- a/model/notifications-impl/src/test/resources/objects/user-jack.xml +++ b/model/notifications-impl/src/test/resources/objects/user-jack.xml @@ -56,4 +56,21 @@ enabled enabled + + + + + + + + 2013-12-01T11:22:33.44 + + + + + + 2015-01-01T00:00:00.00 + + + From dbb0f1e12bb5a4bf4d37858b558e15956efbb6b2 Mon Sep 17 00:00:00 2001 From: Pavol Mederly Date: Fri, 3 Oct 2014 11:19:22 +0200 Subject: [PATCH 12/19] Small fix. --- .../impl/notifiers/SimpleFocalObjectNotifier.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/notifiers/SimpleFocalObjectNotifier.java b/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/notifiers/SimpleFocalObjectNotifier.java index 9b2d3dd59de..930c0dde272 100644 --- a/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/notifiers/SimpleFocalObjectNotifier.java +++ b/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/notifiers/SimpleFocalObjectNotifier.java @@ -131,6 +131,10 @@ protected String getBody(Event event, GeneralNotifierType generalNotifierType, S fullName = ""; // TODO (currently it's not possible to get here) } + if (fullName == null) { + fullName = ""; // "null" is not nice in notifications + } + ObjectDelta delta = ObjectDelta.summarize(((ModelEvent) event).getFocusDeltas()); StringBuilder body = new StringBuilder(); From f26ed43d28bf32e104d8148653a6b3ad55648c21 Mon Sep 17 00:00:00 2001 From: Erik Suta Date: Fri, 3 Oct 2014 15:22:30 +0200 Subject: [PATCH 13/19] Resource Wizard update: - Fix for bug when correlation filter expression was not saved - Added filterClause editor to resource protected accounts editor - Better handling for validators - when error occurs, error message is displazed immidiatel - fix for bug, when deleting expression or filterClause would not be handled --- .../input/ExpressionEditorPanel.java | 15 ++++++--------- .../input/ExpressionEditorPanel.properties | 1 + .../component/input/SearchFilterPanel.java | 16 +++++++--------- .../input/dto/SearchFilterTypeDto.java | 8 +++++--- .../web/component/wizard/WizardStep.java | 11 ++++++----- .../component/wizard/WizardStep.properties | 3 ++- .../wizard/resource/SchemaHandlingStep.java | 12 ++++++------ .../ResourceProtectedEditor.html | 18 +----------------- .../ResourceProtectedEditor.java | 19 ++++++------------- .../ConditionalSearchFilterEditor.java | 17 ++++++++++++++++- .../midpoint/web/util/ExpressionUtil.java | 3 ++- 11 files changed, 58 insertions(+), 65 deletions(-) diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/input/ExpressionEditorPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/input/ExpressionEditorPanel.java index e1ad66dcefd..a7057a34987 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/input/ExpressionEditorPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/input/ExpressionEditorPanel.java @@ -35,12 +35,10 @@ import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior; import org.apache.wicket.ajax.markup.html.AjaxLink; +import org.apache.wicket.ajax.markup.html.form.AjaxSubmitLink; import org.apache.wicket.markup.html.WebMarkupContainer; import org.apache.wicket.markup.html.basic.Label; -import org.apache.wicket.markup.html.form.DropDownChoice; -import org.apache.wicket.markup.html.form.EnumChoiceRenderer; -import org.apache.wicket.markup.html.form.IChoiceRenderer; -import org.apache.wicket.markup.html.form.TextArea; +import org.apache.wicket.markup.html.form.*; import org.apache.wicket.model.AbstractReadOnlyModel; import org.apache.wicket.model.IModel; import org.apache.wicket.model.PropertyModel; @@ -114,6 +112,7 @@ protected void onUpdate(AjaxRequestTarget target) { }); type.setOutputMarkupId(true); type.setOutputMarkupPlaceholderTag(true); + type.setNullValid(true); add(type); WebMarkupContainer languageContainer = new WebMarkupContainer(ID_LANGUAGE_CONTAINER); @@ -193,10 +192,10 @@ protected void onUpdate(AjaxRequestTarget target) { expression.setOutputMarkupId(true); add(expression); - AjaxLink update = new AjaxLink(ID_BUTTON_UPDATE) { + AjaxSubmitLink update = new AjaxSubmitLink(ID_BUTTON_UPDATE) { @Override - public void onClick(AjaxRequestTarget target) { + protected void onSubmit(AjaxRequestTarget target, Form form) { updateExpressionPerformed(target); } }; @@ -255,9 +254,7 @@ protected void updateExpressionPerformed(AjaxRequestTarget target){ /** * Override this in component with ExpressionEditorPanel to provide additional functionality when expression is updated * */ - public void performExpressionHook(AjaxRequestTarget target){ - - } + public void performExpressionHook(AjaxRequestTarget target){} /** * Provide key for expression type label diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/input/ExpressionEditorPanel.properties b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/input/ExpressionEditorPanel.properties index bb1b1076045..097edb658f7 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/input/ExpressionEditorPanel.properties +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/input/ExpressionEditorPanel.properties @@ -24,6 +24,7 @@ ExpressionEditorPanel.message.cantSerialize=Could not create JAXBElement from ExpressionEditorPanel.message.expressionSuccess=Expression has been update successfully. policyRef.nullValid=Choose One +type.nullValid=Choose One ExpressionEvaluatorType.LITERAL=Literal ExpressionEvaluatorType.AS_IS=As is ExpressionEvaluatorType.PATH=Path diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/input/SearchFilterPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/input/SearchFilterPanel.java index 01a3624068a..2779c34763f 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/input/SearchFilterPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/input/SearchFilterPanel.java @@ -16,7 +16,6 @@ package com.evolveum.midpoint.web.component.input; -import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.util.logging.LoggingUtils; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; @@ -25,7 +24,8 @@ import com.evolveum.midpoint.web.component.util.SimplePanel; import com.evolveum.prism.xml.ns._public.query_3.SearchFilterType; import org.apache.wicket.ajax.AjaxRequestTarget; -import org.apache.wicket.ajax.markup.html.AjaxLink; +import org.apache.wicket.ajax.markup.html.form.AjaxSubmitLink; +import org.apache.wicket.markup.html.form.Form; import org.apache.wicket.markup.html.form.TextArea; import org.apache.wicket.model.IModel; import org.apache.wicket.model.PropertyModel; @@ -41,7 +41,7 @@ public class SearchFilterPanel extends SimplePanel model; + protected IModel model; public SearchFilterPanel(String id, IModel model){ super(id, model); @@ -71,10 +71,10 @@ protected void initLayout(){ new PropertyModel(model, SearchFilterTypeDto.F_FILTER_CLAUSE)); add(filterClause); - AjaxLink update = new AjaxLink(ID_BUTTON_UPDATE) { + AjaxSubmitLink update = new AjaxSubmitLink(ID_BUTTON_UPDATE) { @Override - public void onClick(AjaxRequestTarget target) { + protected void onSubmit(AjaxRequestTarget target, Form form) { updateClausePerformed(target); } }; @@ -86,7 +86,7 @@ private void updateClausePerformed(AjaxRequestTarget target){ model.getObject().updateFilterClause(getPageBase().getPrismContext()); success(getString("SearchFilterPanel.message.expressionSuccess")); - } catch (SchemaException e){ + } catch (Exception e){ LoggingUtils.logException(LOGGER, "Could not create MapXNode from provided XML filterClause.", e); error(getString("SearchFilterPanel.message.cantSerialize")); } @@ -98,7 +98,5 @@ private void updateClausePerformed(AjaxRequestTarget target){ /** * Override this in component with SearchFilterPanel to provide additional functionality when filterClause is updated * */ - public void performFilterClauseHook(AjaxRequestTarget target){ - target.add(); - } + public void performFilterClauseHook(AjaxRequestTarget target){} } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/input/dto/SearchFilterTypeDto.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/input/dto/SearchFilterTypeDto.java index cc78730dfb8..3a5e96c273d 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/input/dto/SearchFilterTypeDto.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/input/dto/SearchFilterTypeDto.java @@ -17,9 +17,7 @@ package com.evolveum.midpoint.web.component.input.dto; import com.evolveum.midpoint.prism.PrismContext; -import com.evolveum.midpoint.prism.xnode.MapXNode; import com.evolveum.midpoint.prism.xnode.RootXNode; -import com.evolveum.midpoint.prism.xnode.XNode; import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.util.logging.LoggingUtils; import com.evolveum.midpoint.util.logging.Trace; @@ -27,7 +25,6 @@ import com.evolveum.prism.xml.ns._public.query_3.SearchFilterType; import org.apache.commons.lang.StringUtils; -import javax.xml.namespace.QName; import java.io.Serializable; /** @@ -86,6 +83,11 @@ public void updateFilterClause(PrismContext context) throws SchemaException{ RootXNode filterClauseNode = (RootXNode) context.parseToXNode(filterClause, PrismContext.LANG_XML); filterObject.setFilterClauseXNode(filterClauseNode); + } else { + String oldDescription = filterObject.getDescription(); + + filterObject = new SearchFilterType(); + filterObject.setDescription(oldDescription); } } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/WizardStep.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/WizardStep.java index 5225a583ce2..2ded7d323a2 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/WizardStep.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/WizardStep.java @@ -26,6 +26,7 @@ import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceType; import org.apache.commons.lang.StringUtils; import org.apache.wicket.Component; +import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.extensions.wizard.IWizard; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.model.AbstractReadOnlyModel; @@ -49,15 +50,13 @@ public WizardStep() { @Override public Component getHeader(String id, Component parent, IWizard wizard) { - Label header = new Label(id, new AbstractReadOnlyModel() { + return new Label(id, new AbstractReadOnlyModel() { @Override public String getObject() { return getTitle(); } }); - - return header; } public PageBase getPageBase() { @@ -127,8 +126,8 @@ protected IValidator createObjectClassValidator(final IModel return new IValidator() { @Override - public void validate(IValidatable validatable) { - String value = validatable.getValue(); + public void validate(IValidatable validated) { + String value = validated.getValue(); List list = model.getObject(); List stringList = new ArrayList<>(); @@ -138,6 +137,8 @@ public void validate(IValidatable validatable) { if(!stringList.contains(value)){ error(createStringResource("SchemaHandlingStep.message.validationError", value).getString()); + AjaxRequestTarget target = getRequestCycle().find(AjaxRequestTarget.class); + target.add(getPageBase().getFeedbackPanel()); } } }; diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/WizardStep.properties b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/WizardStep.properties index 0eeda5ddcd6..54ab714af24 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/WizardStep.properties +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/WizardStep.properties @@ -14,4 +14,5 @@ # limitations under the License. # -WizardStep.title= \ No newline at end of file +WizardStep.title= +SchemaHandlingStep.message.validationError=Inserted objectClass value: '{0}' is not valid. Please provide valid objectClass value. \ No newline at end of file diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/resource/SchemaHandlingStep.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/resource/SchemaHandlingStep.java index 4f5f38a2bbd..f43b8e1fd48 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/resource/SchemaHandlingStep.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/resource/SchemaHandlingStep.java @@ -537,7 +537,7 @@ private void dependencyEditPerformed(AjaxRequestTarget target){ new PropertyModel>(model, SchemaHandlingDto.F_SELECTED + ".dependency")); getThirdRowContainer().replaceWith(newContainer); - target.add(getThirdRowContainer()); + target.add(getThirdRowContainer(), getPageBase().getFeedbackPanel()); } private void iterationEditPerformed(AjaxRequestTarget target){ @@ -545,7 +545,7 @@ private void iterationEditPerformed(AjaxRequestTarget target){ new PropertyModel(model, SchemaHandlingDto.F_SELECTED + ".iteration")); getThirdRowContainer().replaceWith(newContainer); - target.add(getThirdRowContainer()); + target.add(getThirdRowContainer(), getPageBase().getFeedbackPanel()); } private void protectedEditPerformed(AjaxRequestTarget target){ @@ -553,7 +553,7 @@ private void protectedEditPerformed(AjaxRequestTarget target){ new PropertyModel>(model, SchemaHandlingDto.F_SELECTED + "._protected")); getThirdRowContainer().replaceWith(newContainer); - target.add(getThirdRowContainer()); + target.add(getThirdRowContainer(), getPageBase().getFeedbackPanel()); } private void activationEditPerformed(AjaxRequestTarget target){ @@ -561,7 +561,7 @@ private void activationEditPerformed(AjaxRequestTarget target){ new PropertyModel(model, SchemaHandlingDto.F_SELECTED + ".activation")); getThirdRowContainer().replaceWith(newContainer); - target.add(getThirdRowContainer()); + target.add(getThirdRowContainer(), getPageBase().getFeedbackPanel()); } private void credentialsEditPerformed(AjaxRequestTarget target){ @@ -569,7 +569,7 @@ private void credentialsEditPerformed(AjaxRequestTarget target){ new PropertyModel(model, SchemaHandlingDto.F_SELECTED + ".credentials")); getThirdRowContainer().replaceWith(newContainer); - target.add(getThirdRowContainer()); + target.add(getThirdRowContainer(), getPageBase().getFeedbackPanel()); } private void editAttributePerformed(AjaxRequestTarget target, ResourceAttributeDefinitionType object){ @@ -592,7 +592,7 @@ private void editAssociationPerformed(AjaxRequestTarget target, ResourceObjectAs model.getObject().getSelected(), resourceModel.getObject()); getThirdRowContainer().replaceWith(newContainer); - target.add(getThirdRowContainer()); + target.add(getThirdRowContainer(), getPageBase().getFeedbackPanel()); } else { warn(getString("SchemaHandlingStep.message.selectObjectClassAss")); getThirdRowContainer().replaceWith(new WebMarkupContainer(ID_THIRD_ROW_CONTAINER)); diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/resource/component/schemahandling/ResourceProtectedEditor.html b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/resource/component/schemahandling/ResourceProtectedEditor.html index b7791df1e7a..4b88fba0afb 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/resource/component/schemahandling/ResourceProtectedEditor.html +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/resource/component/schemahandling/ResourceProtectedEditor.html @@ -56,23 +56,7 @@

-
-
- -
-
- -
-
- -
-
- -
-
- -
-
+
diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/resource/component/schemahandling/ResourceProtectedEditor.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/resource/component/schemahandling/ResourceProtectedEditor.java index 48d0edceca8..dbf66e346cf 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/resource/component/schemahandling/ResourceProtectedEditor.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/resource/component/schemahandling/ResourceProtectedEditor.java @@ -16,15 +16,16 @@ package com.evolveum.midpoint.web.component.wizard.resource.component.schemahandling; +import com.evolveum.midpoint.web.component.input.SearchFilterPanel; import com.evolveum.midpoint.web.component.util.SimplePanel; import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceObjectPatternType; +import com.evolveum.prism.xml.ns._public.query_3.SearchFilterType; import org.apache.wicket.AttributeModifier; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior; import org.apache.wicket.ajax.markup.html.AjaxLink; import org.apache.wicket.markup.html.WebMarkupContainer; import org.apache.wicket.markup.html.basic.Label; -import org.apache.wicket.markup.html.form.TextArea; import org.apache.wicket.markup.html.form.TextField; import org.apache.wicket.markup.html.list.ListItem; import org.apache.wicket.markup.html.list.ListView; @@ -51,8 +52,7 @@ private static enum ChangeState{ private static final String ID_ACCOUNT_BODY = "accountBodyContainer"; private static final String ID_NAME = "name"; private static final String ID_UID = "uid"; - private static final String ID_FILTER_DESCRIPTION = "filterDescription"; - private static final String ID_FILTER_CLAUSE = "filterClause"; + private static final String ID_FILTER_EDITOR = "filterClause"; private static final String ID_BUTTON_ADD = "addButton"; private static final String ID_BUTTON_DELETE = "deleteAccount"; @@ -150,16 +150,9 @@ public String getObject() { uid.add(prepareAjaxOnComponentTagUpdateBehavior()); accountBody.add(uid); - TextArea filterDescription = new TextArea<>(ID_FILTER_DESCRIPTION, - new PropertyModel(item.getModelObject(), "filter.description")); - filterDescription.add(prepareAjaxOnComponentTagUpdateBehavior()); - accountBody.add(filterDescription); - - //TODO - what is this? How should we edit this? - TextField filterClause = new TextField<>(ID_FILTER_CLAUSE, - new PropertyModel(item.getModelObject(), "filter.filterClauseXNode")); - filterClause.add(prepareAjaxOnComponentTagUpdateBehavior()); - accountBody.add(filterClause); + SearchFilterPanel searchFilterPanel = new SearchFilterPanel<>(ID_FILTER_EDITOR, + new PropertyModel(item.getModelObject(), "filter")); + accountBody.add(searchFilterPanel); } }; repeater.setOutputMarkupId(true); diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/resource/component/synchronization/ConditionalSearchFilterEditor.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/resource/component/synchronization/ConditionalSearchFilterEditor.java index 611937c3707..af39aadfc9f 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/resource/component/synchronization/ConditionalSearchFilterEditor.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wizard/resource/component/synchronization/ConditionalSearchFilterEditor.java @@ -18,10 +18,12 @@ import com.evolveum.midpoint.web.component.input.ExpressionEditorPanel; import com.evolveum.midpoint.web.component.input.SearchFilterPanel; +import com.evolveum.midpoint.web.component.input.dto.SearchFilterTypeDto; import com.evolveum.midpoint.web.component.util.LoadableModel; import com.evolveum.midpoint.web.component.util.SimplePanel; import com.evolveum.midpoint.xml.ns._public.common.common_3.ConditionalSearchFilterType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ExpressionType; +import com.evolveum.prism.xml.ns._public.query_3.SearchFilterType; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.markup.html.form.TextArea; import org.apache.wicket.model.IModel; @@ -103,7 +105,20 @@ public String getExpressionLabelKey() { }; add(expressionEditor); - SearchFilterPanel filterClauseEditor = new SearchFilterPanel<>(ID_FILTER_CLAUSE_PANEL, getModel()); + SearchFilterPanel filterClauseEditor = new SearchFilterPanel(ID_FILTER_CLAUSE_PANEL, getModel()){ + + @Override + public void performFilterClauseHook(AjaxRequestTarget target){ + if(model != null && model.getObject() != null && ConditionalSearchFilterEditor.this.getModel() != null){ + SearchFilterTypeDto dto = model.getObject(); + SearchFilterType filter = dto.getFilterObject(); + + if(filter != null){ + ConditionalSearchFilterEditor.this.getModelObject().setFilterClauseXNode(filter.getFilterClauseXNode()); + } + } + } + }; add(filterClauseEditor); } } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/util/ExpressionUtil.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/util/ExpressionUtil.java index 1ac5073b47b..1be5b673bc8 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/util/ExpressionUtil.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/util/ExpressionUtil.java @@ -80,6 +80,7 @@ public void setLanguage(String language) { public static final String ELEMENT_PATH = ""; public static final String ELEMENT_VALUE = ""; public static final String ELEMENT_AS_IS = ""; + public static final String ELEMENT_AS_IS_WITH_NS = " Date: Fri, 3 Oct 2014 15:48:29 +0200 Subject: [PATCH 14/19] Fix for ChooseTypePanel - when assigning multiple roles, the deletion of tenant attribute in one role cause next assignment to crash. --- .../configuration/component/ChooseTypePanel.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/component/ChooseTypePanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/component/ChooseTypePanel.java index e7292f31311..e9d3fac588a 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/component/ChooseTypePanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/component/ChooseTypePanel.java @@ -69,6 +69,7 @@ public String getObject(){ name.setOutputMarkupId(true); AjaxLink choose = new AjaxLink(ID_LINK_CHOOSE) { + @Override public void onClick(AjaxRequestTarget target) { changeOptionPerformed(target); @@ -76,6 +77,7 @@ public void onClick(AjaxRequestTarget target) { }; AjaxLink remove = new AjaxLink(ID_LINK_REMOVE) { + @Override public void onClick(AjaxRequestTarget target) { setToDefault(); @@ -91,7 +93,7 @@ public void onClick(AjaxRequestTarget target) { } private void initDialog(){ - ModalWindow dialog = new ChooseTypeDialog(MODAL_ID_SHOW_CHOOSE_OPTIONS, getModel().getObject().getType()){ + ModalWindow dialog = new ChooseTypeDialog(MODAL_ID_SHOW_CHOOSE_OPTIONS, getObjectTypeClass()){ @Override protected void chooseOperationPerformed(AjaxRequestTarget target, ObjectType object){ @@ -151,7 +153,13 @@ private void changeOptionPerformed(AjaxRequestTarget target){ } private void setToDefault(){ - getModel().setObject(new ObjectViewDto()); + ObjectViewDto dto = new ObjectViewDto(); + dto.setType(getObjectTypeClass()); + getModel().setObject(dto); + } + + private Class getObjectTypeClass(){ + return getModel().getObject().getType(); } public StringResourceModel createStringResource(String resourceKey, Object... objects) { From 05abb27bf0b4020d2fb0efbe247be9a70137cf63 Mon Sep 17 00:00:00 2001 From: "Katarina Valalikova (katkav)" Date: Sat, 4 Oct 2014 08:57:21 +0200 Subject: [PATCH 15/19] added possibility to override resource schema and set secondary identifier - imporved consistency mechanism.. --- .../refinery/RefinedAttributeDefinition.java | 19 ++++++++++++++ .../RefinedObjectClassDefinition.java | 2 +- .../xml/ns/public/common/common-3.xsd | 10 ++++++++ .../projector/ProjectionValuesProcessor.java | 10 -------- .../impl/ObjectAlreadyExistHandler.java | 25 +++++++++++++------ .../provisioning/util/ProvisioningUtil.java | 10 ++++++-- 6 files changed, 55 insertions(+), 21 deletions(-) diff --git a/infra/common/src/main/java/com/evolveum/midpoint/common/refinery/RefinedAttributeDefinition.java b/infra/common/src/main/java/com/evolveum/midpoint/common/refinery/RefinedAttributeDefinition.java index 5093fe73c1f..cd8c6bf3f27 100644 --- a/infra/common/src/main/java/com/evolveum/midpoint/common/refinery/RefinedAttributeDefinition.java +++ b/infra/common/src/main/java/com/evolveum/midpoint/common/refinery/RefinedAttributeDefinition.java @@ -48,6 +48,7 @@ public class RefinedAttributeDefinition extends ResourceAttributeDefinition impl private String description; private boolean tolerant = true; private boolean isExclusiveStrong = false; + protected boolean secondaryIdentifier = false; private List intolerantValuePattern; private List tolerantValuePattern; private ResourceAttributeDefinition attributeDefinition; @@ -75,6 +76,14 @@ public void setTolerant(boolean tolerant) { this.tolerant = tolerant; } + public boolean isSecondaryIdentifier() { + return secondaryIdentifier; + } + + public void setSecondaryIdentifier(boolean secondaryIdentifier) { + this.secondaryIdentifier = secondaryIdentifier; + } + @Override public boolean canAdd() { return canAdd(DEFAULT_LAYER); @@ -328,6 +337,7 @@ static RefinedAttributeDefinition parse(ResourceAttributeDefinition schemaAttrDe schemaLimitations.getAccess().setModify(schemaAttrDef.canModify()); schemaLimitations.getAccess().setRead(schemaAttrDef.canRead()); + if (schemaHandlingAttrDefType != null) { if (schemaHandlingAttrDefType.getDescription() != null) { @@ -340,6 +350,12 @@ static RefinedAttributeDefinition parse(ResourceAttributeDefinition schemaAttrDe rAttrDef.tolerant = schemaHandlingAttrDefType.isTolerant(); } + if (schemaHandlingAttrDefType.isSecondaryIdentifier() == null){ + rAttrDef.secondaryIdentifier = false; + } else { + rAttrDef.secondaryIdentifier = schemaHandlingAttrDefType.isSecondaryIdentifier(); + } + rAttrDef.tolerantValuePattern = schemaHandlingAttrDefType.getTolerantValuePattern(); rAttrDef.intolerantValuePattern = schemaHandlingAttrDefType.getIntolerantValuePattern(); @@ -365,6 +381,8 @@ static RefinedAttributeDefinition parse(ResourceAttributeDefinition schemaAttrDe limitations.getAccess().setAdd(previousLimitations.getAccess().isAdd()); limitations.getAccess().setRead(previousLimitations.getAccess().isRead()); limitations.getAccess().setModify(previousLimitations.getAccess().isModify()); + limitations.setSecondaryIdentifier(previousLimitations.isSecondaryIdentifier()); + limitations.setUnique(previousLimitations.isUnique()); } previousLimitations = limitations; if (schemaHandlingAttrDefType != null) { @@ -408,6 +426,7 @@ private static void applyLimitationsType(PropertyLimitations limitations, Proper limitations.getAccess().setModify(accessType.isModify()); } } + } private static PropertyLimitationsType getLimitationsType(List limitationsTypes, LayerType layer) throws SchemaException { diff --git a/infra/common/src/main/java/com/evolveum/midpoint/common/refinery/RefinedObjectClassDefinition.java b/infra/common/src/main/java/com/evolveum/midpoint/common/refinery/RefinedObjectClassDefinition.java index 12517f5c97b..2211be3b61c 100644 --- a/infra/common/src/main/java/com/evolveum/midpoint/common/refinery/RefinedObjectClassDefinition.java +++ b/infra/common/src/main/java/com/evolveum/midpoint/common/refinery/RefinedObjectClassDefinition.java @@ -576,7 +576,7 @@ private void processIdentifiers(RefinedAttributeDefinition rAttrDef, ObjectClass if (objectClassDef.isIdentifier(attrName)) { ((Collection)getIdentifiers()).add(rAttrDef); } - if (objectClassDef.isSecondaryIdentifier(attrName)) { + if (objectClassDef.isSecondaryIdentifier(attrName) || rAttrDef.isSecondaryIdentifier()) { ((Collection)getSecondaryIdentifiers()).add(rAttrDef); } } diff --git a/infra/schema/src/main/resources/xml/ns/public/common/common-3.xsd b/infra/schema/src/main/resources/xml/ns/public/common/common-3.xsd index 1322670f293..96546f3d009 100644 --- a/infra/schema/src/main/resources/xml/ns/public/common/common-3.xsd +++ b/infra/schema/src/main/resources/xml/ns/public/common/common-3.xsd @@ -3567,6 +3567,16 @@ + + + + Indicated if the attribute should be considered as secondary identifier. If set to true, + this attribue is stored in repository and user for example by synchronization (correlation + rule), consistency mechanism, etc. + + + + diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ProjectionValuesProcessor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ProjectionValuesProcessor.java index 2b37b481cb4..05ab5b29b73 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ProjectionValuesProcessor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ProjectionValuesProcessor.java @@ -389,16 +389,6 @@ private void processProjections(LensContext context, } LOGGER.trace("User {} satisfies correlation rules.", context.getFocusContext().getObjectNew()); -// result.computeStatus(); -// // if the result is fatal error, it may mean that the -// // already exists expection occures before..but in this -// // scenario it means, the exception was handled and we -// // can mute the result to give better understanding of -// // the situation which happend -// if (result.isError()){ -// result.muteError(); -// } -// // Re-do this same iteration again (do not increase iteration count). // It will recompute the values and therefore enforce the user deltas and enable reconciliation skipUniquenessCheck = true; // to avoid endless loop diff --git a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/consistency/impl/ObjectAlreadyExistHandler.java b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/consistency/impl/ObjectAlreadyExistHandler.java index 400e58b1e88..5416f1544f9 100644 --- a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/consistency/impl/ObjectAlreadyExistHandler.java +++ b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/consistency/impl/ObjectAlreadyExistHandler.java @@ -32,6 +32,7 @@ import com.evolveum.midpoint.prism.query.AndFilter; import com.evolveum.midpoint.prism.query.EqualFilter; import com.evolveum.midpoint.prism.query.ObjectQuery; +import com.evolveum.midpoint.prism.query.OrFilter; import com.evolveum.midpoint.prism.query.RefFilter; import com.evolveum.midpoint.provisioning.api.ProvisioningService; import com.evolveum.midpoint.provisioning.api.ResourceObjectShadowChangeDescription; @@ -124,21 +125,29 @@ public T handleError(T shadow, FailedOperation op, Except private ObjectQuery createQueryByIcfName(ShadowType shadow) throws SchemaException { // TODO: error handling TODO TODO TODO set matching rule instead of null in equlas filter Collection> secondaryIdentifiers = ShadowUtil.getSecondaryIdentifiers(shadow); - PrismProperty nameProperty = null; - if (secondaryIdentifiers.size() != 1){ - nameProperty = shadow.getAttributes().asPrismContainerValue() - .findProperty(new QName(SchemaConstants.NS_ICF_SCHEMA, "name")); - } else { - nameProperty = secondaryIdentifiers.iterator().next(); + + List secondaryIdentifierFilters = new ArrayList(); + + for (ResourceAttribute secondaryIdentifier : secondaryIdentifiers){ + EqualFilter equal = EqualFilter.createEqual(new ItemPath(ShadowType.F_ATTRIBUTES, secondaryIdentifier.getElementName()), secondaryIdentifier); + secondaryIdentifierFilters.add(equal); } + OrFilter orSecondary = OrFilter.createOr((List)secondaryIdentifierFilters); +// PrismProperty nameProperty = null; +// if (secondaryIdentifiers.size() != 1){ +// nameProperty = shadow.getAttributes().asPrismContainerValue() +// .findProperty(new QName(SchemaConstants.NS_ICF_SCHEMA, "name")); +// } else { +// nameProperty = secondaryIdentifiers.iterator().next(); +// } - EqualFilter nameFilter = EqualFilter.createEqual(new ItemPath(ShadowType.F_ATTRIBUTES, nameProperty.getDefinition().getName()),nameProperty); +// EqualFilter nameFilter = EqualFilter.createEqual(new ItemPath(ShadowType.F_ATTRIBUTES, nameProperty.getDefinition().getName()),nameProperty); RefFilter resourceRefFilter = RefFilter.createReferenceEqual(ShadowType.F_RESOURCE_REF, ShadowType.class, prismContext, shadow.getResourceRef().getOid()); EqualFilter objectClassFilter = EqualFilter.createEqual(ShadowType.F_OBJECT_CLASS, ShadowType.class, prismContext, null, shadow.getObjectClass()); - ObjectQuery query = ObjectQuery.createObjectQuery(AndFilter.createAnd(nameFilter, resourceRefFilter, + ObjectQuery query = ObjectQuery.createObjectQuery(AndFilter.createAnd(orSecondary, resourceRefFilter, objectClassFilter)); return query; diff --git a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/util/ProvisioningUtil.java b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/util/ProvisioningUtil.java index ac1f0a995b5..36937c78166 100644 --- a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/util/ProvisioningUtil.java +++ b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/util/ProvisioningUtil.java @@ -197,7 +197,10 @@ public static String getResourceOidFromFilter(List condi return values.get(0).getOid(); } if (NaryLogicalFilter.class.isAssignableFrom(f.getClass())){ - return getResourceOidFromFilter(((NaryLogicalFilter) f).getConditions()); + String resourceOid = getResourceOidFromFilter(((NaryLogicalFilter) f).getConditions()); + if (resourceOid != null){ + return resourceOid; + } } } @@ -221,7 +224,10 @@ public static T getValueFromFilter(List conditions, return (T) ((PrismPropertyValue)values.get(0)).getValue(); } if (NaryLogicalFilter.class.isAssignableFrom(f.getClass())){ - return getValueFromFilter(((NaryLogicalFilter) f).getConditions(), propertyName); + T value = getValueFromFilter(((NaryLogicalFilter) f).getConditions(), propertyName); + if (value != null){ + return value; + } } } From 51e280e68bbfa3bb693042c9dfe69502b10ec0f9 Mon Sep 17 00:00:00 2001 From: "Katarina Valalikova (katkav)" Date: Sat, 4 Oct 2014 10:22:43 +0200 Subject: [PATCH 16/19] fixing build..sorry. --- .../midpoint/common/refinery/RefinedAttributeDefinition.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/infra/common/src/main/java/com/evolveum/midpoint/common/refinery/RefinedAttributeDefinition.java b/infra/common/src/main/java/com/evolveum/midpoint/common/refinery/RefinedAttributeDefinition.java index cd8c6bf3f27..2b0c882d82d 100644 --- a/infra/common/src/main/java/com/evolveum/midpoint/common/refinery/RefinedAttributeDefinition.java +++ b/infra/common/src/main/java/com/evolveum/midpoint/common/refinery/RefinedAttributeDefinition.java @@ -381,8 +381,6 @@ static RefinedAttributeDefinition parse(ResourceAttributeDefinition schemaAttrDe limitations.getAccess().setAdd(previousLimitations.getAccess().isAdd()); limitations.getAccess().setRead(previousLimitations.getAccess().isRead()); limitations.getAccess().setModify(previousLimitations.getAccess().isModify()); - limitations.setSecondaryIdentifier(previousLimitations.isSecondaryIdentifier()); - limitations.setUnique(previousLimitations.isUnique()); } previousLimitations = limitations; if (schemaHandlingAttrDefType != null) { From fd5b9f9ea5faabccdcbaf52a5ceab8103b863895 Mon Sep 17 00:00:00 2001 From: "Katarina Valalikova (katkav)" Date: Sun, 5 Oct 2014 20:07:19 +0200 Subject: [PATCH 17/19] new model execute option - limitPropagation * improved compensation mechanism for already exits situation - propagate changes related only to the conflicting shadow * configurable changes propagation - can be propagated only to the source resource * skipping some steps while computing changes - if specified to propagate changes only for source resource --- .../xml/ns/public/common/common-3.xsd | 21 ++ .../model/api/ModelExecuteOptions.java | 33 ++- .../model/impl/lens/ChangeExecutor.java | 10 +- .../midpoint/model/impl/lens/LensContext.java | 17 ++ .../impl/lens/LensProjectionContext.java | 13 ++ .../lens/projector/AssignmentProcessor.java | 99 ++++++--- .../impl/lens/projector/ContextLoader.java | 25 +++ .../lens/projector/DependencyProcessor.java | 12 +- .../impl/lens/projector/InboundProcessor.java | 4 + .../projector/ObjectTemplateProcessor.java | 41 +--- .../impl/sync/SynchronizationService.java | 50 ++++- .../impl/ObjectAlreadyExistHandler.java | 11 +- .../provisioning/util/ProvisioningUtil.java | 190 ++++++++++-------- 13 files changed, 345 insertions(+), 181 deletions(-) diff --git a/infra/schema/src/main/resources/xml/ns/public/common/common-3.xsd b/infra/schema/src/main/resources/xml/ns/public/common/common-3.xsd index 96546f3d009..ebba96fe8f1 100644 --- a/infra/schema/src/main/resources/xml/ns/public/common/common-3.xsd +++ b/infra/schema/src/main/resources/xml/ns/public/common/common-3.xsd @@ -5204,6 +5204,19 @@ No additional read will be executed. + + + + + If set to true, applicable synchronization reactions will propagate changes only form/to source + resource. In the case focus cotains links to another resource this will be not recomputed + and after reaction execution there may be small inconsistencies. + + It can improve performance for example for initial import. + + Default value is false. + + @@ -5324,6 +5337,7 @@ + @@ -8550,6 +8564,13 @@ + + + + Option to limit change computation and execution only for the source resource. + + + 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 e05fbc8d2f4..a01d334b7cb 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 @@ -65,6 +65,11 @@ public class ModelExecuteOptions implements Serializable, Cloneable { Boolean isImport; + /** + * Option to limit propagation only for the source resource + */ + Boolean limitPropagation; + public Boolean getForce() { return force; @@ -224,6 +229,27 @@ public static boolean isExecuteImmediatelyAfterApproval(ModelExecuteOptions opti } return options.executeImmediatelyAfterApproval; } + + public static ModelExecuteOptions createIsLimitPropagation() { + ModelExecuteOptions opts = new ModelExecuteOptions(); + opts.setLimitPropagation(true); + return opts; + + } + + public void setLimitPropagation(Boolean limitPropagation) { + this.limitPropagation = limitPropagation; + } + + public static boolean isLimitPropagation(ModelExecuteOptions options){ + if (options == null){ + return false; + } + if (options.limitPropagation == null){ + return false; + } + return options.limitPropagation; + } public static ModelExecuteOptions createExecuteImmediatelyAfterApproval(){ ModelExecuteOptions opts = new ModelExecuteOptions(); @@ -240,6 +266,7 @@ public ModelExecuteOptionsType toModelExecutionOptionsType() { retval.setExecuteImmediatelyAfterApproval(executeImmediatelyAfterApproval); retval.setOverwrite(overwrite); retval.setIsImport(isImport); + retval.setLimitPropagation(limitPropagation); return retval; } @@ -255,6 +282,7 @@ public static ModelExecuteOptions fromModelExecutionOptionsType(ModelExecuteOpti retval.setExecuteImmediatelyAfterApproval(type.isExecuteImmediatelyAfterApproval()); retval.setOverwrite(type.isOverwrite()); retval.setIsImport(type.isIsImport()); + retval.setLimitPropagation(type.isLimitPropagation()); return retval; } @@ -286,6 +314,9 @@ public static ModelExecuteOptions fromRestOptions(List options){ if (ModelExecuteOptionsType.F_IS_IMPORT.getLocalPart().equals(option)){ retVal.setIsImport(true);; } + if (ModelExecuteOptionsType.F_LIMIT_PROPAGATION.getLocalPart().equals(option)){ + retVal.setIsImport(true);; + } } return retVal; @@ -297,7 +328,7 @@ public String toString(){ + ",reconcile=" + reconcile + ",executeImmediatelyAfterApproval=" + executeImmediatelyAfterApproval + ",overwrite=" + overwrite - + "]"; + + "limitPropagation="+limitPropagation+"]"; } public ModelExecuteOptions clone() { diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/ChangeExecutor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/ChangeExecutor.java index eb1f8a73688..f4fe52cf74d 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/ChangeExecutor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/ChangeExecutor.java @@ -169,7 +169,7 @@ public void executeChanges(LensContext syncContext, Ta throw e; } catch (ObjectAlreadyExistsException e) { subResult.computeStatus(); - if (!subResult.isSuccess()) { + if (!subResult.isSuccess() && !subResult.isHandledError()) { subResult.recordFatalError(e); } result.computeStatusComposite(); @@ -205,6 +205,11 @@ public void executeChanges(LensContext syncContext, Ta if (accCtx.getWave() != syncContext.getExecutionWave()) { continue; } + + if (!accCtx.isCanProject()){ + continue; + } + OperationResult subResult = result.createSubresult(OPERATION_EXECUTE_PROJECTION+"."+accCtx.getObjectTypeClass().getSimpleName()); subResult.addContext("discriminator", accCtx.getResourceShadowDiscriminator()); if (accCtx.getResource() != null) { @@ -290,7 +295,8 @@ public void executeChanges(LensContext syncContext, Ta // and also do not set fatal error to the operation result, this is a special case // if it is fatal, it will be set later // but we need to set some result - subResult.recordHandledError(e); + subResult.recordSuccess(); + subResult.muteLastSubresultError(); continue; } catch (CommunicationException e) { recordProjectionExecutionException(e, accCtx, subResult, SynchronizationPolicyDecision.BROKEN); 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 4380b5407e8..3eb5567f066 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 @@ -98,6 +98,8 @@ public class LensContext implements ModelContext { * Current wave of execution. */ int executionWave = 0; + + private String triggeredResourceOid; transient private boolean isFresh = false; transient private boolean isRequestAuthorized = false; @@ -149,6 +151,21 @@ protected PrismContext getNotNullPrismContext() { 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 String getTriggeredResourceOid() { + return triggeredResourceOid; + } + @Override public ModelState getState() { diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensProjectionContext.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensProjectionContext.java index 29c09f08093..c7f53d5dd3c 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensProjectionContext.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensProjectionContext.java @@ -132,6 +132,11 @@ public class LensProjectionContext extends LensElementContext implem */ private boolean doReconciliation; + /** + * false if the context should be not taken into the account while synchronizing changes from other resource + */ + private boolean canProject = true; + /** @@ -510,6 +515,14 @@ public ValuePolicyType getAccountPasswordPolicy() { return accountPasswordPolicy; } + public void setCanProject(boolean canProject) { + this.canProject = canProject; + } + + public boolean isCanProject() { + return canProject; + } + public void setAccountPasswordPolicy(ValuePolicyType accountPasswordPolicy) { this.accountPasswordPolicy = accountPasswordPolicy; } 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 c8c29906a8a..af08e1ad72f 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 @@ -16,7 +16,19 @@ package com.evolveum.midpoint.model.impl.lens.projector; -import ch.qos.logback.classic.Logger; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import javax.xml.datatype.XMLGregorianCalendar; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; import com.evolveum.midpoint.common.ActivationComputer; import com.evolveum.midpoint.common.refinery.ResourceShadowDiscriminator; @@ -39,7 +51,15 @@ import com.evolveum.midpoint.model.impl.lens.LensFocusContext; import com.evolveum.midpoint.model.impl.lens.LensProjectionContext; import com.evolveum.midpoint.model.impl.lens.LensUtil; -import com.evolveum.midpoint.prism.*; +import com.evolveum.midpoint.prism.PrismContainer; +import com.evolveum.midpoint.prism.PrismContainerDefinition; +import com.evolveum.midpoint.prism.PrismContainerValue; +import com.evolveum.midpoint.prism.PrismContext; +import com.evolveum.midpoint.prism.PrismObjectDefinition; +import com.evolveum.midpoint.prism.PrismPropertyValue; +import com.evolveum.midpoint.prism.PrismReferenceDefinition; +import com.evolveum.midpoint.prism.PrismReferenceValue; +import com.evolveum.midpoint.prism.PrismValue; import com.evolveum.midpoint.prism.delta.ContainerDelta; import com.evolveum.midpoint.prism.delta.DeltaMapTriple; import com.evolveum.midpoint.prism.delta.DeltaSetTriple; @@ -47,20 +67,18 @@ import com.evolveum.midpoint.prism.delta.ObjectDelta; import com.evolveum.midpoint.prism.delta.PlusMinusZero; import com.evolveum.midpoint.prism.delta.PrismValueDeltaSetTriple; -import com.evolveum.midpoint.prism.delta.PropertyDelta; import com.evolveum.midpoint.prism.path.IdItemPathSegment; import com.evolveum.midpoint.prism.path.ItemPath; import com.evolveum.midpoint.prism.path.NameItemPathSegment; import com.evolveum.midpoint.provisioning.api.ProvisioningService; import com.evolveum.midpoint.repo.api.RepositoryService; +import com.evolveum.midpoint.schema.constants.SchemaConstants; import com.evolveum.midpoint.schema.result.OperationResult; -import com.evolveum.midpoint.schema.util.MiscSchemaUtil; +import com.evolveum.midpoint.schema.util.ObjectResolver; import com.evolveum.midpoint.schema.util.ObjectTypeUtil; import com.evolveum.midpoint.schema.util.SchemaDebugUtil; -import com.evolveum.midpoint.schema.util.ObjectResolver; import com.evolveum.midpoint.task.api.Task; -import com.evolveum.midpoint.util.DebugUtil; -import com.evolveum.midpoint.util.MiscUtil; +import com.evolveum.midpoint.util.QNameUtil; import com.evolveum.midpoint.util.exception.CommunicationException; import com.evolveum.midpoint.util.exception.ConfigurationException; import com.evolveum.midpoint.util.exception.ExpressionEvaluationException; @@ -68,7 +86,6 @@ import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.util.exception.SecurityViolationException; import com.evolveum.midpoint.util.exception.SystemException; -import com.evolveum.midpoint.util.exception.TunnelException; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.xml.ns._public.common.common_3.AbstractRoleType; @@ -77,28 +94,11 @@ import com.evolveum.midpoint.xml.ns._public.common.common_3.ConstructionType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ExclusionType; import com.evolveum.midpoint.xml.ns._public.common.common_3.FocusType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.MappingType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectTemplateType; 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.ProjectionPolicyType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.RoleType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowKindType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.stereotype.Component; - -import javax.xml.datatype.DatatypeConstants; -import javax.xml.datatype.XMLGregorianCalendar; -import javax.xml.namespace.QName; - -import java.util.*; -import java.util.Map.Entry; /** * Assignment processor is recomputing user assignments. It recomputes all the assignements whether they are direct @@ -157,6 +157,10 @@ public void processAssignmentsProjections(LensContext // We can do this only for FocusType. return; } +// if (ModelExecuteOptions.isLimitPropagation(context.getOptions()) && SchemaConstants.CHANGE_CHANNEL_DISCOVERY.equals(QNameUtil.uriToQName(context.getChannel()))){ +// //do not execute assignment if the execution was triggered by compensation mechanism and limitPropagation is set +// return; +// } processAssignmentsProjectionsWithFocus((LensContext)context, now, task, result); } @@ -463,6 +467,8 @@ private void processAssignmentsProjectionsWithFocus(LensCo LOGGER.trace("Projection maps:\n{}", constructionMapTriple.debugDump()); } + + // Now we are processing constructions from all the three sets once again. We will create projection contexts // for them if not yet created. Now we will do the usual routing for converting the delta triples to deltas. // I.e. zero means unchanged, plus means added, minus means deleted. That will be recorded in the SynchronizationPolicyDecision. @@ -470,13 +476,30 @@ private void processAssignmentsProjectionsWithFocus(LensCo // actual attribute deltas (in consolidation processor). Collection allAccountTypes = constructionMapTriple.unionKeySets(); for (ResourceShadowDiscriminator rat : allAccountTypes) { - + if (rat.getResourceOid() == null) { throw new IllegalStateException("Resource OID null in ResourceAccountType during assignment processing"); } if (rat.getIntent() == null) { throw new IllegalStateException("Account type is null in ResourceAccountType during assignment processing"); } + + boolean processOnlyExistingProjCxts = false; + if (ModelExecuteOptions.isLimitPropagation(context.getOptions())){ + if (context.getTriggeredResourceOid() != null + && !rat.getResourceOid().equals(context.getTriggeredResourceOid())) { + LOGGER.trace( + "Skipping processing construction for shadow identified by {} because of limitation to propagate changes only for resource {}", + rat, context.getTriggeredResourceOid()); + continue; + } + + if (SchemaConstants.CHANGE_CHANNEL_DISCOVERY.equals(QNameUtil.uriToQName(context.getChannel()))){ + LOGGER.trace("Processing of shadow identified by {} will be skipped because of limitation for discovery channel."); + processOnlyExistingProjCxts = true; + } + } + String desc = rat.toHumanReadableString(); // SITUATION: The projection should exist (if valid), there is NO CHANGE in assignments @@ -484,6 +507,9 @@ private void processAssignmentsProjectionsWithFocus(LensCo LensProjectionContext projectionContext = context.findProjectionContext(rat); if (projectionContext == null) { + if (processOnlyExistingProjCxts){ + continue; + } // The projection should exist before the change but it does not // This happens during reconciliation if there is an inconsistency. // Pretend that the assignment was just added. That should do. @@ -516,6 +542,9 @@ private void processAssignmentsProjectionsWithFocus(LensCo LensProjectionContext projectionContext = context.findProjectionContext(rat); if (projectionContext == null) { + if (processOnlyExistingProjCxts){ + continue; + } // The projection should exist before the change but it does not // This happens during reconciliation if there is an inconsistency. // Pretend that the assignment was just added. That should do. @@ -532,8 +561,14 @@ private void processAssignmentsProjectionsWithFocus(LensCo } else if (plusPack.hasValidAssignment() && !minusPack.hasValidAssignment()) { // Assignment became valid. Same as if it was assigned. - LensProjectionContext projectionContext = LensUtil.getOrCreateProjectionContext(context, rat); - projectionContext.setAssigned(true); + LensProjectionContext projectionContext = context.findProjectionContext(rat); + if (projectionContext == null){ + if (processOnlyExistingProjCxts){ + continue; + } + projectionContext = LensUtil.getOrCreateProjectionContext(context, rat); + } + projectionContext.setAssigned(true); projectionContext.setLegalOld(false); AssignmentPolicyEnforcementType assignmentPolicyEnforcement = projectionContext.getAssignmentPolicyEnforcementType(); if (assignmentPolicyEnforcement != AssignmentPolicyEnforcementType.NONE) { @@ -544,7 +579,13 @@ private void processAssignmentsProjectionsWithFocus(LensCo } else if (!plusPack.hasValidAssignment() && minusPack.hasValidAssignment()) { // Assignment became invalid. Same as if it was unassigned. if (accountExists(context,rat)) { - LensProjectionContext projectionContext = LensUtil.getOrCreateProjectionContext(context, rat); + LensProjectionContext projectionContext = context.findProjectionContext(rat); + if (projectionContext == null){ + if (processOnlyExistingProjCxts){ + continue; + } + projectionContext = LensUtil.getOrCreateProjectionContext(context, rat); + } projectionContext.setAssigned(false); projectionContext.setLegalOld(true); diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ContextLoader.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ContextLoader.java index 1ffff27a164..08f2d919636 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ContextLoader.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ContextLoader.java @@ -24,6 +24,7 @@ import javax.xml.namespace.QName; import com.evolveum.midpoint.schema.constants.ObjectTypes; +import com.evolveum.midpoint.schema.constants.SchemaConstants; import com.evolveum.midpoint.schema.result.OperationResultStatus; import com.evolveum.midpoint.xml.ns._public.common.common_3.*; @@ -34,6 +35,7 @@ import com.evolveum.midpoint.common.refinery.RefinedObjectClassDefinition; import com.evolveum.midpoint.common.refinery.ResourceShadowDiscriminator; +import com.evolveum.midpoint.model.api.ModelExecuteOptions; import com.evolveum.midpoint.model.api.context.SynchronizationPolicyDecision; import com.evolveum.midpoint.model.impl.lens.LensContext; import com.evolveum.midpoint.model.impl.lens.LensFocusContext; @@ -56,6 +58,7 @@ import com.evolveum.midpoint.schema.SelectorOptions; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.schema.util.ShadowUtil; +import com.evolveum.midpoint.util.QNameUtil; import com.evolveum.midpoint.util.exception.CommunicationException; import com.evolveum.midpoint.util.exception.ConfigurationException; import com.evolveum.midpoint.util.exception.ObjectNotFoundException; @@ -481,6 +484,11 @@ private void loadLinkRefsFromFocus(LensContext context, throw new SchemaException("Null or empty OID in link reference in " + focus); } LensProjectionContext existingAccountContext = findAccountContext(oid, context); + + if (!canBeLoaded(context, existingAccountContext)){ + continue; + } + if (existingAccountContext != null) { // TODO: do we need to reload the account inside here? yes we need @@ -769,6 +777,15 @@ private void loadProjectionContextsSync(LensContext co } } + private boolean canBeLoaded(LensContext context, LensProjectionContext projCtx){ + if (QNameUtil.qNameToUri(SchemaConstants.CHANGE_CHANNEL_DISCOVERY).equals(context.getChannel()) && projCtx == null && ModelExecuteOptions.isLimitPropagation(context.getOptions())) { + // avoid to create projection context if the channel which + // triggered this operation is discovery..we need only + // projection context of discovered shadow + return false; + } + return true; + } private LensProjectionContext getOrCreateAccountContext(LensContext context, PrismObject account, OperationResult result) throws ObjectNotFoundException, CommunicationException, SchemaException, ConfigurationException, SecurityViolationException { @@ -961,6 +978,14 @@ private void finishLoadOfProjectionContext(LensContext } } + //set limitation, e.g. if this projection context should be recomputed and processed by projector + if (ModelExecuteOptions.isLimitPropagation(context.getOptions())){ + if (context.getTriggeredResourceOid() != null){ + if (!context.getTriggeredResourceOid().equals(resourceOid)){ + projContext.setCanProject(false); + } + } + } } private boolean needToReload(LensContext context, diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/DependencyProcessor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/DependencyProcessor.java index 87d98aeda4e..5efcdb08c55 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/DependencyProcessor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/DependencyProcessor.java @@ -448,6 +448,9 @@ public void preprocessDependencies(LensContext context } for (LensProjectionContext projContext : context.getProjectionContexts()){ + if (!projContext.isCanProject()){ + continue; + } for (ResourceObjectTypeDependencyType dependency: projContext.getDependencies()) { ResourceShadowDiscriminator refRat = new ResourceShadowDiscriminator(dependency, @@ -456,20 +459,17 @@ public void preprocessDependencies(LensContext context LensProjectionContext dependencyAccountContext = context.findProjectionContext(refRat); ResourceObjectTypeDependencyStrictnessType strictness = ResourceTypeUtil.getDependencyStrictness(dependency); if (dependencyAccountContext != null){ + if (!dependencyAccountContext.isCanProject()){ + continue; + } // We have the context of the object that we depend on. We need to check if it was provisioned. if (strictness == ResourceObjectTypeDependencyStrictnessType.STRICT || strictness == ResourceObjectTypeDependencyStrictnessType.RELAXED) { if (wasExecuted(dependencyAccountContext)) { // everything OK if (ResourceTypeUtil.isForceLoadDependentShadow(dependency) && !dependencyAccountContext.isDelete()){ - LOGGER.info("FORCE TO LOAD FULL ACCOUNT " + dependencyAccountContext); dependencyAccountContext.setDoReconciliation(true); projContext.setDoReconciliation(true); -// if (dependencyAccountContext.getExecutedDeltas() != null && !dependencyAccountContext.getExecutedDeltas().isEmpty()){ -// if (context.getProjectionWave() < context.getExecutionWave()){ -// context.resetProjectionWave(); -// } -// } } } } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/InboundProcessor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/InboundProcessor.java index 8180ce826c6..de830d931f3 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/InboundProcessor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/InboundProcessor.java @@ -135,6 +135,10 @@ void processInboundFocal(LensContext context, Task task try { for (LensProjectionContext accountContext : context.getProjectionContexts()) { + if (!accountContext.isCanProject()){ + LOGGER.trace("Skipping processing of inbound expressions for account {}: there is a limit to propagate changes only from resource", context.getTriggeredResourceOid()); + continue; + } ResourceShadowDiscriminator rat = accountContext.getResourceShadowDiscriminator(); ObjectDelta aPrioriDelta = getAPrioriDelta(context, accountContext); diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ObjectTemplateProcessor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ObjectTemplateProcessor.java index 8dc00a7fe5e..7d82d1629e4 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ObjectTemplateProcessor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ObjectTemplateProcessor.java @@ -15,94 +15,58 @@ */ package com.evolveum.midpoint.model.impl.lens.projector; -import static com.evolveum.midpoint.common.InternalsConfig.consistencyChecks; - import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.Map.Entry; -import javax.xml.bind.JAXBElement; import javax.xml.datatype.DatatypeConstants; import javax.xml.datatype.XMLGregorianCalendar; -import javax.xml.namespace.QName; -import org.apache.xpath.FoundIndex; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; import com.evolveum.midpoint.common.ActivationComputer; -import com.evolveum.midpoint.common.Clock; -import com.evolveum.midpoint.common.refinery.RefinedAttributeDefinition; -import com.evolveum.midpoint.common.refinery.RefinedObjectClassDefinition; +import com.evolveum.midpoint.model.api.ModelExecuteOptions; import com.evolveum.midpoint.model.api.PolicyViolationException; import com.evolveum.midpoint.model.common.expression.ExpressionFactory; -import com.evolveum.midpoint.model.common.expression.ExpressionVariables; import com.evolveum.midpoint.model.common.expression.ObjectDeltaObject; -import com.evolveum.midpoint.model.common.expression.StringPolicyResolver; import com.evolveum.midpoint.model.common.mapping.Mapping; import com.evolveum.midpoint.model.common.mapping.MappingFactory; import com.evolveum.midpoint.model.impl.ModelObjectResolver; import com.evolveum.midpoint.model.impl.lens.ItemValueWithOrigin; import com.evolveum.midpoint.model.impl.lens.LensContext; import com.evolveum.midpoint.model.impl.lens.LensFocusContext; -import com.evolveum.midpoint.model.impl.lens.LensProjectionContext; import com.evolveum.midpoint.model.impl.lens.LensUtil; import com.evolveum.midpoint.model.impl.trigger.RecomputeTriggerHandler; -import com.evolveum.midpoint.model.impl.util.Utils; -import com.evolveum.midpoint.prism.ComplexTypeDefinition; -import com.evolveum.midpoint.prism.Item; -import com.evolveum.midpoint.prism.ItemDefinition; -import com.evolveum.midpoint.prism.OriginType; import com.evolveum.midpoint.prism.PrismContainerDefinition; import com.evolveum.midpoint.prism.PrismContainerValue; import com.evolveum.midpoint.prism.PrismContext; import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.PrismObjectDefinition; -import com.evolveum.midpoint.prism.PrismPropertyDefinition; -import com.evolveum.midpoint.prism.PrismPropertyValue; import com.evolveum.midpoint.prism.PrismValue; -import com.evolveum.midpoint.prism.delta.ChangeType; import com.evolveum.midpoint.prism.delta.ContainerDelta; import com.evolveum.midpoint.prism.delta.DeltaSetTriple; import com.evolveum.midpoint.prism.delta.ItemDelta; -import com.evolveum.midpoint.prism.delta.ObjectDelta; -import com.evolveum.midpoint.prism.delta.PropertyDelta; import com.evolveum.midpoint.prism.path.ItemPath; import com.evolveum.midpoint.repo.api.RepositoryService; -import com.evolveum.midpoint.schema.constants.ExpressionConstants; -import com.evolveum.midpoint.schema.constants.SchemaConstants; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.util.exception.ExpressionEvaluationException; import com.evolveum.midpoint.util.exception.ObjectAlreadyExistsException; import com.evolveum.midpoint.util.exception.ObjectNotFoundException; import com.evolveum.midpoint.util.exception.SchemaException; -import com.evolveum.midpoint.util.exception.SystemException; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ActivationStatusType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ActivationType; import com.evolveum.midpoint.xml.ns._public.common.common_3.FocusType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.GenerateExpressionEvaluatorType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.MappingStrengthType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.MappingType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectTemplateMappingEvaluationPhaseType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectTemplateMappingType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectTemplateType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.PasswordType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.StringPolicyType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.TimeIntervalStatusType; import com.evolveum.midpoint.xml.ns._public.common.common_3.TriggerType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ValuePolicyType; -import com.evolveum.prism.xml.ns._public.types_3.PolyStringType; /** * Processor to handle object template. @@ -148,7 +112,8 @@ public void processTemplate(LensContext context, Object LOGGER.trace("Skipping processing of object template: focus delete"); return; } - ObjectTemplateType objectTemplate = context.getFocusTemplate(); + + ObjectTemplateType objectTemplate = context.getFocusTemplate(); if (objectTemplate == null) { // No applicable template LOGGER.trace("Skipping processing of object template: no object template"); diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/sync/SynchronizationService.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/sync/SynchronizationService.java index 0023ab134ec..62424934432 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/sync/SynchronizationService.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/sync/SynchronizationService.java @@ -39,6 +39,7 @@ import com.evolveum.midpoint.audit.api.AuditService; import com.evolveum.midpoint.common.InternalsConfig; import com.evolveum.midpoint.common.refinery.ResourceShadowDiscriminator; +import com.evolveum.midpoint.model.api.ModelExecuteOptions; import com.evolveum.midpoint.model.api.PolicyViolationException; import com.evolveum.midpoint.model.common.expression.Expression; import com.evolveum.midpoint.model.common.expression.ExpressionEvaluationContext; @@ -89,6 +90,7 @@ import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.util.DOMUtil; import com.evolveum.midpoint.util.MiscUtil; +import com.evolveum.midpoint.util.QNameUtil; import com.evolveum.midpoint.util.exception.CommunicationException; import com.evolveum.midpoint.util.exception.ConfigurationException; import com.evolveum.midpoint.util.exception.ExpressionEvaluationException; @@ -652,11 +654,16 @@ private void reactToChange(Class focusClass, ResourceOb } } + Boolean limitPropagation = determinePropagationLimitation(synchronizationPolicy, reactionDefinition, change.getSourceChannel()); + ModelExecuteOptions options = new ModelExecuteOptions(); + options.setReconcile(doReconciliation); + options.setLimitPropagation(limitPropagation); + boolean willSynchronize = isSynchronize(reactionDefinition); LensContext lensContext = null; if (willSynchronize) { lensContext = createLensContext(focusClass, change, reactionDefinition, synchronizationPolicy, situation, - doReconciliation, configuration, parentResult); + options, configuration, parentResult); } if (LOGGER.isTraceEnabled() && lensContext != null) { @@ -693,17 +700,46 @@ private Boolean determineReconciliation(ObjectSynchronizationType synchronizatio } return null; } + + private Boolean determinePropagationLimitation(ObjectSynchronizationType synchronizationPolicy, + SynchronizationReactionType reactionDefinition, String channel) { + + if (StringUtils.isNotBlank(channel)){ + QName channelQName = QNameUtil.uriToQName(channel); + // discovery channel is used when compensating some inconsistent + // state. Therefe we do not want to propagate changes to other + // resource. We only want to resolve the problem and continue in + // previous provisioning/synchronization during which his + // compensation was triggered + if (SchemaConstants.CHANGE_CHANNEL_DISCOVERY.equals(channelQName)){ + return true; + } + } + + if (reactionDefinition.isLimitPropagation() != null) { + return reactionDefinition.isLimitPropagation(); + } + if (synchronizationPolicy.isLimitPropagation() != null) { + return synchronizationPolicy.isLimitPropagation(); + } + return null; + } private LensContext createLensContext(Class focusClass, ResourceObjectShadowChangeDescription change, SynchronizationReactionType reactionDefinition, ObjectSynchronizationType synchronizationPolicy, - SynchronizationSituation situation, Boolean doReconciliation, PrismObject configuration, + SynchronizationSituation situation, ModelExecuteOptions options, PrismObject configuration, OperationResult parentResult) throws ObjectNotFoundException, SchemaException { LensContext context = contextFactory.createSyncContext(focusClass, change); context.setLazyAuditRequest(true); context.setSystemConfiguration(configuration); - - ResourceType resource = change.getResource().asObjectable(); + context.setOptions(options); + + ResourceType resource = change.getResource().asObjectable(); + if (ModelExecuteOptions.isLimitPropagation(options)){ + context.setTriggeredResource(resource); + } + context.rememberResource(resource); PrismObject shadow = getShadowFromChange(change); if (InternalsConfig.consistencyChecks) shadow.checkConsistence(); @@ -742,10 +778,8 @@ private LensContext createLensContext(Class focusCla projectionContext.setExists(true); } - if (doReconciliation != null) { - projectionContext.setDoReconciliation(doReconciliation); - } - + projectionContext.setDoReconciliation(ModelExecuteOptions.isReconcile(options)); + // Focus context if (situation.getCurrentOwner() != null) { F focusType = situation.getCurrentOwner(); diff --git a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/consistency/impl/ObjectAlreadyExistHandler.java b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/consistency/impl/ObjectAlreadyExistHandler.java index 5416f1544f9..c6802d8f98c 100644 --- a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/consistency/impl/ObjectAlreadyExistHandler.java +++ b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/consistency/impl/ObjectAlreadyExistHandler.java @@ -108,7 +108,7 @@ public T handleError(T shadow, FailedOperation op, Except changeNotificationDispatcher.notifyChange(change, task, operationResult); } } finally { - operationResult.computeStatus(); + operationResult.computeStatus(); } if (operationResult.isSuccess()) { parentResult.recordSuccess(); @@ -133,15 +133,6 @@ private ObjectQuery createQueryByIcfName(ShadowType shadow) throws SchemaExcepti secondaryIdentifierFilters.add(equal); } OrFilter orSecondary = OrFilter.createOr((List)secondaryIdentifierFilters); -// PrismProperty nameProperty = null; -// if (secondaryIdentifiers.size() != 1){ -// nameProperty = shadow.getAttributes().asPrismContainerValue() -// .findProperty(new QName(SchemaConstants.NS_ICF_SCHEMA, "name")); -// } else { -// nameProperty = secondaryIdentifiers.iterator().next(); -// } - -// EqualFilter nameFilter = EqualFilter.createEqual(new ItemPath(ShadowType.F_ATTRIBUTES, nameProperty.getDefinition().getName()),nameProperty); RefFilter resourceRefFilter = RefFilter.createReferenceEqual(ShadowType.F_RESOURCE_REF, ShadowType.class, prismContext, shadow.getResourceRef().getOid()); EqualFilter objectClassFilter = EqualFilter.createEqual(ShadowType.F_OBJECT_CLASS, ShadowType.class, prismContext, diff --git a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/util/ProvisioningUtil.java b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/util/ProvisioningUtil.java index 36937c78166..58babc2b883 100644 --- a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/util/ProvisioningUtil.java +++ b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/util/ProvisioningUtil.java @@ -76,7 +76,7 @@ import java.util.List; public class ProvisioningUtil { - + private static final QName FAKE_SCRIPT_ARGUMENT_NAME = new QName(SchemaConstants.NS_C, "arg"); private static final Trace LOGGER = TraceManager.getTrace(ProvisioningUtil.class); @@ -119,12 +119,14 @@ public static void normalizeShadow(T shadow, OperationRes } } - - public static PolyString determineShadowName(ShadowType shadow) throws SchemaException { + + public static PolyString determineShadowName(ShadowType shadow) + throws SchemaException { return determineShadowName(shadow.asPrismObject()); } - - public static PolyString determineShadowName(PrismObject shadow) throws SchemaException { + + public static PolyString determineShadowName(PrismObject shadow) + throws SchemaException { String stringName = determineShadowStringName(shadow); if (stringName == null) { return null; @@ -132,7 +134,8 @@ public static PolyString determineShadowName(PrismObject< return new PolyString(stringName); } - public static String determineShadowStringName(PrismObject shadow) throws SchemaException { + public static String determineShadowStringName(PrismObject shadow) + throws SchemaException { ResourceAttributeContainer attributesContainer = ShadowUtil.getAttributesContainer(shadow); ResourceAttribute namingAttribute = attributesContainer.getNamingAttribute(); if (namingAttribute == null || namingAttribute.isEmpty()) { @@ -151,8 +154,8 @@ public static String determineShadowStringName(PrismObjec } } } else { - return attributesContainer.findAttribute(ConnectorFactoryIcfImpl.ICFS_NAME).getValue(String.class) - .getValue(); + return attributesContainer.findAttribute(ConnectorFactoryIcfImpl.ICFS_NAME) + .getValue(String.class).getValue(); } // Identifier is not usable as name // TODO: better identification of a problem @@ -160,91 +163,96 @@ public static String determineShadowStringName(PrismObjec } // TODO: Error handling List> possibleValues = namingAttribute.getValues(); - - if (possibleValues.size() > 1){ - throw new SchemaException("Cannot determine name of shadow. Found more than one value for naming attribute (attr: "+namingAttribute.getElementName()+", values: {}"+possibleValues+")" ); + + if (possibleValues.size() > 1) { + throw new SchemaException( + "Cannot determine name of shadow. Found more than one value for naming attribute (attr: " + + namingAttribute.getElementName() + ", values: {}" + possibleValues + ")"); } - + PrismPropertyValue value = possibleValues.iterator().next(); - - if (value == null){ + + if (value == null) { throw new SchemaException("Naming attribute has no value. Could not determine shadow name."); } - + return value.getValue(); -// return attributesContainer.getNamingAttribute().getValue().getValue(); + // return + // attributesContainer.getNamingAttribute().getValue().getValue(); } - - public static PrismObjectDefinition getResourceObjectShadowDefinition( PrismContext prismContext) { return prismContext.getSchemaRegistry().findObjectDefinitionByCompileTimeClass(ShadowType.class); } - + @SuppressWarnings("unchecked") - public static String getResourceOidFromFilter(List conditions) throws SchemaException{ - - for (ObjectFilter f : conditions){ - if (f instanceof RefFilter && ShadowType.F_RESOURCE_REF.equals(((RefFilter) f).getDefinition().getName())){ - List values = (List)((RefFilter) f).getValues(); - if (values.size() > 1){ - throw new SchemaException("More than one resource references defined in the search query."); - } - if (values.size() < 1){ - throw new SchemaException("Search query does not have specified resource reference."); - } - return values.get(0).getOid(); + public static String getResourceOidFromFilter(List conditions) + throws SchemaException { + + for (ObjectFilter f : conditions) { + if (f instanceof RefFilter + && ShadowType.F_RESOURCE_REF.equals(((RefFilter) f).getDefinition().getName())) { + List values = (List) ((RefFilter) f).getValues(); + if (values.size() > 1) { + throw new SchemaException( + "More than one resource references defined in the search query."); } - if (NaryLogicalFilter.class.isAssignableFrom(f.getClass())){ - String resourceOid = getResourceOidFromFilter(((NaryLogicalFilter) f).getConditions()); - if (resourceOid != null){ - return resourceOid; - } + if (values.size() < 1) { + throw new SchemaException("Search query does not have specified resource reference."); } + return values.get(0).getOid(); } - - return null; - + if (NaryLogicalFilter.class.isAssignableFrom(f.getClass())) { + String resourceOid = getResourceOidFromFilter(((NaryLogicalFilter) f).getConditions()); + if (resourceOid != null) { + return resourceOid; + } + } + } + + return null; + } - + @SuppressWarnings("rawtypes") - public static T getValueFromFilter(List conditions, QName propertyName) throws SchemaException{ - ItemPath propertyPath = new ItemPath(propertyName); - for (ObjectFilter f : conditions){ - if (f instanceof EqualFilter && propertyPath.equivalent(((EqualFilter) f).getFullPath())){ - List values = ((EqualFilter) f).getValues(); - if (values.size() > 1){ - throw new SchemaException("More than one "+propertyName+" defined in the search query."); - } - if (values.size() < 1){ - throw new SchemaException("Search query does not have specified "+propertyName+"."); - } - - return (T) ((PrismPropertyValue)values.get(0)).getValue(); + public static T getValueFromFilter(List conditions, QName propertyName) + throws SchemaException { + ItemPath propertyPath = new ItemPath(propertyName); + for (ObjectFilter f : conditions) { + if (f instanceof EqualFilter && propertyPath.equivalent(((EqualFilter) f).getFullPath())) { + List values = ((EqualFilter) f).getValues(); + if (values.size() > 1) { + throw new SchemaException("More than one " + propertyName + + " defined in the search query."); } - if (NaryLogicalFilter.class.isAssignableFrom(f.getClass())){ - T value = getValueFromFilter(((NaryLogicalFilter) f).getConditions(), propertyName); - if (value != null){ - return value; - } + if (values.size() < 1) { + throw new SchemaException("Search query does not have specified " + propertyName + "."); } + + return (T) ((PrismPropertyValue) values.get(0)).getValue(); } - - return null; + if (NaryLogicalFilter.class.isAssignableFrom(f.getClass())) { + T value = getValueFromFilter(((NaryLogicalFilter) f).getConditions(), propertyName); + if (value != null) { + return value; + } + } + } + + return null; } - - public static ExecuteProvisioningScriptOperation convertToScriptOperation(ProvisioningScriptType scriptType, - String desc, PrismContext prismContext) throws SchemaException { + + public static ExecuteProvisioningScriptOperation convertToScriptOperation( + ProvisioningScriptType scriptType, String desc, PrismContext prismContext) throws SchemaException { ExecuteProvisioningScriptOperation scriptOperation = new ExecuteProvisioningScriptOperation(); - PrismPropertyDefinition scriptArgumentDefinition = new PrismPropertyDefinition(FAKE_SCRIPT_ARGUMENT_NAME, - DOMUtil.XSD_STRING, prismContext); - + PrismPropertyDefinition scriptArgumentDefinition = new PrismPropertyDefinition( + FAKE_SCRIPT_ARGUMENT_NAME, DOMUtil.XSD_STRING, prismContext); + for (ProvisioningScriptArgumentType argument : scriptType.getArgument()) { ExecuteScriptArgument arg = new ExecuteScriptArgument(argument.getName(), - StaticExpressionUtil.getStaticOutput(argument, scriptArgumentDefinition, - desc, + StaticExpressionUtil.getStaticOutput(argument, scriptArgumentDefinition, desc, ExpressionReturnMultiplicityType.SINGLE, prismContext)); scriptOperation.getArgument().add(arg); } @@ -260,61 +268,69 @@ public static ExecuteProvisioningScriptOperation convertToScriptOperation(Provis scriptOperation.setConnectorHost(false); scriptOperation.setResourceHost(true); } - + return scriptOperation; } - - public static AttributesToReturn createAttributesToReturn(RefinedObjectClassDefinition objectClassDefinition, - ResourceType resource) throws SchemaException { + + public static AttributesToReturn createAttributesToReturn( + RefinedObjectClassDefinition objectClassDefinition, ResourceType resource) throws SchemaException { boolean apply = false; AttributesToReturn attributesToReturn = new AttributesToReturn(); attributesToReturn.setReturnDefaultAttributes(true); - + // Attributes Collection explicit = new ArrayList(); - for (RefinedAttributeDefinition attributeDefinition: objectClassDefinition.getAttributeDefinitions()) { + for (RefinedAttributeDefinition attributeDefinition : objectClassDefinition.getAttributeDefinitions()) { AttributeFetchStrategyType fetchStrategy = attributeDefinition.getFetchStrategy(); if (fetchStrategy != null && fetchStrategy == AttributeFetchStrategyType.EXPLICIT) { explicit.add(attributeDefinition); } } - + if (!explicit.isEmpty()) { attributesToReturn.setAttributesToReturn(explicit); apply = true; } - + // Password - CredentialsCapabilityType credentialsCapabilityType = ResourceTypeUtil.getEffectiveCapability(resource, CredentialsCapabilityType.class); + CredentialsCapabilityType credentialsCapabilityType = ResourceTypeUtil.getEffectiveCapability( + resource, CredentialsCapabilityType.class); if (CapabilityUtil.isPasswordReturnedByDefault(credentialsCapabilityType)) { - // There resource is capable of returning password but it does not do it by default - AttributeFetchStrategyType passwordFetchStrategy = objectClassDefinition.getPasswordFetchStrategy(); + // There resource is capable of returning password but it does not + // do it by default + AttributeFetchStrategyType passwordFetchStrategy = objectClassDefinition + .getPasswordFetchStrategy(); if (passwordFetchStrategy == AttributeFetchStrategyType.EXPLICIT) { attributesToReturn.setReturnPasswordExplicit(true); apply = true; } } - + // Activation/administrativeStatus - ActivationCapabilityType activationCapabilityType = ResourceTypeUtil.getEffectiveCapability(resource, ActivationCapabilityType.class); + ActivationCapabilityType activationCapabilityType = ResourceTypeUtil.getEffectiveCapability(resource, + ActivationCapabilityType.class); if (CapabilityUtil.isActivationStatusReturnedByDefault(activationCapabilityType)) { - // There resource is capable of returning enable flag but it does not do it by default - AttributeFetchStrategyType administrativeStatusFetchStrategy = objectClassDefinition.getActivationFetchStrategy(ActivationType.F_ADMINISTRATIVE_STATUS); + // There resource is capable of returning enable flag but it does + // not do it by default + AttributeFetchStrategyType administrativeStatusFetchStrategy = objectClassDefinition + .getActivationFetchStrategy(ActivationType.F_ADMINISTRATIVE_STATUS); if (administrativeStatusFetchStrategy == AttributeFetchStrategyType.EXPLICIT) { attributesToReturn.setReturnAdministrativeStatusExplicit(true); apply = true; } } - + if (CapabilityUtil.isActivationLockoutStatusReturnedByDefault(activationCapabilityType)) { - // There resource is capable of returning lockout flag but it does not do it by default - AttributeFetchStrategyType statusFetchStrategy = objectClassDefinition.getActivationFetchStrategy(ActivationType.F_LOCKOUT_STATUS); + // There resource is capable of returning lockout flag but it does + // not do it by default + AttributeFetchStrategyType statusFetchStrategy = objectClassDefinition + .getActivationFetchStrategy(ActivationType.F_LOCKOUT_STATUS); if (statusFetchStrategy == AttributeFetchStrategyType.EXPLICIT) { attributesToReturn.setReturnLockoutStatusExplicit(true); apply = true; } } - + if (apply) { return attributesToReturn; } else { From bdd71866f3b74a8de6210c84c01b6851230ada67 Mon Sep 17 00:00:00 2001 From: "Katarina Valalikova (katkav)" Date: Sun, 5 Oct 2014 21:56:14 +0200 Subject: [PATCH 18/19] allow limit propagation only for already exists sitaution --- .../midpoint/model/impl/sync/SynchronizationService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/sync/SynchronizationService.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/sync/SynchronizationService.java index 62424934432..8d5aab8ea39 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/sync/SynchronizationService.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/sync/SynchronizationService.java @@ -711,7 +711,7 @@ private Boolean determinePropagationLimitation(ObjectSynchronizationType synchro // resource. We only want to resolve the problem and continue in // previous provisioning/synchronization during which his // compensation was triggered - if (SchemaConstants.CHANGE_CHANNEL_DISCOVERY.equals(channelQName)){ + if (SchemaConstants.CHANGE_CHANNEL_DISCOVERY.equals(channelQName) && SynchronizationSituationType.DELETED != reactionDefinition.getSituation()){ return true; } } From 02accc61f98e76498f9ccbbc4e4560c53c21213c Mon Sep 17 00:00:00 2001 From: Pavol Mederly Date: Mon, 6 Oct 2014 11:46:02 +0200 Subject: [PATCH 19/19] Attempt to correctly show model contexts with null ResourceShadowDiscriminator. --- .../progress/ProgressReportActivityDto.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/progress/ProgressReportActivityDto.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/progress/ProgressReportActivityDto.java index d1424ea93ff..ea94694e639 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/progress/ProgressReportActivityDto.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/progress/ProgressReportActivityDto.java @@ -95,10 +95,15 @@ public boolean correspondsTo(ProgressInformation newStatus) { if (activityType != newStatus.getActivityType()) { return false; } - if (activityType == RESOURCE_OBJECT_OPERATION - && (resourceShadowDiscriminator == null || - !resourceShadowDiscriminator.equals(newStatus.getResourceShadowDiscriminator()))) { - return false; + if (activityType == RESOURCE_OBJECT_OPERATION) { + if (resourceShadowDiscriminator != null && + !resourceShadowDiscriminator.equals(newStatus.getResourceShadowDiscriminator())) { + return false; + } + if (resourceShadowDiscriminator == null && newStatus.getResourceShadowDiscriminator() != null) { + // actually, we consider all resource-related records with null RSD to be equal (even if they deal with different resources) + return false; + } } return true; }