From a41a66216342f8d69962ebf67d47c691004cd158 Mon Sep 17 00:00:00 2001 From: Katarina Valalikova Date: Mon, 16 Mar 2020 07:19:29 +0100 Subject: [PATCH 01/21] fix for MID-5947 - support for securityPolicy for projection defined in schemaHandling/objectType --- .../impl/lens/projector/ContextLoader.java | 3358 ++++++++--------- .../model/impl/security/SecurityHelper.java | 671 ++-- 2 files changed, 2010 insertions(+), 2019 deletions(-) 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 ff6043fab81..4c67fdd79c0 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 @@ -1,1702 +1,1656 @@ -/* - * Copyright (c) 2010-2018 Evolveum and contributors - * - * This work is dual-licensed under the Apache License 2.0 - * and European Union Public License. See LICENSE file for details. - */ -package com.evolveum.midpoint.model.impl.lens.projector; - -import static com.evolveum.midpoint.model.impl.lens.LensUtil.getExportType; -import static com.evolveum.midpoint.schema.internals.InternalsConfig.consistencyChecks; -import static com.evolveum.midpoint.schema.result.OperationResult.DEFAULT; - -import java.util.Collection; -import java.util.Iterator; -import java.util.List; - -import com.evolveum.midpoint.prism.*; -import com.evolveum.midpoint.prism.delta.*; -import com.evolveum.midpoint.schema.constants.ObjectTypes; -import com.evolveum.midpoint.schema.constants.SchemaConstants; -import com.evolveum.midpoint.schema.internals.InternalsConfig; -import com.evolveum.midpoint.xml.ns._public.common.common_3.*; - -import org.apache.commons.lang.StringUtils; -import org.apache.commons.lang.Validate; -import org.jetbrains.annotations.NotNull; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.stereotype.Component; - -import com.evolveum.midpoint.common.refinery.RefinedObjectClassDefinition; -import com.evolveum.midpoint.model.api.ModelExecuteOptions; -import com.evolveum.midpoint.model.api.context.SynchronizationPolicyDecision; -import com.evolveum.midpoint.model.common.ArchetypeManager; -import com.evolveum.midpoint.model.common.SystemObjectCache; -import com.evolveum.midpoint.model.impl.lens.ClockworkMedic; -import com.evolveum.midpoint.model.impl.lens.LensContext; -import com.evolveum.midpoint.model.impl.lens.LensElementContext; -import com.evolveum.midpoint.model.impl.lens.LensFocusContext; -import com.evolveum.midpoint.model.impl.lens.LensObjectDeltaOperation; -import com.evolveum.midpoint.model.impl.lens.LensProjectionContext; -import com.evolveum.midpoint.model.impl.lens.LensUtil; -import com.evolveum.midpoint.model.impl.lens.SynchronizationIntent; -import com.evolveum.midpoint.model.impl.security.SecurityHelper; -import com.evolveum.midpoint.provisioning.api.ProvisioningService; -import com.evolveum.midpoint.repo.api.RepositoryService; -import com.evolveum.midpoint.schema.GetOperationOptions; -import com.evolveum.midpoint.schema.PointInTimeType; -import com.evolveum.midpoint.schema.ResourceShadowDiscriminator; -import com.evolveum.midpoint.schema.RetrieveOption; -import com.evolveum.midpoint.schema.SelectorOptions; -import com.evolveum.midpoint.schema.result.OperationResult; -import com.evolveum.midpoint.schema.util.ExceptionUtil; -import com.evolveum.midpoint.schema.util.MiscSchemaUtil; -import com.evolveum.midpoint.schema.util.ShadowUtil; -import com.evolveum.midpoint.task.api.Task; -import com.evolveum.midpoint.util.exception.CommunicationException; -import com.evolveum.midpoint.util.exception.ConfigurationException; -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.PolicyViolationException; -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.logging.Trace; -import com.evolveum.midpoint.util.logging.TraceManager; - -/** - * Context loader loads the missing parts of the context. The context enters the projector with just the minimum information. - * Context loader gets missing data such as accounts. It gets them from the repository or provisioning as necessary. It follows - * the account links in focus (linkRef) and focus deltas. - * - * @author Radovan Semancik - * - */ -@Component -public class ContextLoader { - - @Autowired - @Qualifier("cacheRepositoryService") - private transient RepositoryService cacheRepositoryService; - - @Autowired private SystemObjectCache systemObjectCache; - @Autowired private ArchetypeManager archetypeManager; - @Autowired private ProvisioningService provisioningService; - @Autowired private PrismContext prismContext; - @Autowired private SecurityHelper securityHelper; - @Autowired private ClockworkMedic medic; - - private static final Trace LOGGER = TraceManager.getTrace(ContextLoader.class); - - public static final String CLASS_DOT = ContextLoader.class.getName() + "."; - private static final String OPERATION_LOAD = CLASS_DOT + "load"; - private static final String OPERATION_LOAD_PROJECTION = CLASS_DOT + "loadProjection"; - - public void load(LensContext context, String activityDescription, - Task task, OperationResult parentResult) - throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, - SecurityViolationException, PolicyViolationException, ExpressionEvaluationException { - - context.checkAbortRequested(); - - context.recompute(); - - OperationResult result = parentResult.createMinorSubresult(OPERATION_LOAD); - ProjectorComponentTraceType trace; - if (result.isTraced()) { - trace = new ProjectorComponentTraceType(prismContext); - if (result.isTracingNormal(ProjectorComponentTraceType.class)) { - trace.setInputLensContextText(context.debugDump()); - } - trace.setInputLensContext(context.toLensContextType(getExportType(trace, result))); - result.addTrace(trace); - } else { - trace = null; - } - - try { - - for (LensProjectionContext projectionContext: context.getProjectionContexts()) { - preprocessProjectionContext(context, projectionContext, task, result); - } - - if (consistencyChecks) context.checkConsistence(); - - determineFocusContext(context, task, result); - - LensFocusContext focusContext = context.getFocusContext(); - if (focusContext != null) { - - context.recomputeFocus(); - - loadFromSystemConfig(context, task, result); - - if (FocusType.class.isAssignableFrom(context.getFocusClass())) { - // this also removes the accountRef deltas - //noinspection unchecked - loadLinkRefs((LensContext)context, task, result); - LOGGER.trace("loadLinkRefs done"); - } - - // Some cleanup - if (focusContext.getPrimaryDelta() != null && focusContext.getPrimaryDelta().isModify() && focusContext.getPrimaryDelta().isEmpty()) { - focusContext.setPrimaryDelta(null); - } - - for (LensProjectionContext projectionContext: context.getProjectionContexts()) { - if (projectionContext.getSynchronizationIntent() != null) { - // Accounts with explicitly set intent are never rotten. These are explicitly requested actions - // if they fail then they really should fail. - projectionContext.setFresh(true); - } - } - - setPrimaryDeltaOldValue(focusContext); - - } else { - // Projection contexts are not rotten in this case. There is no focus so there is no way to refresh them. - for (LensProjectionContext projectionContext: context.getProjectionContexts()) { - projectionContext.setFresh(true); - } - } - - removeRottenContexts(context); - - if (consistencyChecks) context.checkConsistence(); - - for (LensProjectionContext projectionContext: context.getProjectionContexts()) { - context.checkAbortRequested(); - // TODO: not perfect. Practically, we want loadProjection operation to contain all the projection - // results. But for that we would need code restructure. - OperationResult projectionResult = result.createMinorSubresult(OPERATION_LOAD_PROJECTION); - try { - finishLoadOfProjectionContext(context, projectionContext, task, projectionResult); - } catch (Throwable e) { - projectionResult.recordFatalError(e); - throw e; - } - projectionResult.computeStatus(); - } - - if (consistencyChecks) context.checkConsistence(); - - context.recompute(); - - if (consistencyChecks) { - fullCheckConsistence(context); - } - - medic.traceContext(LOGGER, activityDescription, "after load", false, context, false); - - result.computeStatusComposite(); - - } catch (Throwable e) { - result.recordFatalError(e); - throw e; - } finally { - if (trace != null) { - if (result.isTracingNormal(ProjectorComponentTraceType.class)) { - trace.setOutputLensContextText(context.debugDump()); - } - trace.setOutputLensContext(context.toLensContextType(getExportType(trace, result))); - } - } - } - - - /** - * Removes projection contexts that are not fresh. - * These are usually artifacts left after the context reload. E.g. an account that used to be linked to a user before - * but was removed in the meantime. - */ - private void removeRottenContexts(LensContext context) { - Iterator projectionIterator = context.getProjectionContextsIterator(); - while (projectionIterator.hasNext()) { - LensProjectionContext projectionContext = projectionIterator.next(); - if (projectionContext.getPrimaryDelta() != null && !projectionContext.getPrimaryDelta().isEmpty()) { - // We must never remove contexts with primary delta. Even though it fails later on. - // What the user wishes should be done (or at least attempted) regardless of the consequences. - // Vox populi vox dei - continue; - } - if (projectionContext.getWave() >= context.getExecutionWave()) { - // We must not remove context from this and later execution waves. These haven't had the - // chance to be executed yet - continue; - } - ResourceShadowDiscriminator discr = projectionContext.getResourceShadowDiscriminator(); - if (discr != null && discr.getOrder() > 0) { - // HACK never rot higher-order context. TODO: check if lower-order context is rotten, the also rot this one - continue; - } - if (!projectionContext.isFresh()) { - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Removing rotten context {}", projectionContext.getHumanReadableName()); - } - - if (projectionContext.isToBeArchived()) { - context.getHistoricResourceObjects().add(projectionContext.getResourceShadowDiscriminator()); - } - - List> executedDeltas = projectionContext.getExecutedDeltas(); - context.getRottenExecutedDeltas().addAll(executedDeltas); - projectionIterator.remove(); - } - } - } - - - /** - * Make sure that the projection context is loaded as appropriate. - */ - public void makeSureProjectionIsLoaded(LensContext context, - LensProjectionContext projectionContext, Task task, OperationResult result) throws ObjectNotFoundException, CommunicationException, SchemaException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { - preprocessProjectionContext(context, projectionContext, task, result); - finishLoadOfProjectionContext(context, projectionContext, task, result); - } - - /** - * Make sure that the context is OK and consistent. It means that is has a resource, it has correctly processed - * discriminator, etc. - */ - private void preprocessProjectionContext(LensContext context, - LensProjectionContext projectionContext, Task task, OperationResult result) - throws ObjectNotFoundException, CommunicationException, SchemaException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { - if (!ShadowType.class.isAssignableFrom(projectionContext.getObjectTypeClass())) { - return; - } - String resourceOid = null; - boolean isThombstone = false; - ShadowKindType kind = ShadowKindType.ACCOUNT; - String intent = null; - String tag = null; - int order = 0; - ResourceShadowDiscriminator rsd = projectionContext.getResourceShadowDiscriminator(); - if (rsd != null) { - resourceOid = rsd.getResourceOid(); - isThombstone = rsd.isTombstone(); - kind = rsd.getKind(); - intent = rsd.getIntent(); - tag = rsd.getTag(); - order = rsd.getOrder(); - } - if (resourceOid == null && projectionContext.getObjectCurrent() != null) { - resourceOid = ShadowUtil.getResourceOid(projectionContext.getObjectCurrent().asObjectable()); - } - if (resourceOid == null && projectionContext.getObjectNew() != null) { - resourceOid = ShadowUtil.getResourceOid(projectionContext.getObjectNew().asObjectable()); - } - // We still may not have resource OID here. E.g. in case of the delete when the account is not loaded yet. It is - // perhaps safe to skip this. It will be sorted out later. - - if (resourceOid != null) { - if (intent == null && projectionContext.getObjectNew() != null) { - ShadowType shadowNewType = projectionContext.getObjectNew().asObjectable(); - kind = ShadowUtil.getKind(shadowNewType); - intent = ShadowUtil.getIntent(shadowNewType); - tag = shadowNewType.getTag(); - } - ResourceType resource = projectionContext.getResource(); - if (resource == null) { - resource = LensUtil.getResourceReadOnly(context, resourceOid, provisioningService, task, result); - projectionContext.setResource(resource); - } - String refinedIntent = LensUtil.refineProjectionIntent(kind, intent, resource, prismContext); - rsd = new ResourceShadowDiscriminator(resourceOid, kind, refinedIntent, tag, isThombstone); - rsd.setOrder(order); - projectionContext.setResourceShadowDiscriminator(rsd); - } - if (projectionContext.getOid() == null && rsd != null && rsd.getOrder() != 0) { - // Try to determine OID from lower-order contexts - for (LensProjectionContext aProjCtx: context.getProjectionContexts()) { - ResourceShadowDiscriminator aDiscr = aProjCtx.getResourceShadowDiscriminator(); - if (rsd.equivalent(aDiscr) && aProjCtx.getOid() != null) { - projectionContext.setOid(aProjCtx.getOid()); - break; - } - } - } - } - - /** - * try to load focus context from oid, delta, projections (e.g. by determining account owners) - */ - public void determineFocusContext(LensContext context, Task task, OperationResult parentResult) - throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, - SecurityViolationException, ExpressionEvaluationException { - - OperationResult result = parentResult.subresult(CLASS_DOT + "determineFocusContext") - .setMinor() - .build(); - FocusLoadedTraceType trace; - if (result.isTraced()) { - trace = new FocusLoadedTraceType(prismContext); - if (result.isTracingNormal(FocusLoadedTraceType.class)) { - trace.setInputLensContextText(context.debugDump()); - } - trace.setInputLensContext(context.toLensContextType(getExportType(trace, result))); - result.addTrace(trace); - } else { - trace = null; - } - LensFocusContext focusContext = context.getFocusContext(); - try { - if (focusContext == null) { - focusContext = determineFocusContextFromProjections(context, result); - } - - if (focusContext == null) { - result.addReturnComment("Nothing to load"); - return; - } - - // Make sure that we RELOAD the focus object if the context is not fresh - // the focus may have changed in the meantime - if (focusContext.getObjectCurrent() != null && focusContext.isFresh()) { - result.addReturnComment("Already loaded"); - return; - } - ObjectDelta objectDelta = focusContext.getDelta(); - if (objectDelta != null && objectDelta.isAdd() && focusContext.getExecutedDeltas().isEmpty()) { - //we're adding the focal object. No need to load it, it is in the delta - focusContext.setFresh(true); - result.addReturnComment("Obtained from delta"); - return; - } - if (focusContext.getObjectCurrent() != null && objectDelta != null && objectDelta.isDelete()) { - // do not reload if the delta is delete. the reload will most likely fail anyway - // but DO NOT set the fresh flag in this case, it may be misleading - result.addReturnComment("Not loading as delta is DELETE"); - return; - } - - String focusOid = focusContext.getOid(); - if (StringUtils.isBlank(focusOid)) { - throw new IllegalArgumentException("No OID in primary focus delta"); - } - - PrismObject object; - if (ObjectTypes.isClassManagedByProvisioning(focusContext.getObjectTypeClass())) { - object = provisioningService.getObject(focusContext.getObjectTypeClass(), focusOid, - SelectorOptions.createCollection(GetOperationOptions.createNoFetch()), task, result); - result.addReturnComment("Loaded via provisioning"); - } else { - - // Always load a complete object here, including the not-returned-by-default properties. - // This is temporary measure to make sure that the mappings will have all they need. - // See MID-2635 - Collection> options = - SelectorOptions.createCollection(GetOperationOptions.createRetrieve(RetrieveOption.INCLUDE)); - object = cacheRepositoryService.getObject(focusContext.getObjectTypeClass(), focusOid, options, result); - result.addReturnComment("Loaded from repository"); - } - - focusContext.setLoadedObject(object); - focusContext.setFresh(true); - LOGGER.trace("Focal object loaded: {}", object); - } catch (Throwable t) { - result.recordFatalError(t); - throw t; - } finally { - if (trace != null) { - if (result.isTracingNormal(FocusLoadedTraceType.class)) { - trace.setOutputLensContextText(context.debugDump()); - } - trace.setOutputLensContext(context.toLensContextType(getExportType(trace, result))); - } - result.computeStatusIfUnknown(); - } - } - - private LensFocusContext determineFocusContextFromProjections(LensContext context, OperationResult result) { - String focusOid = null; - LensProjectionContext projectionContextThatYeildedFocusOid = null; - PrismObject focusOwner = null; - for (LensProjectionContext projectionContext: context.getProjectionContexts()) { - String projectionOid = projectionContext.getOid(); - if (projectionOid != null) { - PrismObject shadowOwner = cacheRepositoryService.searchShadowOwner(projectionOid, - SelectorOptions.createCollection(GetOperationOptions.createAllowNotFound()), - result); - if (shadowOwner != null) { - if (focusOid == null || focusOid.equals(shadowOwner.getOid())) { - focusOid = shadowOwner.getOid(); - //noinspection unchecked - focusOwner = (PrismObject) shadowOwner; - projectionContextThatYeildedFocusOid = projectionContext; - } else { - throw new IllegalArgumentException("The context does not have explicit focus. Attempt to determine focus failed because two " + - "projections points to different foci: "+projectionContextThatYeildedFocusOid+"->"+focusOid+"; "+ - projectionContext+"->"+shadowOwner); - } - } - } - } - - if (focusOid != null) { - LensFocusContext focusCtx = context.getOrCreateFocusContext(focusOwner.getCompileTimeClass()); - focusCtx.setOid(focusOid); - return focusCtx; - } - - return null; - } - - private void setPrimaryDeltaOldValue(LensElementContext ctx) { - if (ctx.getPrimaryDelta() != null && ctx.getObjectOld() != null && ctx.isModify()) { - boolean freezeAfterChange; - if (ctx.getPrimaryDelta().isImmutable()) { - ctx.setPrimaryDelta(ctx.getPrimaryDelta().clone()); - freezeAfterChange = true; - } else { - freezeAfterChange = false; - } - for (ItemDelta itemDelta: ctx.getPrimaryDelta().getModifications()) { - LensUtil.setDeltaOldValue(ctx, itemDelta); - } - if (freezeAfterChange) { - ctx.getPrimaryDelta().freeze(); - } - } - } - - private void loadFromSystemConfig(LensContext context, Task task, OperationResult result) - throws ObjectNotFoundException, SchemaException, ConfigurationException, ExpressionEvaluationException, CommunicationException, SecurityViolationException { - PrismObject systemConfiguration = systemObjectCache.getSystemConfiguration(result); - if (systemConfiguration == null) { - // This happens in some tests. And also during first startup. - return; - } - context.setSystemConfiguration(systemConfiguration); - SystemConfigurationType systemConfigurationType = systemConfiguration.asObjectable(); - - if (context.getFocusContext() != null) { - if (context.getFocusContext().getArchetypePolicyType() == null) { - ArchetypePolicyType archetypePolicy = determineArchetypePolicy(context, task, result); - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Selected archetype policy:\n{}", - archetypePolicy==null?null:archetypePolicy.asPrismContainerValue().debugDump(1)); - } - context.getFocusContext().setArchetypePolicyType(archetypePolicy); - } - } - - if (context.getFocusTemplate() == null) { - // TODO is the nullity check needed here? - setFocusTemplate(context, result); - } - - if (context.getAccountSynchronizationSettings() == null) { - ProjectionPolicyType globalAccountSynchronizationSettings = systemConfigurationType.getGlobalAccountSynchronizationSettings(); - LOGGER.trace("Applying globalAccountSynchronizationSettings to context: {}", globalAccountSynchronizationSettings); - context.setAccountSynchronizationSettings(globalAccountSynchronizationSettings); - } - - loadSecurityPolicy(context, task, result); - } - - private ArchetypePolicyType determineArchetypePolicy(LensContext context, Task task, OperationResult result) throws SchemaException, ConfigurationException { - PrismObject systemConfiguration = context.getSystemConfiguration(); - if (systemConfiguration == null) { - return null; - } - if (context.getFocusContext() == null) { - return null; - } - PrismObject object = context.getFocusContext().getObjectAny(); - String explicitArchetypeOid = LensUtil.determineExplicitArchetypeOid(context.getFocusContext().getObjectAny()); - return archetypeManager.determineArchetypePolicy(object, explicitArchetypeOid, result); - } - - public ArchetypeType updateArchetype(LensContext context, Task task, OperationResult result) throws SchemaException, ConfigurationException { - PrismObject systemConfiguration = context.getSystemConfiguration(); - if (systemConfiguration == null) { - return null; - } - if (context.getFocusContext() == null) { - return null; - } - - PrismObject object = context.getFocusContext().getObjectAny(); - - String explicitArchetypeOid = LensUtil.determineExplicitArchetypeOid(context.getFocusContext().getObjectAny()); - PrismObject archetype = archetypeManager.determineArchetype(object, explicitArchetypeOid, result); - ArchetypeType archetypeType = null; - if (archetype != null) { - archetypeType = archetype.asObjectable(); - } - - context.getFocusContext().setArchetype(archetypeType); - - return archetypeType; - } - - public void updateArchetypePolicy(LensContext context, Task task, OperationResult result) throws SchemaException, ConfigurationException { - if (context.getFocusContext() == null) { - return; - } - ArchetypePolicyType newArchetypePolicy = determineArchetypePolicy(context, task, result); - if (newArchetypePolicy != context.getFocusContext().getArchetypePolicyType()) { - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Changed policy configuration because of changed subtypes:\n{}", - newArchetypePolicy==null?null:newArchetypePolicy.asPrismContainerValue().debugDump(1)); - } - context.getFocusContext().setArchetypePolicyType(newArchetypePolicy); - } - } - - // expects that object policy configuration is already set in focusContext - public void setFocusTemplate(LensContext context, OperationResult result) - throws ObjectNotFoundException, SchemaException { - - // 1. When this method is called after inbound processing, we might want to change the existing template - // (because e.g. subtype or archetype was determined and we want to move from generic to more specific template). - // 2. On the other hand, if focus template is set up explicitly from the outside (e.g. in synchronization section) - // we probably do not want to change it here. - if (context.getFocusTemplate() != null && context.isFocusTemplateExternallySet()) { - return; - } - - String currentOid = context.getFocusTemplate() != null ? context.getFocusTemplate().getOid() : null; - String newOid; - - LensFocusContext focusContext = context.getFocusContext(); - if (focusContext == null) { - newOid = null; - } else { - ArchetypePolicyType archetypePolicy = focusContext.getArchetypePolicyType(); - if (archetypePolicy == null) { - LOGGER.trace("No default object template (no policy)"); - newOid = null; - } else { - ObjectReferenceType templateRef = archetypePolicy.getObjectTemplateRef(); - if (templateRef == null) { - LOGGER.trace("No default object template (no templateRef)"); - newOid = null; - } else { - newOid = templateRef.getOid(); - } - } - } - - LOGGER.trace("current focus template OID = {}, new = {}", currentOid, newOid); - if (!java.util.Objects.equals(currentOid, newOid)) { - ObjectTemplateType template; - if (newOid != null) { - template = cacheRepositoryService.getObject(ObjectTemplateType.class, newOid, null, result).asObjectable(); - } else { - template = null; - } - context.setFocusTemplate(template); - } - } - - private void loadLinkRefs(LensContext context, Task task, OperationResult result) throws ObjectNotFoundException, - SchemaException, CommunicationException, ConfigurationException, SecurityViolationException, PolicyViolationException, ExpressionEvaluationException { - LensFocusContext focusContext = context.getFocusContext(); - if (focusContext == null) { - // Nothing to load - return; - } - - LOGGER.trace("loadLinkRefs starting"); - - PrismObject focusCurrent = focusContext.getObjectCurrent(); - if (focusCurrent != null) { - loadLinkRefsFromFocus(context, focusCurrent, task, result); - LOGGER.trace("loadLinkRefsFromFocus done"); - } - - if (consistencyChecks) context.checkConsistence(); - - loadLinkRefsFromDelta(context, focusCurrent, focusContext, task, result); - LOGGER.trace("loadLinkRefsFromDelta done"); - - if (consistencyChecks) context.checkConsistence(); - - loadProjectionContextsSync(context, task, result); - LOGGER.trace("loadProjectionContextsSync done"); - - if (consistencyChecks) context.checkConsistence(); - } - - /** - * Does not overwrite existing account contexts, just adds new ones. - */ - private void loadLinkRefsFromFocus(LensContext context, PrismObject focus, - Task task, OperationResult result) throws ObjectNotFoundException, - CommunicationException, SchemaException, ConfigurationException, SecurityViolationException, PolicyViolationException, ExpressionEvaluationException { - PrismReference linkRef = focus.findReference(FocusType.F_LINK_REF); - if (linkRef == null) { - return; - } - for (PrismReferenceValue linkRefVal : linkRef.getValues()) { - String oid = linkRefVal.getOid(); - if (StringUtils.isBlank(oid)) { - LOGGER.trace("Null or empty OID in link reference {} in:\n{}", linkRef, - focus.debugDump(1)); - 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 - - existingAccountContext.setFresh(true); - continue; - } - PrismObject shadow; - //noinspection unchecked - PrismObject shadowFromLink = linkRefVal.getObject(); - if (shadowFromLink == null) { - GetOperationOptions rootOpts; - if (context.isDoReconciliationForAllProjections()) { - rootOpts = GetOperationOptions.createForceRetry(); - } else { - // Using NO_FETCH so we avoid reading in a full account. This is more efficient as we don't need full account here. - // We need to fetch from provisioning and not repository so the correct definition will be set. - rootOpts = GetOperationOptions.createNoFetch(); - rootOpts.setPointInTimeType(PointInTimeType.FUTURE); - } - - Collection> options = SelectorOptions.createCollection(rootOpts); - LOGGER.trace("Loading shadow {} from linkRef, options={}", oid, options); - try { - shadow = provisioningService.getObject(ShadowType.class, oid, options, task, result); - } catch (ObjectNotFoundException e) { - // Broken accountRef. We need to mark it for deletion - LensProjectionContext projectionContext = getOrCreateEmptyThombstoneProjectionContext(context, oid); - projectionContext.setFresh(true); - projectionContext.setExists(false); - projectionContext.setShadowExistsInRepo(false); - OperationResult getObjectSubresult = result.getLastSubresult(); - getObjectSubresult.setErrorsHandled(); - continue; - } - } else { - shadow = shadowFromLink; - // Make sure it has a proper definition. This may come from outside of the model. - provisioningService.applyDefinition(shadow, task, result); - } - LensProjectionContext projectionContext = getOrCreateAccountContext(context, shadow, task, result); - projectionContext.setFresh(true); - projectionContext.setExists(ShadowUtil.isExists(shadow.asObjectable())); - if (ShadowUtil.isDead(shadow.asObjectable())) { - projectionContext.markTombstone(); - LOGGER.trace("Loading dead shadow {} for projection {}.", shadow, projectionContext.getHumanReadableName()); - continue; - } - if (context.isDoReconciliationForAllProjections()) { - projectionContext.setDoReconciliation(true); - } - if (projectionContext.isDoReconciliation()) { - // Do not load old account now. It will get loaded later in the - // reconciliation step. - continue; - } - projectionContext.setLoadedObject(shadow); - } - } - - private void loadLinkRefsFromDelta(LensContext context, PrismObject focus, - LensFocusContext focusContext, Task task, OperationResult result) throws SchemaException, - ObjectNotFoundException, CommunicationException, ConfigurationException, - SecurityViolationException, PolicyViolationException, ExpressionEvaluationException { - - ObjectDelta focusPrimaryDelta = focusContext.getPrimaryDelta(); - if (focusPrimaryDelta == null) { - return; - } - - ReferenceDelta linkRefDelta; - if (focusPrimaryDelta.getChangeType() == ChangeType.ADD) { - PrismReference linkRef = focusPrimaryDelta.getObjectToAdd().findReference( - FocusType.F_LINK_REF); - if (linkRef == null) { - // Adding new focus with no linkRef -> nothing to do - return; - } - linkRefDelta = linkRef.createDelta(FocusType.F_LINK_REF); - linkRefDelta.addValuesToAdd(PrismValueCollectionsUtil.cloneValues(linkRef.getValues())); - } else if (focusPrimaryDelta.getChangeType() == ChangeType.MODIFY) { - linkRefDelta = focusPrimaryDelta.findReferenceModification(FocusType.F_LINK_REF); - if (linkRefDelta == null) { - return; - } - } else { - // delete, all existing account are already marked for delete - return; - } - - if (linkRefDelta.isReplace()) { - // process "replace" by distributing values to delete and add - linkRefDelta = (ReferenceDelta) linkRefDelta.clone(); - PrismReference linkRef = focus.findReference(FocusType.F_LINK_REF); - linkRefDelta.distributeReplace(linkRef == null ? null : linkRef.getValues()); - } - - if (linkRefDelta.getValuesToAdd() != null) { - for (PrismReferenceValue refVal : linkRefDelta.getValuesToAdd()) { - String oid = refVal.getOid(); - LensProjectionContext projectionContext = null; - PrismObject shadow = null; - boolean isCombinedAdd = false; - if (oid == null) { - // Adding new account - shadow = refVal.getObject(); - if (shadow == null) { - throw new SchemaException("Null or empty OID in account reference " + refVal + " in " - + focus); - } - provisioningService.applyDefinition(shadow, task, result); - if (consistencyChecks) ShadowUtil.checkConsistence(shadow, "account from "+linkRefDelta); - // Check for conflicting change - projectionContext = LensUtil.getProjectionContext(context, shadow, provisioningService, prismContext, task, result); - if (projectionContext != null) { - // There is already existing context for the same discriminator. Tolerate this only if - // the deltas match. It is an error otherwise. - ObjectDelta primaryDelta = projectionContext.getPrimaryDelta(); - if (primaryDelta == null) { - throw new SchemaException("Attempt to add "+shadow+" to a focus that already contains "+ - projectionContext.getHumanReadableKind()+" of type '"+ - projectionContext.getResourceShadowDiscriminator().getIntent()+"' on "+projectionContext.getResource()); - } - if (!primaryDelta.isAdd()) { - throw new SchemaException("Conflicting changes in the context. " + - "Add of linkRef in the focus delta with embedded object conflicts with explicit delta "+primaryDelta); - } - if (!shadow.equals(primaryDelta.getObjectToAdd())) { - throw new SchemaException("Conflicting changes in the context. " + - "Add of linkRef in the focus delta with embedded object is not adding the same object as explicit delta "+primaryDelta); - } - } else { - // Create account context from embedded object - projectionContext = createProjectionContext(context, shadow, task, result); - } - // This is a new account that is to be added. So it should - // go to account primary delta - ObjectDelta accountPrimaryDelta = shadow.createAddDelta(); - projectionContext.setPrimaryDelta(accountPrimaryDelta); - projectionContext.setFullShadow(true); - projectionContext.setExists(false); - isCombinedAdd = true; - } else { - // We have OID. This is either linking of existing account or - // add of new account - // therefore check for account existence to decide - try { - // Using NO_FETCH so we avoid reading in a full account. This is more efficient as we don't need full account here. - // We need to fetch from provisioning and not repository so the correct definition will be set. - GetOperationOptions rootOpts = GetOperationOptions.createNoFetch(); - rootOpts.setPointInTimeType(PointInTimeType.FUTURE); - Collection> options = SelectorOptions.createCollection(rootOpts); - shadow = provisioningService.getObject(ShadowType.class, oid, options, task, result); - // Create account context from retrieved object - projectionContext = getOrCreateAccountContext(context, shadow, task, result); - projectionContext.setLoadedObject(shadow); - projectionContext.setExists(ShadowUtil.isExists(shadow.asObjectable())); - } catch (ObjectNotFoundException e) { - if (refVal.getObject() == null) { - // account does not exist, no composite account in - // ref -> this is really an error - throw e; - } else { - // New account (with OID) - result.muteLastSubresultError(); - shadow = refVal.getObject(); - if (!shadow.hasCompleteDefinition()) { - provisioningService.applyDefinition(shadow, task, result); - } - // Create account context from embedded object - projectionContext = createProjectionContext(context, shadow, task, result); - ObjectDelta accountPrimaryDelta = shadow.createAddDelta(); - projectionContext.setPrimaryDelta(accountPrimaryDelta); - projectionContext.setFullShadow(true); - projectionContext.setExists(false); - projectionContext.setShadowExistsInRepo(false); - isCombinedAdd = true; - } - } - } - if (context.isDoReconciliationForAllProjections() && !isCombinedAdd) { - projectionContext.setDoReconciliation(true); - } - projectionContext.setFresh(true); - } - } - - if (linkRefDelta.getValuesToDelete() != null) { - for (PrismReferenceValue refVal : linkRefDelta.getValuesToDelete()) { - String oid = refVal.getOid(); - LensProjectionContext projectionContext = null; - PrismObject shadow = null; - if (oid == null) { - throw new SchemaException("Cannot delete account ref without an oid in " + focus); - } else { - try { - // Using NO_FETCH so we avoid reading in a full account. This is more efficient as we don't need full account here. - // We need to fetch from provisioning and not repository so the correct definition will be set. - Collection> options = SelectorOptions.createCollection(GetOperationOptions.createNoFetch()); - shadow = provisioningService.getObject(ShadowType.class, oid, options, task, result); - // Create account context from retrieved object - projectionContext = getOrCreateAccountContext(context, shadow, task, result); - projectionContext.setLoadedObject(shadow); - projectionContext.setExists(ShadowUtil.isExists(shadow.asObjectable())); - } catch (ObjectNotFoundException e) { - try{ - // Broken accountRef. We need to try again with raw options, because the error should be thrown because of non-existent resource - Collection> options = SelectorOptions.createCollection(GetOperationOptions.createRaw()); - shadow = provisioningService.getObject(ShadowType.class, oid, options, task, result); - projectionContext = getOrCreateEmptyThombstoneProjectionContext(context, oid); - projectionContext.setFresh(true); - projectionContext.setExists(false); - projectionContext.setShadowExistsInRepo(false); - OperationResult getObjectSubresult = result.getLastSubresult(); - getObjectSubresult.setErrorsHandled(); - } catch (ObjectNotFoundException ex){ - // This is still OK. It means deleting an accountRef - // that points to non-existing object - // just log a warning - LOGGER.warn("Deleting accountRef of " + focus + " that points to non-existing OID " - + oid); - } - - } - } - if (projectionContext != null) { - if (refVal.getObject() == null) { - projectionContext.setSynchronizationIntent(SynchronizationIntent.UNLINK); - } else { - projectionContext.setSynchronizationIntent(SynchronizationIntent.DELETE); - ObjectDelta accountPrimaryDelta = shadow.createDeleteDelta(); - projectionContext.setPrimaryDelta(accountPrimaryDelta); - } - projectionContext.setFresh(true); - } - - } - } - - // remove the accountRefs without oid. These will get into the way now. - // The accounts - // are in the context now and will be linked at the end of the process - // (it they survive the policy) - // We need to make sure this happens on the real primary focus delta - - ObjectDelta primaryDeltaToUpdate; - if (focusPrimaryDelta.isImmutable()) { - primaryDeltaToUpdate = focusPrimaryDelta.clone(); - focusContext.setPrimaryDelta(primaryDeltaToUpdate); - } else { - primaryDeltaToUpdate = focusPrimaryDelta; - } - - if (primaryDeltaToUpdate.getChangeType() == ChangeType.ADD) { - primaryDeltaToUpdate.getObjectToAdd().removeReference(FocusType.F_LINK_REF); - } else if (primaryDeltaToUpdate.getChangeType() == ChangeType.MODIFY) { - primaryDeltaToUpdate.removeReferenceModification(FocusType.F_LINK_REF); - } - // It is little bit questionable whether we need to make primary delta immutable. It makes some sense, but I am not sure. - // Note that (as a side effect) this can make "focus new" immutable as well, in the case of ADD delta. - primaryDeltaToUpdate.freeze(); - } - - private void loadProjectionContextsSync(LensContext context, Task task, OperationResult result) throws SchemaException, - ObjectNotFoundException, CommunicationException, ConfigurationException, - SecurityViolationException, ExpressionEvaluationException { - for (LensProjectionContext projCtx : context.getProjectionContexts()) { - if (projCtx.isFresh() && projCtx.getObjectCurrent() != null) { - // already loaded - continue; - } - ObjectDelta syncDelta = projCtx.getSyncDelta(); - if (syncDelta != null) { - if (projCtx.isDoReconciliation()) { - // Do not load old account now. It will get loaded later in the - // reconciliation step. Just mark it as fresh. - projCtx.setFresh(true); - continue; - } - String oid = syncDelta.getOid(); - PrismObject shadow = null; - - if (syncDelta.getChangeType() == ChangeType.ADD) { - shadow = syncDelta.getObjectToAdd().clone(); - projCtx.setLoadedObject(shadow); - projCtx.setExists(ShadowUtil.isExists(shadow.asObjectable())); - - } else { - - if (oid == null) { - throw new IllegalArgumentException("No OID in sync delta in " + projCtx); - } - // Using NO_FETCH so we avoid reading in a full account. This is more efficient as we don't need full account here. - // We need to fetch from provisioning and not repository so the correct definition will be set. - GetOperationOptions option = GetOperationOptions.createNoFetch(); - option.setDoNotDiscovery(true); - option.setPointInTimeType(PointInTimeType.FUTURE); - Collection> options = SelectorOptions.createCollection(option); - - try { - - shadow = provisioningService.getObject(ShadowType.class, oid, options, task, result); - - } catch (ObjectNotFoundException e) { - LOGGER.trace("Loading shadow {} from sync delta failed: not found", oid); - projCtx.setExists(false); - projCtx.setObjectCurrent(null); - projCtx.setShadowExistsInRepo(false); - } - - // We will not set old account if the delta is delete. The - // account does not really exists now. - // (but the OID and resource will be set from the repo - // shadow) - if (syncDelta.getChangeType() == ChangeType.DELETE) { - projCtx.markTombstone(); - } else if (shadow != null) { - syncDelta.applyTo(shadow); - projCtx.setLoadedObject(shadow); - projCtx.setExists(ShadowUtil.isExists(shadow.asObjectable())); - } - } - - // Make sure OID is set correctly - projCtx.setOid(oid); - // Make sure that resource is also resolved - if (projCtx.getResource() == null && shadow != null) { - String resourceOid = ShadowUtil.getResourceOid(shadow.asObjectable()); - if (resourceOid == null) { - throw new IllegalArgumentException("No resource OID in " + shadow); - } - ResourceType resourceType = LensUtil.getResourceReadOnly(context, resourceOid, provisioningService, task, result); - projCtx.setResource(resourceType); - } - projCtx.setFresh(true); - } - } - } - -// 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 projection, Task task, OperationResult result) throws ObjectNotFoundException, - CommunicationException, SchemaException, ConfigurationException, SecurityViolationException, PolicyViolationException, ExpressionEvaluationException { - ShadowType shadowType = projection.asObjectable(); - String resourceOid = ShadowUtil.getResourceOid(shadowType); - if (resourceOid == null) { - throw new SchemaException("The " + projection + " has null resource reference OID"); - } - - LensProjectionContext projectionContext = context.findProjectionContextByOid(shadowType.getOid()); - - if (projectionContext == null) { - String intent = ShadowUtil.getIntent(shadowType); - ShadowKindType kind = ShadowUtil.getKind(shadowType); - ResourceType resource = LensUtil.getResourceReadOnly(context, resourceOid, provisioningService, task, result); - intent = LensUtil.refineProjectionIntent(kind, intent, resource, prismContext); - boolean thombstone = false; - if (ShadowUtil.isDead(shadowType)) { - thombstone = true; - } - ResourceShadowDiscriminator rsd = new ResourceShadowDiscriminator(resourceOid, kind, intent, shadowType.getTag(), thombstone); - projectionContext = LensUtil.getOrCreateProjectionContext(context, rsd); - - if (projectionContext.getOid() == null) { - projectionContext.setOid(projection.getOid()); - } else if (projection.getOid() != null && !projectionContext.getOid().equals(projection.getOid())) { - // Conflict. We have existing projection and another project that is added (with the same discriminator). - // Chances are that the old object is already deleted (e.g. during rename). So let's be - // slightly inefficient here and check for existing shadow existence - try { - GetOperationOptions rootOpt = GetOperationOptions.createPointInTimeType(PointInTimeType.FUTURE); - rootOpt.setDoNotDiscovery(true); - Collection> opts = SelectorOptions.createCollection(rootOpt); - LOGGER.trace("Projection conflict detected, existing: {}, new {}", projectionContext.getOid(), projection.getOid()); - PrismObject existingShadow = provisioningService.getObject(ShadowType.class, projectionContext.getOid(), opts, task, result); - // Maybe it is the other way around - try { - PrismObject newShadow = provisioningService.getObject(ShadowType.class, projection.getOid(), opts, task, result); - // Obviously, two projections with the same discriminator exists - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Projection {} already exists in context\nExisting:\n{}\nNew:\n{}", rsd, - existingShadow.debugDump(1), newShadow.debugDump(1)); - } - if (!ShadowUtil.isDead(newShadow.asObjectable())) { - throw new PolicyViolationException("Projection "+rsd+" already exists in context (existing "+existingShadow+", new "+projection); - } - // Dead shadow. This is somehow expected, fix it and we can go on - rsd.setTombstone(true); - projectionContext = LensUtil.getOrCreateProjectionContext(context, rsd); - projectionContext.setExists(ShadowUtil.isExists(newShadow.asObjectable())); - projectionContext.setFullShadow(false); - } catch (ObjectNotFoundException e) { - // This is somehow expected, fix it and we can go on - result.muteLastSubresultError(); - // We have to create new context in this case, but it has to have thumbstone set - rsd.setTombstone(true); - projectionContext = LensUtil.getOrCreateProjectionContext(context, rsd); - // We have to mark it as dead right now, otherwise the uniqueness check may fail - markShadowDead(projection.getOid(), result); - projectionContext.setShadowExistsInRepo(false); - } - } catch (ObjectNotFoundException e) { - // This is somehow expected, fix it and we can go on - result.muteLastSubresultError(); - String shadowOid = projectionContext.getOid(); - projectionContext.getResourceShadowDiscriminator().setTombstone(true); - projectionContext = LensUtil.getOrCreateProjectionContext(context, rsd); - projectionContext.setShadowExistsInRepo(false); - // We have to mark it as dead right now, otherwise the uniqueness check may fail - markShadowDead(shadowOid, result); - } - } - } - return projectionContext; - } - - private void markShadowDead(String oid, OperationResult result) { - if (oid == null) { - // nothing to mark - return; - } - Collection> modifications = MiscSchemaUtil.createCollection( - prismContext.deltaFactory().property().createReplaceDelta(prismContext.getSchemaRegistry().findObjectDefinitionByCompileTimeClass(ShadowType.class), - ShadowType.F_DEAD, true)); - try { - cacheRepositoryService.modifyObject(ShadowType.class, oid, modifications, result); - // TODO report to task? - } catch (ObjectNotFoundException e) { - // Done already - result.muteLastSubresultError(); - } catch (ObjectAlreadyExistsException | SchemaException e) { - // Should not happen - throw new SystemException(e.getMessage(), e); - } - } - - - private LensProjectionContext createProjectionContext(LensContext context, - PrismObject account, Task task, OperationResult result) throws ObjectNotFoundException, - CommunicationException, SchemaException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { - ShadowType shadowType = account.asObjectable(); - String resourceOid = ShadowUtil.getResourceOid(shadowType); - if (resourceOid == null) { - throw new SchemaException("The " + account + " has null resource reference OID"); - } - String intent = ShadowUtil.getIntent(shadowType); - ShadowKindType kind = ShadowUtil.getKind(shadowType); - ResourceType resource = LensUtil.getResourceReadOnly(context, resourceOid, provisioningService, task, result); - String accountIntent = LensUtil.refineProjectionIntent(kind, intent, resource, prismContext); - ResourceShadowDiscriminator rsd = new ResourceShadowDiscriminator(resourceOid, kind, accountIntent, shadowType.getTag(), false); - LensProjectionContext accountSyncContext = context.findProjectionContext(rsd); - if (accountSyncContext != null) { - throw new SchemaException("Attempt to add "+account+" to a focus that already contains projection of type '"+accountIntent+"' on "+resource); - } - accountSyncContext = context.createProjectionContext(rsd); - accountSyncContext.setResource(resource); - accountSyncContext.setOid(account.getOid()); - return accountSyncContext; - } - - private LensProjectionContext findAccountContext(String accountOid, LensContext context) { - for (LensProjectionContext accContext : context.getProjectionContexts()) { - if (accountOid.equals(accContext.getOid())) { - return accContext; - } - } - - return null; - } - - private LensProjectionContext getOrCreateEmptyThombstoneProjectionContext(LensContext context, - String missingShadowOid) { - LensProjectionContext projContext = context.findProjectionContextByOid(missingShadowOid); - if (projContext == null) { - projContext = context.createProjectionContext(null); - projContext.setOid(missingShadowOid); - } - - if (projContext.getResourceShadowDiscriminator() == null) { - projContext.setResourceShadowDiscriminator(new ResourceShadowDiscriminator(null, null, null, null, true)); - } else { - projContext.markTombstone(); - } - - projContext.setFullShadow(false); - projContext.setObjectCurrent(null); - - return projContext; - } - - /** - * Check reconcile flag in account sync context and set accountOld - * variable if it's not set (from provisioning), load resource (if not set already), etc. - */ - private void finishLoadOfProjectionContext(LensContext context, - LensProjectionContext projContext, Task task, OperationResult result) - throws ObjectNotFoundException, CommunicationException, SchemaException, ConfigurationException, - SecurityViolationException, ExpressionEvaluationException { - - if (projContext.getSynchronizationPolicyDecision() == SynchronizationPolicyDecision.BROKEN) { - return; - } - - // MID-2436 (volatile objects) - as a quick but effective hack, we set reconciliation:=TRUE for volatile accounts - ResourceObjectTypeDefinitionType objectDefinition = projContext.getResourceObjectTypeDefinitionType(); - if (objectDefinition != null && objectDefinition.getVolatility() == ResourceObjectVolatilityType.UNPREDICTABLE && !projContext.isDoReconciliation()) { - LOGGER.trace("Resource object volatility is UNPREDICTABLE => setting doReconciliation to TRUE for {}", projContext.getResourceShadowDiscriminator()); - projContext.setDoReconciliation(true); - } - - // Remember OID before the object could be wiped - String projectionObjectOid = projContext.getOid(); - if (projContext.isDoReconciliation() && !projContext.isFullShadow()) { - // The current object is useless here. So lets just wipe it so it will get loaded - projContext.setObjectCurrent(null); - } - - // Load current object - boolean tombstone = false; - PrismObject projectionObject = projContext.getObjectCurrent(); - if (projContext.getObjectCurrent() == null || needToReload(context, projContext)) { - if (projContext.isAdd()) { - // No need to load old object, there is none - projContext.setExists(false); - projContext.recompute(); - projectionObject = projContext.getObjectNew(); - } else { - if (projectionObjectOid == null) { - projContext.setExists(false); - if (projContext.getResourceShadowDiscriminator() == null || projContext.getResourceShadowDiscriminator().getResourceOid() == null) { - throw new SystemException( - "Projection "+projContext.getHumanReadableName()+" with null OID, no representation and no resource OID in account sync context "+projContext); - } - } else { - GetOperationOptions rootOptions = GetOperationOptions.createPointInTimeType(PointInTimeType.FUTURE); - if (projContext.isDoReconciliation()) { - rootOptions.setForceRefresh(true); - if (SchemaConstants.CHANGE_CHANNEL_DISCOVERY_URI.equals(context.getChannel())) { - // Avoid discovery loops - rootOptions.setDoNotDiscovery(true); - } - } else { - rootOptions.setNoFetch(true); - } - rootOptions.setAllowNotFound(true); - Collection> options = SelectorOptions.createCollection(rootOptions); - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Loading shadow {} for projection {}, options={}", projectionObjectOid, projContext.getHumanReadableName(), options); - } - - try { - PrismObject objectOld = provisioningService.getObject( - projContext.getObjectTypeClass(), projectionObjectOid, options, task, result); - if (LOGGER.isTraceEnabled()) { - if (!GetOperationOptions.isNoFetch(rootOptions) && !GetOperationOptions.isRaw(rootOptions)) { - LOGGER.trace("Full shadow loaded for {}:\n{}", projContext.getHumanReadableName(), objectOld.debugDump(1)); - } - } - Validate.notNull(objectOld.getOid()); - if (InternalsConfig.consistencyChecks) { - String resourceOid = projContext.getResourceOid(); - if (resourceOid != null && !resourceOid.equals(objectOld.asObjectable().getResourceRef().getOid())) { - throw new IllegalStateException("Loaded shadow with wrong resourceRef. Loading shadow "+projectionObjectOid+", got "+ - objectOld.getOid()+", expected resourceRef "+resourceOid+", but was "+objectOld.asObjectable().getResourceRef().getOid()+ - " for context "+projContext.getHumanReadableName()); - } - } - projContext.setLoadedObject(objectOld); - if (projContext.isDoReconciliation()) { - projContext.determineFullShadowFlag(objectOld); - } else { - projContext.setFullShadow(false); - } - projectionObject = objectOld; - if (ShadowUtil.isExists(objectOld.asObjectable())) { - projContext.setExists(true); - } else { - projContext.setExists(false); - if (ShadowUtil.isDead(objectOld.asObjectable())) { - projContext.markTombstone(); - } - LOGGER.debug("Foud only dead {} for projection context {}.", objectOld, projContext.getHumanReadableName()); - tombstone = true; - } - - } catch (ObjectNotFoundException ex) { - LOGGER.debug("Could not find object with oid {} for projection context {}.", projectionObjectOid, projContext.getHumanReadableName()); - // This does not mean BROKEN. The projection was there, but it gone now. - // Consistency mechanism might have kicked in and fixed the shadow. - // What we really want here is a thombstone projection or a refreshed projection. - result.muteLastSubresultError(); - projContext.setShadowExistsInRepo(false); - refreshContextAfterShadowNotFound(context, projContext, options, task, result); - - } catch (CommunicationException | SchemaException | ConfigurationException | SecurityViolationException - | RuntimeException | Error e) { - - LOGGER.warn("Problem while getting object with oid {}. Projection context {} is marked as broken: {}: {}", - projectionObjectOid, projContext.getHumanReadableName(), e.getClass().getSimpleName(), e.getMessage()); - projContext.setSynchronizationPolicyDecision(SynchronizationPolicyDecision.BROKEN); - - ResourceType resourceType = projContext.getResource(); - if (resourceType == null) { - throw e; - } else { - ErrorSelectorType errorSelector = null; - if (resourceType.getConsistency() != null) { - errorSelector = resourceType.getConsistency().getConnectorErrorCriticality(); - } - if (errorSelector == null) { - if (e instanceof SchemaException) { - // Just continue evaluation. The error is recorded in the result. - // The consistency mechanism has (most likely) already done the best. - // We cannot do any better. - return; - } else { - throw e; - } - } else { - if (CriticalityType.FATAL.equals(ExceptionUtil.getCriticality(errorSelector, e, CriticalityType.FATAL))) { - throw e; - } else { - return; - } - } - } - } - - } - projContext.setFresh(true); - } - } else { - projectionObject = projContext.getObjectCurrent(); - if (projectionObjectOid != null) { - projContext.setExists(ShadowUtil.isExists(projectionObject.asObjectable())); - } - } - - - // Determine Resource - ResourceType resourceType = projContext.getResource(); - String resourceOid = null; - if (resourceType == null) { - if (projectionObject != null) { - ShadowType shadowType = projectionObject.asObjectable(); - resourceOid = ShadowUtil.getResourceOid(shadowType); - } else if (projContext.getResourceShadowDiscriminator() != null) { - resourceOid = projContext.getResourceShadowDiscriminator().getResourceOid(); - } else if (!tombstone) { - throw new IllegalStateException("No shadow, no discriminator and not tombstone? That won't do. Projection "+projContext.getHumanReadableName()); - } - } else { - resourceOid = resourceType.getOid(); - } - - // Determine discriminator - ResourceShadowDiscriminator discr = projContext.getResourceShadowDiscriminator(); - if (discr == null) { - if (projectionObject != null) { - ShadowType accountShadowType = projectionObject.asObjectable(); - String intent = ShadowUtil.getIntent(accountShadowType); - ShadowKindType kind = ShadowUtil.getKind(accountShadowType); - discr = new ResourceShadowDiscriminator(resourceOid, kind, intent, accountShadowType.getTag(), tombstone); - } else { - discr = new ResourceShadowDiscriminator(null, null, null, null, tombstone); - } - projContext.setResourceShadowDiscriminator(discr); - } else { - if (tombstone) { - // We do not want to reset tombstone flag if it was set before - projContext.markTombstone(); - } - } - - // Load resource - if (resourceType == null && resourceOid != null) { - resourceType = LensUtil.getResourceReadOnly(context, resourceOid, provisioningService, task, result); - projContext.setResource(resourceType); - } - - //Determine refined schema and password policies for account type - RefinedObjectClassDefinition structuralObjectClassDef = projContext.getStructuralObjectClassDefinition(); - if (structuralObjectClassDef != null) { - loadProjectionSecurityPolicy(context, projContext, task, result); - } else { - LOGGER.trace("No structural object class definition, skipping determining security policy"); - } - - //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); - } - } - } - - setPrimaryDeltaOldValue(projContext); - } - - private void loadProjectionSecurityPolicy(LensContext context, - LensProjectionContext projContext, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException { - LOGGER.trace("Finishing loading of projection context: security policy"); - ObjectReferenceType securityPolicyRef = projContext.getStructuralObjectClassDefinition().getSecurityPolicyRef(); - if (securityPolicyRef == null || securityPolicyRef.getOid() == null) { - LOGGER.trace("Security policy not defined for the projection context."); - loadProjectionLegacyPasswordPolicy(context, projContext, task, result); - return; - } - LOGGER.trace("Loading security policy {} for projection context: {}", securityPolicyRef, projContext); - PrismObject securityPolicy = cacheRepositoryService.getObject(SecurityPolicyType.class, securityPolicyRef.getOid(), null, result); - if (securityPolicy == null) { - LOGGER.debug("Security policy {} defined for the projection does not exist", securityPolicyRef); - return; - } - LOGGER.trace("Found legacy password policy: {}", securityPolicy); - projContext.setProjectionSecurityPolicy(securityPolicy.asObjectable()); - } - - - private void loadProjectionLegacyPasswordPolicy(LensContext context, - LensProjectionContext projContext, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException { - ObjectReferenceType passwordPolicyRef = projContext.getStructuralObjectClassDefinition().getPasswordPolicy(); - if (passwordPolicyRef == null || passwordPolicyRef.getOid() == null) { - LOGGER.trace("Legacy password policy not defined for the projection context."); - return; - } - LOGGER.trace("Loading legacy password policy {} for projection context: {}", passwordPolicyRef, projContext); - PrismObject passwordPolicy = cacheRepositoryService.getObject( - ValuePolicyType.class, passwordPolicyRef.getOid(), null, result); - if (passwordPolicy == null) { - LOGGER.debug("Legacy password policy {} defined for the projection does not exist", passwordPolicyRef); - return; - } - ObjectReferenceType dummyPasswordPolicyRef = new ObjectReferenceType(); - dummyPasswordPolicyRef.asReferenceValue().setObject(passwordPolicy); - PrismObject securityPolicy = prismContext.createObject(SecurityPolicyType.class); - securityPolicy.asObjectable() - .beginCredentials() - .beginPassword() - .valuePolicyRef(dummyPasswordPolicyRef); - projContext.setProjectionSecurityPolicy(securityPolicy.asObjectable()); - } - - - private boolean needToReload(LensContext context, - LensProjectionContext projContext) { - ResourceShadowDiscriminator discr = projContext.getResourceShadowDiscriminator(); - if (discr == null) { - return false; - } - // This is kind of brutal. But effective. We are reloading all higher-order dependencies - // before they are processed. This makes sure we have fresh state when they are re-computed. - // Because higher-order dependencies may have more than one projection context and the - // changes applied to one of them are not automatically reflected on on other. therefore we need to reload. - if (discr.getOrder() == 0) { - return false; - } - int executionWave = context.getExecutionWave(); - int projCtxWave = projContext.getWave(); - if (executionWave == projCtxWave - 1) { - // Reload right before its execution wave - return true; - } - return false; - } - - private void fullCheckConsistence(LensContext context) { - context.checkConsistence(); - for (LensProjectionContext projectionContext: context.getProjectionContexts()) { - if (projectionContext.getSynchronizationPolicyDecision() == SynchronizationPolicyDecision.BROKEN) { - continue; - } - if (projectionContext.getResourceShadowDiscriminator() == null) { - throw new IllegalStateException("No discriminator in "+projectionContext); - } - } - } - - public void loadFullShadow(LensContext context, LensProjectionContext projCtx, String reason, Task task, OperationResult parentResult) - throws ObjectNotFoundException, CommunicationException, SchemaException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { - if (projCtx.isFullShadow()) { - // already loaded - return; - } - if (projCtx.isAdd() && projCtx.getOid() == null) { - // nothing to load yet - return; - } - if (projCtx.isTombstone()) { - // loading is futile - return; - } - OperationResult result = parentResult.subresult(CLASS_DOT + "loadFullShadow") - .setMinor() - .build(); - FullShadowLoadedTraceType trace; - if (result.isTraced()) { - trace = new FullShadowLoadedTraceType(prismContext); - if (result.isTracingNormal(FullShadowLoadedTraceType.class)) { - trace.setInputLensContextText(context.debugDump()); - } - trace.setInputLensContext(context.toLensContextType(getExportType(trace, result))); - result.addTrace(trace); - } else { - trace = null; - } - try { - ResourceShadowDiscriminator discr = projCtx.getResourceShadowDiscriminator(); - if (discr != null && discr.getOrder() > 0) { - // It may be just too early to load the projection - if (LensUtil.hasLowerOrderContext(context, projCtx) && (context.getExecutionWave() < projCtx.getWave())) { - // We cannot reliably load the context now - result.addReturn(DEFAULT, "too early"); - return; - } - } - - GetOperationOptions getOptions = GetOperationOptions.createAllowNotFound(); - getOptions.setPointInTimeType(PointInTimeType.FUTURE); - if (projCtx.isDoReconciliation()) { - getOptions.setForceRefresh(true); - } - if (SchemaConstants.CHANGE_CHANNEL_DISCOVERY_URI.equals(context.getChannel())) { - LOGGER.trace("Loading full resource object {} from provisioning - with doNotDiscover to avoid loops; reason: {}", - projCtx, reason); - // Avoid discovery loops - getOptions.setDoNotDiscovery(true); - } else { - LOGGER.trace("Loading full resource object {} from provisioning (discovery enabled), reason: {}, channel: {}", - projCtx, reason, context.getChannel()); - } - Collection> options = SelectorOptions.createCollection(getOptions); - applyAttributesToGet(projCtx, options); - try { - PrismObject objectCurrent = provisioningService - .getObject(ShadowType.class, projCtx.getOid(), options, task, result); - Validate.notNull(objectCurrent.getOid()); - // TODO: use setLoadedObject() instead? - projCtx.setObjectCurrent(objectCurrent); - projCtx.determineFullShadowFlag(objectCurrent); - if (ShadowUtil.isExists(objectCurrent.asObjectable())) { - result.addReturn(DEFAULT, "found"); - } else { - LOGGER.debug("Load of full resource object {} ended with non-existent shadow (options={})", projCtx, - getOptions); - projCtx.setExists(false); - refreshContextAfterShadowNotFound(context, projCtx, options, task, result); - result.addReturn(DEFAULT, "not found"); - } - - } catch (ObjectNotFoundException ex) { - LOGGER.debug("Load of full resource object {} ended with ObjectNotFoundException (options={})", projCtx, - getOptions); - result.muteLastSubresultError(); - projCtx.setShadowExistsInRepo(false); - refreshContextAfterShadowNotFound(context, projCtx, options, task, result); - result.addReturn(DEFAULT, "not found"); - } - - projCtx.recompute(); - - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Loaded full resource object:\n{}", projCtx.debugDump(1)); - } - } catch (Throwable t) { - result.recordFatalError(t); - throw t; - } finally { - if (trace != null) { - if (result.isTracingNormal(FullShadowLoadedTraceType.class)) { - trace.setOutputLensContextText(context.debugDump()); - } - trace.setOutputLensContext(context.toLensContextType(getExportType(trace, result))); - } - result.computeStatusIfUnknown(); - } - } - - public void refreshContextAfterShadowNotFound(LensContext context, LensProjectionContext projCtx, Collection> options, Task task, OperationResult result) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException { - if (projCtx.isDelete()){ - //this is OK, shadow was deleted, but we will continue in processing with old shadow..and set it as full so prevent from other full loading - projCtx.setFullShadow(true); - return; - } - - boolean compensated = false; - if (!GetOperationOptions.isDoNotDiscovery(SelectorOptions.findRootOptions(options))) { - // The account might have been re-created by the discovery. - // Reload focus, try to find out if there is a new matching link (and the old is gone) - LensFocusContext focusContext = context.getFocusContext(); - if (focusContext != null) { - Class focusClass = focusContext.getObjectTypeClass(); - if (FocusType.class.isAssignableFrom(focusClass)) { - LOGGER.trace("Reloading focus to check for new links"); - PrismObject focusCurrent; - try { - focusCurrent = cacheRepositoryService.getObject(focusContext.getObjectTypeClass(), focusContext.getOid(), null, result); - } catch (ObjectNotFoundException e) { - if (focusContext.isDelete()) { - // This may be OK. This may be later wave and the focus may be already deleted. - // Therefore let's just keep what we have. We have no way how to refresh context - // in that situation. - result.muteLastSubresultError(); - LOGGER.trace("ObjectNotFound error is not compensated (focus already deleted), setting context to tombstone"); - projCtx.markTombstone(); - return; - } else { - throw e; - } - } - FocusType focusType = (FocusType) focusCurrent.asObjectable(); - for (ObjectReferenceType linkRef: focusType.getLinkRef()) { - if (linkRef.getOid().equals(projCtx.getOid())) { - // The deleted shadow is still in the linkRef. This should not happen, but it obviously happens sometimes. - // Maybe some strange race condition? Anyway, we want a robust behavior and this linkRef should NOT be there. - // So simple remove it. - LOGGER.warn("The OID "+projCtx.getOid()+" of deleted shadow still exists in the linkRef after discovery ("+focusCurrent+"), removing it"); - ReferenceDelta unlinkDelta = prismContext.deltaFactory().reference().createModificationDelete( - FocusType.F_LINK_REF, focusContext.getObjectDefinition(), linkRef.asReferenceValue().clone()); - focusContext.swallowToSecondaryDelta(unlinkDelta); - continue; - } - boolean found = false; - for (LensProjectionContext pCtx: context.getProjectionContexts()) { - if (linkRef.getOid().equals(pCtx.getOid())) { - found = true; - break; - } - } - if (!found) { - // This link is new, it is not in the existing lens context - PrismObject newLinkRepoShadow = cacheRepositoryService.getObject(ShadowType.class, linkRef.getOid(), null, result); - if (ShadowUtil.matches(newLinkRepoShadow, projCtx.getResourceShadowDiscriminator())) { - LOGGER.trace("Found new matching link: {}, updating projection context", newLinkRepoShadow); - LOGGER.trace("Applying definition from provisioning first."); // MID-3317 - provisioningService.applyDefinition(newLinkRepoShadow, task, result); - projCtx.setObjectCurrent(newLinkRepoShadow); - projCtx.setOid(newLinkRepoShadow.getOid()); - projCtx.recompute(); - compensated = true; - break; - } else { - LOGGER.trace("Found new link: {}, but skipping it because it does not match the projection context", newLinkRepoShadow); - } - } - } - } - } - - } - - if (!compensated) { - LOGGER.trace("ObjectNotFound error is not compensated, setting context to tombstone"); - projCtx.markTombstone(); - } - } - - private void applyAttributesToGet(LensProjectionContext projCtx, Collection> options) throws SchemaException { - if ( !LensUtil.isPasswordReturnedByDefault(projCtx) - && LensUtil.needsFullShadowForCredentialProcessing(projCtx)) { - options.add(SelectorOptions.create(prismContext.toUniformPath(SchemaConstants.PATH_PASSWORD_VALUE), GetOperationOptions.createRetrieve())); - } - } - - public void reloadSecurityPolicyIfNeeded(@NotNull LensContext context, - @NotNull LensFocusContext focusContext, Task task, OperationResult result) - throws ExpressionEvaluationException, SchemaException, - CommunicationException, ConfigurationException, SecurityViolationException { - if (focusContext.hasOrganizationalChange()) { - loadSecurityPolicy(context, true, task, result); - } - } - - private void loadSecurityPolicy(LensContext context, - Task task, OperationResult result) throws ExpressionEvaluationException, - SchemaException, CommunicationException, ConfigurationException, SecurityViolationException { - loadSecurityPolicy(context, false, task, result); - } - - @SuppressWarnings("unchecked") - private void loadSecurityPolicy(LensContext context, boolean forceReload, - Task task, OperationResult result) throws ExpressionEvaluationException, - SchemaException, CommunicationException, ConfigurationException, SecurityViolationException { - LensFocusContext genericFocusContext = context.getFocusContext(); - if (genericFocusContext == null || !genericFocusContext.represents(FocusType.class)) { - LOGGER.trace("Skipping load of security policy because focus is not of FocusType"); - return; - } - LensFocusContext focusContext = (LensFocusContext) genericFocusContext; - PrismObject focus = focusContext.getObjectAny(); - SecurityPolicyType globalSecurityPolicy = determineAndSetGlobalSecurityPolicy(context, focus, task, result); - SecurityPolicyType focusSecurityPolicy = determineAndSetFocusSecurityPolicy(focusContext, focus, globalSecurityPolicy, - forceReload, task, result); - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Security policy:\n Global:\n{}\n Focus:\n{}", - globalSecurityPolicy.asPrismObject().debugDump(2), - focusSecurityPolicy==null?null:focusSecurityPolicy.asPrismObject().debugDump(2)); - } else { - LOGGER.debug("Security policy: global: {}, focus: {}", globalSecurityPolicy, focusSecurityPolicy); - } - } - - @NotNull - private SecurityPolicyType determineAndSetGlobalSecurityPolicy(LensContext context, - PrismObject focus, Task task, OperationResult result) - throws CommunicationException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { - SecurityPolicyType existingPolicy = context.getGlobalSecurityPolicy(); - if (existingPolicy != null) { - return existingPolicy; - } else { - SecurityPolicyType loadedPolicy = securityHelper.locateGlobalSecurityPolicy(focus, context.getSystemConfiguration(), - task, result); - SecurityPolicyType resultingPolicy; - if (loadedPolicy != null) { - resultingPolicy = loadedPolicy; - } else { - // use empty policy to avoid repeated lookups - resultingPolicy = new SecurityPolicyType(); - } - context.setGlobalSecurityPolicy(resultingPolicy); - return resultingPolicy; - } - } - - private SecurityPolicyType determineAndSetFocusSecurityPolicy(LensFocusContext focusContext, - PrismObject focus, SecurityPolicyType globalSecurityPolicy, boolean forceReload, Task task, - OperationResult result) throws SchemaException { - SecurityPolicyType existingPolicy = focusContext.getSecurityPolicy(); - if (existingPolicy != null && !forceReload) { - return existingPolicy; - } else { - SecurityPolicyType loadedPolicy = securityHelper.locateFocusSecurityPolicy(focus, task, result); - SecurityPolicyType resultingPolicy; - if (loadedPolicy != null) { - resultingPolicy = loadedPolicy; - } else { - // Not very clean. In fact we should store focus security policy separate from global - // policy to avoid confusion. But need to do this to fix MID-4793 and backport the fix. - // Therefore avoiding big changes. TODO: fix properly later - resultingPolicy = globalSecurityPolicy; - } - focusContext.setSecurityPolicy(resultingPolicy); - return resultingPolicy; - } - } -} +/* + * Copyright (c) 2010-2018 Evolveum and contributors + * + * This work is dual-licensed under the Apache License 2.0 + * and European Union Public License. See LICENSE file for details. + */ +package com.evolveum.midpoint.model.impl.lens.projector; + +import static com.evolveum.midpoint.model.impl.lens.LensUtil.getExportType; +import static com.evolveum.midpoint.schema.internals.InternalsConfig.consistencyChecks; +import static com.evolveum.midpoint.schema.result.OperationResult.DEFAULT; + +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +import com.evolveum.midpoint.prism.*; +import com.evolveum.midpoint.prism.delta.*; +import com.evolveum.midpoint.schema.*; +import com.evolveum.midpoint.schema.constants.ObjectTypes; +import com.evolveum.midpoint.schema.constants.SchemaConstants; +import com.evolveum.midpoint.schema.internals.InternalsConfig; +import com.evolveum.midpoint.xml.ns._public.common.common_3.*; + +import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang.Validate; +import org.jetbrains.annotations.NotNull; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; + +import com.evolveum.midpoint.common.refinery.RefinedObjectClassDefinition; +import com.evolveum.midpoint.model.api.ModelExecuteOptions; +import com.evolveum.midpoint.model.api.context.SynchronizationPolicyDecision; +import com.evolveum.midpoint.model.common.ArchetypeManager; +import com.evolveum.midpoint.model.common.SystemObjectCache; +import com.evolveum.midpoint.model.impl.lens.ClockworkMedic; +import com.evolveum.midpoint.model.impl.lens.LensContext; +import com.evolveum.midpoint.model.impl.lens.LensElementContext; +import com.evolveum.midpoint.model.impl.lens.LensFocusContext; +import com.evolveum.midpoint.model.impl.lens.LensObjectDeltaOperation; +import com.evolveum.midpoint.model.impl.lens.LensProjectionContext; +import com.evolveum.midpoint.model.impl.lens.LensUtil; +import com.evolveum.midpoint.model.impl.lens.SynchronizationIntent; +import com.evolveum.midpoint.model.impl.security.SecurityHelper; +import com.evolveum.midpoint.provisioning.api.ProvisioningService; +import com.evolveum.midpoint.repo.api.RepositoryService; +import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.schema.util.ExceptionUtil; +import com.evolveum.midpoint.schema.util.MiscSchemaUtil; +import com.evolveum.midpoint.schema.util.ShadowUtil; +import com.evolveum.midpoint.task.api.Task; +import com.evolveum.midpoint.util.exception.CommunicationException; +import com.evolveum.midpoint.util.exception.ConfigurationException; +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.PolicyViolationException; +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.logging.Trace; +import com.evolveum.midpoint.util.logging.TraceManager; + +/** + * Context loader loads the missing parts of the context. The context enters the projector with just the minimum information. + * Context loader gets missing data such as accounts. It gets them from the repository or provisioning as necessary. It follows + * the account links in focus (linkRef) and focus deltas. + * + * @author Radovan Semancik + * + */ +@Component +public class ContextLoader { + + @Autowired + @Qualifier("cacheRepositoryService") + private transient RepositoryService cacheRepositoryService; + + @Autowired private SystemObjectCache systemObjectCache; + @Autowired private ArchetypeManager archetypeManager; + @Autowired private ProvisioningService provisioningService; + @Autowired private PrismContext prismContext; + @Autowired private SecurityHelper securityHelper; + @Autowired private ClockworkMedic medic; + + private static final Trace LOGGER = TraceManager.getTrace(ContextLoader.class); + + public static final String CLASS_DOT = ContextLoader.class.getName() + "."; + private static final String OPERATION_LOAD = CLASS_DOT + "load"; + private static final String OPERATION_LOAD_PROJECTION = CLASS_DOT + "loadProjection"; + + public void load(LensContext context, String activityDescription, + Task task, OperationResult parentResult) + throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, + SecurityViolationException, PolicyViolationException, ExpressionEvaluationException { + + context.checkAbortRequested(); + + context.recompute(); + + OperationResult result = parentResult.createMinorSubresult(OPERATION_LOAD); + ProjectorComponentTraceType trace; + if (result.isTraced()) { + trace = new ProjectorComponentTraceType(prismContext); + if (result.isTracingNormal(ProjectorComponentTraceType.class)) { + trace.setInputLensContextText(context.debugDump()); + } + trace.setInputLensContext(context.toLensContextType(getExportType(trace, result))); + result.addTrace(trace); + } else { + trace = null; + } + + try { + + for (LensProjectionContext projectionContext: context.getProjectionContexts()) { + preprocessProjectionContext(context, projectionContext, task, result); + } + + if (consistencyChecks) context.checkConsistence(); + + determineFocusContext(context, task, result); + + LensFocusContext focusContext = context.getFocusContext(); + if (focusContext != null) { + + context.recomputeFocus(); + + loadFromSystemConfig(context, task, result); + + if (FocusType.class.isAssignableFrom(context.getFocusClass())) { + // this also removes the accountRef deltas + //noinspection unchecked + loadLinkRefs((LensContext)context, task, result); + LOGGER.trace("loadLinkRefs done"); + } + + // Some cleanup + if (focusContext.getPrimaryDelta() != null && focusContext.getPrimaryDelta().isModify() && focusContext.getPrimaryDelta().isEmpty()) { + focusContext.setPrimaryDelta(null); + } + + for (LensProjectionContext projectionContext: context.getProjectionContexts()) { + if (projectionContext.getSynchronizationIntent() != null) { + // Accounts with explicitly set intent are never rotten. These are explicitly requested actions + // if they fail then they really should fail. + projectionContext.setFresh(true); + } + } + + setPrimaryDeltaOldValue(focusContext); + + } else { + // Projection contexts are not rotten in this case. There is no focus so there is no way to refresh them. + for (LensProjectionContext projectionContext: context.getProjectionContexts()) { + projectionContext.setFresh(true); + } + } + + removeRottenContexts(context); + + if (consistencyChecks) context.checkConsistence(); + + for (LensProjectionContext projectionContext: context.getProjectionContexts()) { + context.checkAbortRequested(); + // TODO: not perfect. Practically, we want loadProjection operation to contain all the projection + // results. But for that we would need code restructure. + OperationResult projectionResult = result.createMinorSubresult(OPERATION_LOAD_PROJECTION); + try { + finishLoadOfProjectionContext(context, projectionContext, task, projectionResult); + } catch (Throwable e) { + projectionResult.recordFatalError(e); + throw e; + } + projectionResult.computeStatus(); + } + + if (consistencyChecks) context.checkConsistence(); + + context.recompute(); + + if (consistencyChecks) { + fullCheckConsistence(context); + } + + medic.traceContext(LOGGER, activityDescription, "after load", false, context, false); + + result.computeStatusComposite(); + + } catch (Throwable e) { + result.recordFatalError(e); + throw e; + } finally { + if (trace != null) { + if (result.isTracingNormal(ProjectorComponentTraceType.class)) { + trace.setOutputLensContextText(context.debugDump()); + } + trace.setOutputLensContext(context.toLensContextType(getExportType(trace, result))); + } + } + } + + + /** + * Removes projection contexts that are not fresh. + * These are usually artifacts left after the context reload. E.g. an account that used to be linked to a user before + * but was removed in the meantime. + */ + private void removeRottenContexts(LensContext context) { + Iterator projectionIterator = context.getProjectionContextsIterator(); + while (projectionIterator.hasNext()) { + LensProjectionContext projectionContext = projectionIterator.next(); + if (projectionContext.getPrimaryDelta() != null && !projectionContext.getPrimaryDelta().isEmpty()) { + // We must never remove contexts with primary delta. Even though it fails later on. + // What the user wishes should be done (or at least attempted) regardless of the consequences. + // Vox populi vox dei + continue; + } + if (projectionContext.getWave() >= context.getExecutionWave()) { + // We must not remove context from this and later execution waves. These haven't had the + // chance to be executed yet + continue; + } + ResourceShadowDiscriminator discr = projectionContext.getResourceShadowDiscriminator(); + if (discr != null && discr.getOrder() > 0) { + // HACK never rot higher-order context. TODO: check if lower-order context is rotten, the also rot this one + continue; + } + if (!projectionContext.isFresh()) { + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("Removing rotten context {}", projectionContext.getHumanReadableName()); + } + + if (projectionContext.isToBeArchived()) { + context.getHistoricResourceObjects().add(projectionContext.getResourceShadowDiscriminator()); + } + + List> executedDeltas = projectionContext.getExecutedDeltas(); + context.getRottenExecutedDeltas().addAll(executedDeltas); + projectionIterator.remove(); + } + } + } + + + /** + * Make sure that the projection context is loaded as appropriate. + */ + public void makeSureProjectionIsLoaded(LensContext context, + LensProjectionContext projectionContext, Task task, OperationResult result) throws ObjectNotFoundException, CommunicationException, SchemaException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { + preprocessProjectionContext(context, projectionContext, task, result); + finishLoadOfProjectionContext(context, projectionContext, task, result); + } + + /** + * Make sure that the context is OK and consistent. It means that is has a resource, it has correctly processed + * discriminator, etc. + */ + private void preprocessProjectionContext(LensContext context, + LensProjectionContext projectionContext, Task task, OperationResult result) + throws ObjectNotFoundException, CommunicationException, SchemaException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { + if (!ShadowType.class.isAssignableFrom(projectionContext.getObjectTypeClass())) { + return; + } + String resourceOid = null; + boolean isThombstone = false; + ShadowKindType kind = ShadowKindType.ACCOUNT; + String intent = null; + String tag = null; + int order = 0; + ResourceShadowDiscriminator rsd = projectionContext.getResourceShadowDiscriminator(); + if (rsd != null) { + resourceOid = rsd.getResourceOid(); + isThombstone = rsd.isTombstone(); + kind = rsd.getKind(); + intent = rsd.getIntent(); + tag = rsd.getTag(); + order = rsd.getOrder(); + } + if (resourceOid == null && projectionContext.getObjectCurrent() != null) { + resourceOid = ShadowUtil.getResourceOid(projectionContext.getObjectCurrent().asObjectable()); + } + if (resourceOid == null && projectionContext.getObjectNew() != null) { + resourceOid = ShadowUtil.getResourceOid(projectionContext.getObjectNew().asObjectable()); + } + // We still may not have resource OID here. E.g. in case of the delete when the account is not loaded yet. It is + // perhaps safe to skip this. It will be sorted out later. + + if (resourceOid != null) { + if (intent == null && projectionContext.getObjectNew() != null) { + ShadowType shadowNewType = projectionContext.getObjectNew().asObjectable(); + kind = ShadowUtil.getKind(shadowNewType); + intent = ShadowUtil.getIntent(shadowNewType); + tag = shadowNewType.getTag(); + } + ResourceType resource = projectionContext.getResource(); + if (resource == null) { + resource = LensUtil.getResourceReadOnly(context, resourceOid, provisioningService, task, result); + projectionContext.setResource(resource); + } + String refinedIntent = LensUtil.refineProjectionIntent(kind, intent, resource, prismContext); + rsd = new ResourceShadowDiscriminator(resourceOid, kind, refinedIntent, tag, isThombstone); + rsd.setOrder(order); + projectionContext.setResourceShadowDiscriminator(rsd); + } + if (projectionContext.getOid() == null && rsd != null && rsd.getOrder() != 0) { + // Try to determine OID from lower-order contexts + for (LensProjectionContext aProjCtx: context.getProjectionContexts()) { + ResourceShadowDiscriminator aDiscr = aProjCtx.getResourceShadowDiscriminator(); + if (rsd.equivalent(aDiscr) && aProjCtx.getOid() != null) { + projectionContext.setOid(aProjCtx.getOid()); + break; + } + } + } + } + + /** + * try to load focus context from oid, delta, projections (e.g. by determining account owners) + */ + public void determineFocusContext(LensContext context, Task task, OperationResult parentResult) + throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, + SecurityViolationException, ExpressionEvaluationException { + + OperationResult result = parentResult.subresult(CLASS_DOT + "determineFocusContext") + .setMinor() + .build(); + FocusLoadedTraceType trace; + if (result.isTraced()) { + trace = new FocusLoadedTraceType(prismContext); + if (result.isTracingNormal(FocusLoadedTraceType.class)) { + trace.setInputLensContextText(context.debugDump()); + } + trace.setInputLensContext(context.toLensContextType(getExportType(trace, result))); + result.addTrace(trace); + } else { + trace = null; + } + LensFocusContext focusContext = context.getFocusContext(); + try { + if (focusContext == null) { + focusContext = determineFocusContextFromProjections(context, result); + } + + if (focusContext == null) { + result.addReturnComment("Nothing to load"); + return; + } + + // Make sure that we RELOAD the focus object if the context is not fresh + // the focus may have changed in the meantime + if (focusContext.getObjectCurrent() != null && focusContext.isFresh()) { + result.addReturnComment("Already loaded"); + return; + } + ObjectDelta objectDelta = focusContext.getDelta(); + if (objectDelta != null && objectDelta.isAdd() && focusContext.getExecutedDeltas().isEmpty()) { + //we're adding the focal object. No need to load it, it is in the delta + focusContext.setFresh(true); + result.addReturnComment("Obtained from delta"); + return; + } + if (focusContext.getObjectCurrent() != null && objectDelta != null && objectDelta.isDelete()) { + // do not reload if the delta is delete. the reload will most likely fail anyway + // but DO NOT set the fresh flag in this case, it may be misleading + result.addReturnComment("Not loading as delta is DELETE"); + return; + } + + String focusOid = focusContext.getOid(); + if (StringUtils.isBlank(focusOid)) { + throw new IllegalArgumentException("No OID in primary focus delta"); + } + + PrismObject object; + if (ObjectTypes.isClassManagedByProvisioning(focusContext.getObjectTypeClass())) { + object = provisioningService.getObject(focusContext.getObjectTypeClass(), focusOid, + SelectorOptions.createCollection(GetOperationOptions.createNoFetch()), task, result); + result.addReturnComment("Loaded via provisioning"); + } else { + + // Always load a complete object here, including the not-returned-by-default properties. + // This is temporary measure to make sure that the mappings will have all they need. + // See MID-2635 + Collection> options = + SelectorOptions.createCollection(GetOperationOptions.createRetrieve(RetrieveOption.INCLUDE)); + object = cacheRepositoryService.getObject(focusContext.getObjectTypeClass(), focusOid, options, result); + result.addReturnComment("Loaded from repository"); + } + + focusContext.setLoadedObject(object); + focusContext.setFresh(true); + LOGGER.trace("Focal object loaded: {}", object); + } catch (Throwable t) { + result.recordFatalError(t); + throw t; + } finally { + if (trace != null) { + if (result.isTracingNormal(FocusLoadedTraceType.class)) { + trace.setOutputLensContextText(context.debugDump()); + } + trace.setOutputLensContext(context.toLensContextType(getExportType(trace, result))); + } + result.computeStatusIfUnknown(); + } + } + + private LensFocusContext determineFocusContextFromProjections(LensContext context, OperationResult result) { + String focusOid = null; + LensProjectionContext projectionContextThatYeildedFocusOid = null; + PrismObject focusOwner = null; + for (LensProjectionContext projectionContext: context.getProjectionContexts()) { + String projectionOid = projectionContext.getOid(); + if (projectionOid != null) { + PrismObject shadowOwner = cacheRepositoryService.searchShadowOwner(projectionOid, + SelectorOptions.createCollection(GetOperationOptions.createAllowNotFound()), + result); + if (shadowOwner != null) { + if (focusOid == null || focusOid.equals(shadowOwner.getOid())) { + focusOid = shadowOwner.getOid(); + //noinspection unchecked + focusOwner = (PrismObject) shadowOwner; + projectionContextThatYeildedFocusOid = projectionContext; + } else { + throw new IllegalArgumentException("The context does not have explicit focus. Attempt to determine focus failed because two " + + "projections points to different foci: "+projectionContextThatYeildedFocusOid+"->"+focusOid+"; "+ + projectionContext+"->"+shadowOwner); + } + } + } + } + + if (focusOid != null) { + LensFocusContext focusCtx = context.getOrCreateFocusContext(focusOwner.getCompileTimeClass()); + focusCtx.setOid(focusOid); + return focusCtx; + } + + return null; + } + + private void setPrimaryDeltaOldValue(LensElementContext ctx) { + if (ctx.getPrimaryDelta() != null && ctx.getObjectOld() != null && ctx.isModify()) { + boolean freezeAfterChange; + if (ctx.getPrimaryDelta().isImmutable()) { + ctx.setPrimaryDelta(ctx.getPrimaryDelta().clone()); + freezeAfterChange = true; + } else { + freezeAfterChange = false; + } + for (ItemDelta itemDelta: ctx.getPrimaryDelta().getModifications()) { + LensUtil.setDeltaOldValue(ctx, itemDelta); + } + if (freezeAfterChange) { + ctx.getPrimaryDelta().freeze(); + } + } + } + + private void loadFromSystemConfig(LensContext context, Task task, OperationResult result) + throws ObjectNotFoundException, SchemaException, ConfigurationException, ExpressionEvaluationException, CommunicationException, SecurityViolationException { + PrismObject systemConfiguration = systemObjectCache.getSystemConfiguration(result); + if (systemConfiguration == null) { + // This happens in some tests. And also during first startup. + return; + } + context.setSystemConfiguration(systemConfiguration); + SystemConfigurationType systemConfigurationType = systemConfiguration.asObjectable(); + + if (context.getFocusContext() != null) { + if (context.getFocusContext().getArchetypePolicyType() == null) { + ArchetypePolicyType archetypePolicy = determineArchetypePolicy(context, task, result); + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("Selected archetype policy:\n{}", + archetypePolicy==null?null:archetypePolicy.asPrismContainerValue().debugDump(1)); + } + context.getFocusContext().setArchetypePolicyType(archetypePolicy); + } + } + + if (context.getFocusTemplate() == null) { + // TODO is the nullity check needed here? + setFocusTemplate(context, result); + } + + if (context.getAccountSynchronizationSettings() == null) { + ProjectionPolicyType globalAccountSynchronizationSettings = systemConfigurationType.getGlobalAccountSynchronizationSettings(); + LOGGER.trace("Applying globalAccountSynchronizationSettings to context: {}", globalAccountSynchronizationSettings); + context.setAccountSynchronizationSettings(globalAccountSynchronizationSettings); + } + + loadSecurityPolicy(context, task, result); + } + + private ArchetypePolicyType determineArchetypePolicy(LensContext context, Task task, OperationResult result) throws SchemaException, ConfigurationException { + PrismObject systemConfiguration = context.getSystemConfiguration(); + if (systemConfiguration == null) { + return null; + } + if (context.getFocusContext() == null) { + return null; + } + PrismObject object = context.getFocusContext().getObjectAny(); + String explicitArchetypeOid = LensUtil.determineExplicitArchetypeOid(context.getFocusContext().getObjectAny()); + return archetypeManager.determineArchetypePolicy(object, explicitArchetypeOid, result); + } + + public ArchetypeType updateArchetype(LensContext context, Task task, OperationResult result) throws SchemaException, ConfigurationException { + PrismObject systemConfiguration = context.getSystemConfiguration(); + if (systemConfiguration == null) { + return null; + } + if (context.getFocusContext() == null) { + return null; + } + + PrismObject object = context.getFocusContext().getObjectAny(); + + String explicitArchetypeOid = LensUtil.determineExplicitArchetypeOid(context.getFocusContext().getObjectAny()); + PrismObject archetype = archetypeManager.determineArchetype(object, explicitArchetypeOid, result); + ArchetypeType archetypeType = null; + if (archetype != null) { + archetypeType = archetype.asObjectable(); + } + + context.getFocusContext().setArchetype(archetypeType); + + return archetypeType; + } + + public void updateArchetypePolicy(LensContext context, Task task, OperationResult result) throws SchemaException, ConfigurationException { + if (context.getFocusContext() == null) { + return; + } + ArchetypePolicyType newArchetypePolicy = determineArchetypePolicy(context, task, result); + if (newArchetypePolicy != context.getFocusContext().getArchetypePolicyType()) { + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("Changed policy configuration because of changed subtypes:\n{}", + newArchetypePolicy==null?null:newArchetypePolicy.asPrismContainerValue().debugDump(1)); + } + context.getFocusContext().setArchetypePolicyType(newArchetypePolicy); + } + } + + // expects that object policy configuration is already set in focusContext + public void setFocusTemplate(LensContext context, OperationResult result) + throws ObjectNotFoundException, SchemaException { + + // 1. When this method is called after inbound processing, we might want to change the existing template + // (because e.g. subtype or archetype was determined and we want to move from generic to more specific template). + // 2. On the other hand, if focus template is set up explicitly from the outside (e.g. in synchronization section) + // we probably do not want to change it here. + if (context.getFocusTemplate() != null && context.isFocusTemplateExternallySet()) { + return; + } + + String currentOid = context.getFocusTemplate() != null ? context.getFocusTemplate().getOid() : null; + String newOid; + + LensFocusContext focusContext = context.getFocusContext(); + if (focusContext == null) { + newOid = null; + } else { + ArchetypePolicyType archetypePolicy = focusContext.getArchetypePolicyType(); + if (archetypePolicy == null) { + LOGGER.trace("No default object template (no policy)"); + newOid = null; + } else { + ObjectReferenceType templateRef = archetypePolicy.getObjectTemplateRef(); + if (templateRef == null) { + LOGGER.trace("No default object template (no templateRef)"); + newOid = null; + } else { + newOid = templateRef.getOid(); + } + } + } + + LOGGER.trace("current focus template OID = {}, new = {}", currentOid, newOid); + if (!java.util.Objects.equals(currentOid, newOid)) { + ObjectTemplateType template; + if (newOid != null) { + template = cacheRepositoryService.getObject(ObjectTemplateType.class, newOid, null, result).asObjectable(); + } else { + template = null; + } + context.setFocusTemplate(template); + } + } + + private void loadLinkRefs(LensContext context, Task task, OperationResult result) throws ObjectNotFoundException, + SchemaException, CommunicationException, ConfigurationException, SecurityViolationException, PolicyViolationException, ExpressionEvaluationException { + LensFocusContext focusContext = context.getFocusContext(); + if (focusContext == null) { + // Nothing to load + return; + } + + LOGGER.trace("loadLinkRefs starting"); + + PrismObject focusCurrent = focusContext.getObjectCurrent(); + if (focusCurrent != null) { + loadLinkRefsFromFocus(context, focusCurrent, task, result); + LOGGER.trace("loadLinkRefsFromFocus done"); + } + + if (consistencyChecks) context.checkConsistence(); + + loadLinkRefsFromDelta(context, focusCurrent, focusContext, task, result); + LOGGER.trace("loadLinkRefsFromDelta done"); + + if (consistencyChecks) context.checkConsistence(); + + loadProjectionContextsSync(context, task, result); + LOGGER.trace("loadProjectionContextsSync done"); + + if (consistencyChecks) context.checkConsistence(); + } + + /** + * Does not overwrite existing account contexts, just adds new ones. + */ + private void loadLinkRefsFromFocus(LensContext context, PrismObject focus, + Task task, OperationResult result) throws ObjectNotFoundException, + CommunicationException, SchemaException, ConfigurationException, SecurityViolationException, PolicyViolationException, ExpressionEvaluationException { + PrismReference linkRef = focus.findReference(FocusType.F_LINK_REF); + if (linkRef == null) { + return; + } + for (PrismReferenceValue linkRefVal : linkRef.getValues()) { + String oid = linkRefVal.getOid(); + if (StringUtils.isBlank(oid)) { + LOGGER.trace("Null or empty OID in link reference {} in:\n{}", linkRef, + focus.debugDump(1)); + 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 + + existingAccountContext.setFresh(true); + continue; + } + PrismObject shadow; + //noinspection unchecked + PrismObject shadowFromLink = linkRefVal.getObject(); + if (shadowFromLink == null) { + GetOperationOptions rootOpts; + if (context.isDoReconciliationForAllProjections()) { + rootOpts = GetOperationOptions.createForceRetry(); + } else { + // Using NO_FETCH so we avoid reading in a full account. This is more efficient as we don't need full account here. + // We need to fetch from provisioning and not repository so the correct definition will be set. + rootOpts = GetOperationOptions.createNoFetch(); + rootOpts.setPointInTimeType(PointInTimeType.FUTURE); + } + + Collection> options = SelectorOptions.createCollection(rootOpts); + LOGGER.trace("Loading shadow {} from linkRef, options={}", oid, options); + try { + shadow = provisioningService.getObject(ShadowType.class, oid, options, task, result); + } catch (ObjectNotFoundException e) { + // Broken accountRef. We need to mark it for deletion + LensProjectionContext projectionContext = getOrCreateEmptyThombstoneProjectionContext(context, oid); + projectionContext.setFresh(true); + projectionContext.setExists(false); + projectionContext.setShadowExistsInRepo(false); + OperationResult getObjectSubresult = result.getLastSubresult(); + getObjectSubresult.setErrorsHandled(); + continue; + } + } else { + shadow = shadowFromLink; + // Make sure it has a proper definition. This may come from outside of the model. + provisioningService.applyDefinition(shadow, task, result); + } + LensProjectionContext projectionContext = getOrCreateAccountContext(context, shadow, task, result); + projectionContext.setFresh(true); + projectionContext.setExists(ShadowUtil.isExists(shadow.asObjectable())); + if (ShadowUtil.isDead(shadow.asObjectable())) { + projectionContext.markTombstone(); + LOGGER.trace("Loading dead shadow {} for projection {}.", shadow, projectionContext.getHumanReadableName()); + continue; + } + if (context.isDoReconciliationForAllProjections()) { + projectionContext.setDoReconciliation(true); + } + if (projectionContext.isDoReconciliation()) { + // Do not load old account now. It will get loaded later in the + // reconciliation step. + continue; + } + projectionContext.setLoadedObject(shadow); + } + } + + private void loadLinkRefsFromDelta(LensContext context, PrismObject focus, + LensFocusContext focusContext, Task task, OperationResult result) throws SchemaException, + ObjectNotFoundException, CommunicationException, ConfigurationException, + SecurityViolationException, PolicyViolationException, ExpressionEvaluationException { + + ObjectDelta focusPrimaryDelta = focusContext.getPrimaryDelta(); + if (focusPrimaryDelta == null) { + return; + } + + ReferenceDelta linkRefDelta; + if (focusPrimaryDelta.getChangeType() == ChangeType.ADD) { + PrismReference linkRef = focusPrimaryDelta.getObjectToAdd().findReference( + FocusType.F_LINK_REF); + if (linkRef == null) { + // Adding new focus with no linkRef -> nothing to do + return; + } + linkRefDelta = linkRef.createDelta(FocusType.F_LINK_REF); + linkRefDelta.addValuesToAdd(PrismValueCollectionsUtil.cloneValues(linkRef.getValues())); + } else if (focusPrimaryDelta.getChangeType() == ChangeType.MODIFY) { + linkRefDelta = focusPrimaryDelta.findReferenceModification(FocusType.F_LINK_REF); + if (linkRefDelta == null) { + return; + } + } else { + // delete, all existing account are already marked for delete + return; + } + + if (linkRefDelta.isReplace()) { + // process "replace" by distributing values to delete and add + linkRefDelta = (ReferenceDelta) linkRefDelta.clone(); + PrismReference linkRef = focus.findReference(FocusType.F_LINK_REF); + linkRefDelta.distributeReplace(linkRef == null ? null : linkRef.getValues()); + } + + if (linkRefDelta.getValuesToAdd() != null) { + for (PrismReferenceValue refVal : linkRefDelta.getValuesToAdd()) { + String oid = refVal.getOid(); + LensProjectionContext projectionContext = null; + PrismObject shadow = null; + boolean isCombinedAdd = false; + if (oid == null) { + // Adding new account + shadow = refVal.getObject(); + if (shadow == null) { + throw new SchemaException("Null or empty OID in account reference " + refVal + " in " + + focus); + } + provisioningService.applyDefinition(shadow, task, result); + if (consistencyChecks) ShadowUtil.checkConsistence(shadow, "account from "+linkRefDelta); + // Check for conflicting change + projectionContext = LensUtil.getProjectionContext(context, shadow, provisioningService, prismContext, task, result); + if (projectionContext != null) { + // There is already existing context for the same discriminator. Tolerate this only if + // the deltas match. It is an error otherwise. + ObjectDelta primaryDelta = projectionContext.getPrimaryDelta(); + if (primaryDelta == null) { + throw new SchemaException("Attempt to add "+shadow+" to a focus that already contains "+ + projectionContext.getHumanReadableKind()+" of type '"+ + projectionContext.getResourceShadowDiscriminator().getIntent()+"' on "+projectionContext.getResource()); + } + if (!primaryDelta.isAdd()) { + throw new SchemaException("Conflicting changes in the context. " + + "Add of linkRef in the focus delta with embedded object conflicts with explicit delta "+primaryDelta); + } + if (!shadow.equals(primaryDelta.getObjectToAdd())) { + throw new SchemaException("Conflicting changes in the context. " + + "Add of linkRef in the focus delta with embedded object is not adding the same object as explicit delta "+primaryDelta); + } + } else { + // Create account context from embedded object + projectionContext = createProjectionContext(context, shadow, task, result); + } + // This is a new account that is to be added. So it should + // go to account primary delta + ObjectDelta accountPrimaryDelta = shadow.createAddDelta(); + projectionContext.setPrimaryDelta(accountPrimaryDelta); + projectionContext.setFullShadow(true); + projectionContext.setExists(false); + isCombinedAdd = true; + } else { + // We have OID. This is either linking of existing account or + // add of new account + // therefore check for account existence to decide + try { + // Using NO_FETCH so we avoid reading in a full account. This is more efficient as we don't need full account here. + // We need to fetch from provisioning and not repository so the correct definition will be set. + GetOperationOptions rootOpts = GetOperationOptions.createNoFetch(); + rootOpts.setPointInTimeType(PointInTimeType.FUTURE); + Collection> options = SelectorOptions.createCollection(rootOpts); + shadow = provisioningService.getObject(ShadowType.class, oid, options, task, result); + // Create account context from retrieved object + projectionContext = getOrCreateAccountContext(context, shadow, task, result); + projectionContext.setLoadedObject(shadow); + projectionContext.setExists(ShadowUtil.isExists(shadow.asObjectable())); + } catch (ObjectNotFoundException e) { + if (refVal.getObject() == null) { + // account does not exist, no composite account in + // ref -> this is really an error + throw e; + } else { + // New account (with OID) + result.muteLastSubresultError(); + shadow = refVal.getObject(); + if (!shadow.hasCompleteDefinition()) { + provisioningService.applyDefinition(shadow, task, result); + } + // Create account context from embedded object + projectionContext = createProjectionContext(context, shadow, task, result); + ObjectDelta accountPrimaryDelta = shadow.createAddDelta(); + projectionContext.setPrimaryDelta(accountPrimaryDelta); + projectionContext.setFullShadow(true); + projectionContext.setExists(false); + projectionContext.setShadowExistsInRepo(false); + isCombinedAdd = true; + } + } + } + if (context.isDoReconciliationForAllProjections() && !isCombinedAdd) { + projectionContext.setDoReconciliation(true); + } + projectionContext.setFresh(true); + } + } + + if (linkRefDelta.getValuesToDelete() != null) { + for (PrismReferenceValue refVal : linkRefDelta.getValuesToDelete()) { + String oid = refVal.getOid(); + LensProjectionContext projectionContext = null; + PrismObject shadow = null; + if (oid == null) { + throw new SchemaException("Cannot delete account ref without an oid in " + focus); + } else { + try { + // Using NO_FETCH so we avoid reading in a full account. This is more efficient as we don't need full account here. + // We need to fetch from provisioning and not repository so the correct definition will be set. + Collection> options = SelectorOptions.createCollection(GetOperationOptions.createNoFetch()); + shadow = provisioningService.getObject(ShadowType.class, oid, options, task, result); + // Create account context from retrieved object + projectionContext = getOrCreateAccountContext(context, shadow, task, result); + projectionContext.setLoadedObject(shadow); + projectionContext.setExists(ShadowUtil.isExists(shadow.asObjectable())); + } catch (ObjectNotFoundException e) { + try{ + // Broken accountRef. We need to try again with raw options, because the error should be thrown because of non-existent resource + Collection> options = SelectorOptions.createCollection(GetOperationOptions.createRaw()); + shadow = provisioningService.getObject(ShadowType.class, oid, options, task, result); + projectionContext = getOrCreateEmptyThombstoneProjectionContext(context, oid); + projectionContext.setFresh(true); + projectionContext.setExists(false); + projectionContext.setShadowExistsInRepo(false); + OperationResult getObjectSubresult = result.getLastSubresult(); + getObjectSubresult.setErrorsHandled(); + } catch (ObjectNotFoundException ex){ + // This is still OK. It means deleting an accountRef + // that points to non-existing object + // just log a warning + LOGGER.warn("Deleting accountRef of " + focus + " that points to non-existing OID " + + oid); + } + + } + } + if (projectionContext != null) { + if (refVal.getObject() == null) { + projectionContext.setSynchronizationIntent(SynchronizationIntent.UNLINK); + } else { + projectionContext.setSynchronizationIntent(SynchronizationIntent.DELETE); + ObjectDelta accountPrimaryDelta = shadow.createDeleteDelta(); + projectionContext.setPrimaryDelta(accountPrimaryDelta); + } + projectionContext.setFresh(true); + } + + } + } + + // remove the accountRefs without oid. These will get into the way now. + // The accounts + // are in the context now and will be linked at the end of the process + // (it they survive the policy) + // We need to make sure this happens on the real primary focus delta + + ObjectDelta primaryDeltaToUpdate; + if (focusPrimaryDelta.isImmutable()) { + primaryDeltaToUpdate = focusPrimaryDelta.clone(); + focusContext.setPrimaryDelta(primaryDeltaToUpdate); + } else { + primaryDeltaToUpdate = focusPrimaryDelta; + } + + if (primaryDeltaToUpdate.getChangeType() == ChangeType.ADD) { + primaryDeltaToUpdate.getObjectToAdd().removeReference(FocusType.F_LINK_REF); + } else if (primaryDeltaToUpdate.getChangeType() == ChangeType.MODIFY) { + primaryDeltaToUpdate.removeReferenceModification(FocusType.F_LINK_REF); + } + // It is little bit questionable whether we need to make primary delta immutable. It makes some sense, but I am not sure. + // Note that (as a side effect) this can make "focus new" immutable as well, in the case of ADD delta. + primaryDeltaToUpdate.freeze(); + } + + private void loadProjectionContextsSync(LensContext context, Task task, OperationResult result) throws SchemaException, + ObjectNotFoundException, CommunicationException, ConfigurationException, + SecurityViolationException, ExpressionEvaluationException { + for (LensProjectionContext projCtx : context.getProjectionContexts()) { + if (projCtx.isFresh() && projCtx.getObjectCurrent() != null) { + // already loaded + continue; + } + ObjectDelta syncDelta = projCtx.getSyncDelta(); + if (syncDelta != null) { + if (projCtx.isDoReconciliation()) { + // Do not load old account now. It will get loaded later in the + // reconciliation step. Just mark it as fresh. + projCtx.setFresh(true); + continue; + } + String oid = syncDelta.getOid(); + PrismObject shadow = null; + + if (syncDelta.getChangeType() == ChangeType.ADD) { + shadow = syncDelta.getObjectToAdd().clone(); + projCtx.setLoadedObject(shadow); + projCtx.setExists(ShadowUtil.isExists(shadow.asObjectable())); + + } else { + + if (oid == null) { + throw new IllegalArgumentException("No OID in sync delta in " + projCtx); + } + // Using NO_FETCH so we avoid reading in a full account. This is more efficient as we don't need full account here. + // We need to fetch from provisioning and not repository so the correct definition will be set. + GetOperationOptions option = GetOperationOptions.createNoFetch(); + option.setDoNotDiscovery(true); + option.setPointInTimeType(PointInTimeType.FUTURE); + Collection> options = SelectorOptions.createCollection(option); + + try { + + shadow = provisioningService.getObject(ShadowType.class, oid, options, task, result); + + } catch (ObjectNotFoundException e) { + LOGGER.trace("Loading shadow {} from sync delta failed: not found", oid); + projCtx.setExists(false); + projCtx.setObjectCurrent(null); + projCtx.setShadowExistsInRepo(false); + } + + // We will not set old account if the delta is delete. The + // account does not really exists now. + // (but the OID and resource will be set from the repo + // shadow) + if (syncDelta.getChangeType() == ChangeType.DELETE) { + projCtx.markTombstone(); + } else if (shadow != null) { + syncDelta.applyTo(shadow); + projCtx.setLoadedObject(shadow); + projCtx.setExists(ShadowUtil.isExists(shadow.asObjectable())); + } + } + + // Make sure OID is set correctly + projCtx.setOid(oid); + // Make sure that resource is also resolved + if (projCtx.getResource() == null && shadow != null) { + String resourceOid = ShadowUtil.getResourceOid(shadow.asObjectable()); + if (resourceOid == null) { + throw new IllegalArgumentException("No resource OID in " + shadow); + } + ResourceType resourceType = LensUtil.getResourceReadOnly(context, resourceOid, provisioningService, task, result); + projCtx.setResource(resourceType); + } + projCtx.setFresh(true); + } + } + } + +// 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 projection, Task task, OperationResult result) throws ObjectNotFoundException, + CommunicationException, SchemaException, ConfigurationException, SecurityViolationException, PolicyViolationException, ExpressionEvaluationException { + ShadowType shadowType = projection.asObjectable(); + String resourceOid = ShadowUtil.getResourceOid(shadowType); + if (resourceOid == null) { + throw new SchemaException("The " + projection + " has null resource reference OID"); + } + + LensProjectionContext projectionContext = context.findProjectionContextByOid(shadowType.getOid()); + + if (projectionContext == null) { + String intent = ShadowUtil.getIntent(shadowType); + ShadowKindType kind = ShadowUtil.getKind(shadowType); + ResourceType resource = LensUtil.getResourceReadOnly(context, resourceOid, provisioningService, task, result); + intent = LensUtil.refineProjectionIntent(kind, intent, resource, prismContext); + boolean thombstone = false; + if (ShadowUtil.isDead(shadowType)) { + thombstone = true; + } + ResourceShadowDiscriminator rsd = new ResourceShadowDiscriminator(resourceOid, kind, intent, shadowType.getTag(), thombstone); + projectionContext = LensUtil.getOrCreateProjectionContext(context, rsd); + + if (projectionContext.getOid() == null) { + projectionContext.setOid(projection.getOid()); + } else if (projection.getOid() != null && !projectionContext.getOid().equals(projection.getOid())) { + // Conflict. We have existing projection and another project that is added (with the same discriminator). + // Chances are that the old object is already deleted (e.g. during rename). So let's be + // slightly inefficient here and check for existing shadow existence + try { + GetOperationOptions rootOpt = GetOperationOptions.createPointInTimeType(PointInTimeType.FUTURE); + rootOpt.setDoNotDiscovery(true); + Collection> opts = SelectorOptions.createCollection(rootOpt); + LOGGER.trace("Projection conflict detected, existing: {}, new {}", projectionContext.getOid(), projection.getOid()); + PrismObject existingShadow = provisioningService.getObject(ShadowType.class, projectionContext.getOid(), opts, task, result); + // Maybe it is the other way around + try { + PrismObject newShadow = provisioningService.getObject(ShadowType.class, projection.getOid(), opts, task, result); + // Obviously, two projections with the same discriminator exists + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("Projection {} already exists in context\nExisting:\n{}\nNew:\n{}", rsd, + existingShadow.debugDump(1), newShadow.debugDump(1)); + } + if (!ShadowUtil.isDead(newShadow.asObjectable())) { + throw new PolicyViolationException("Projection "+rsd+" already exists in context (existing "+existingShadow+", new "+projection); + } + // Dead shadow. This is somehow expected, fix it and we can go on + rsd.setTombstone(true); + projectionContext = LensUtil.getOrCreateProjectionContext(context, rsd); + projectionContext.setExists(ShadowUtil.isExists(newShadow.asObjectable())); + projectionContext.setFullShadow(false); + } catch (ObjectNotFoundException e) { + // This is somehow expected, fix it and we can go on + result.muteLastSubresultError(); + // We have to create new context in this case, but it has to have thumbstone set + rsd.setTombstone(true); + projectionContext = LensUtil.getOrCreateProjectionContext(context, rsd); + // We have to mark it as dead right now, otherwise the uniqueness check may fail + markShadowDead(projection.getOid(), result); + projectionContext.setShadowExistsInRepo(false); + } + } catch (ObjectNotFoundException e) { + // This is somehow expected, fix it and we can go on + result.muteLastSubresultError(); + String shadowOid = projectionContext.getOid(); + projectionContext.getResourceShadowDiscriminator().setTombstone(true); + projectionContext = LensUtil.getOrCreateProjectionContext(context, rsd); + projectionContext.setShadowExistsInRepo(false); + // We have to mark it as dead right now, otherwise the uniqueness check may fail + markShadowDead(shadowOid, result); + } + } + } + return projectionContext; + } + + private void markShadowDead(String oid, OperationResult result) { + if (oid == null) { + // nothing to mark + return; + } + Collection> modifications = MiscSchemaUtil.createCollection( + prismContext.deltaFactory().property().createReplaceDelta(prismContext.getSchemaRegistry().findObjectDefinitionByCompileTimeClass(ShadowType.class), + ShadowType.F_DEAD, true)); + try { + cacheRepositoryService.modifyObject(ShadowType.class, oid, modifications, result); + // TODO report to task? + } catch (ObjectNotFoundException e) { + // Done already + result.muteLastSubresultError(); + } catch (ObjectAlreadyExistsException | SchemaException e) { + // Should not happen + throw new SystemException(e.getMessage(), e); + } + } + + + private LensProjectionContext createProjectionContext(LensContext context, + PrismObject account, Task task, OperationResult result) throws ObjectNotFoundException, + CommunicationException, SchemaException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { + ShadowType shadowType = account.asObjectable(); + String resourceOid = ShadowUtil.getResourceOid(shadowType); + if (resourceOid == null) { + throw new SchemaException("The " + account + " has null resource reference OID"); + } + String intent = ShadowUtil.getIntent(shadowType); + ShadowKindType kind = ShadowUtil.getKind(shadowType); + ResourceType resource = LensUtil.getResourceReadOnly(context, resourceOid, provisioningService, task, result); + String accountIntent = LensUtil.refineProjectionIntent(kind, intent, resource, prismContext); + ResourceShadowDiscriminator rsd = new ResourceShadowDiscriminator(resourceOid, kind, accountIntent, shadowType.getTag(), false); + LensProjectionContext accountSyncContext = context.findProjectionContext(rsd); + if (accountSyncContext != null) { + throw new SchemaException("Attempt to add "+account+" to a focus that already contains projection of type '"+accountIntent+"' on "+resource); + } + accountSyncContext = context.createProjectionContext(rsd); + accountSyncContext.setResource(resource); + accountSyncContext.setOid(account.getOid()); + return accountSyncContext; + } + + private LensProjectionContext findAccountContext(String accountOid, LensContext context) { + for (LensProjectionContext accContext : context.getProjectionContexts()) { + if (accountOid.equals(accContext.getOid())) { + return accContext; + } + } + + return null; + } + + private LensProjectionContext getOrCreateEmptyThombstoneProjectionContext(LensContext context, + String missingShadowOid) { + LensProjectionContext projContext = context.findProjectionContextByOid(missingShadowOid); + if (projContext == null) { + projContext = context.createProjectionContext(null); + projContext.setOid(missingShadowOid); + } + + if (projContext.getResourceShadowDiscriminator() == null) { + projContext.setResourceShadowDiscriminator(new ResourceShadowDiscriminator(null, null, null, null, true)); + } else { + projContext.markTombstone(); + } + + projContext.setFullShadow(false); + projContext.setObjectCurrent(null); + + return projContext; + } + + /** + * Check reconcile flag in account sync context and set accountOld + * variable if it's not set (from provisioning), load resource (if not set already), etc. + */ + private void finishLoadOfProjectionContext(LensContext context, + LensProjectionContext projContext, Task task, OperationResult result) + throws ObjectNotFoundException, CommunicationException, SchemaException, ConfigurationException, + SecurityViolationException, ExpressionEvaluationException { + + if (projContext.getSynchronizationPolicyDecision() == SynchronizationPolicyDecision.BROKEN) { + return; + } + + // MID-2436 (volatile objects) - as a quick but effective hack, we set reconciliation:=TRUE for volatile accounts + ResourceObjectTypeDefinitionType objectDefinition = projContext.getResourceObjectTypeDefinitionType(); + if (objectDefinition != null && objectDefinition.getVolatility() == ResourceObjectVolatilityType.UNPREDICTABLE && !projContext.isDoReconciliation()) { + LOGGER.trace("Resource object volatility is UNPREDICTABLE => setting doReconciliation to TRUE for {}", projContext.getResourceShadowDiscriminator()); + projContext.setDoReconciliation(true); + } + + // Remember OID before the object could be wiped + String projectionObjectOid = projContext.getOid(); + if (projContext.isDoReconciliation() && !projContext.isFullShadow()) { + // The current object is useless here. So lets just wipe it so it will get loaded + projContext.setObjectCurrent(null); + } + + // Load current object + boolean tombstone = false; + PrismObject projectionObject = projContext.getObjectCurrent(); + if (projContext.getObjectCurrent() == null || needToReload(context, projContext)) { + if (projContext.isAdd()) { + // No need to load old object, there is none + projContext.setExists(false); + projContext.recompute(); + projectionObject = projContext.getObjectNew(); + } else { + if (projectionObjectOid == null) { + projContext.setExists(false); + if (projContext.getResourceShadowDiscriminator() == null || projContext.getResourceShadowDiscriminator().getResourceOid() == null) { + throw new SystemException( + "Projection "+projContext.getHumanReadableName()+" with null OID, no representation and no resource OID in account sync context "+projContext); + } + } else { + GetOperationOptions rootOptions = GetOperationOptions.createPointInTimeType(PointInTimeType.FUTURE); + if (projContext.isDoReconciliation()) { + rootOptions.setForceRefresh(true); + if (SchemaConstants.CHANGE_CHANNEL_DISCOVERY_URI.equals(context.getChannel())) { + // Avoid discovery loops + rootOptions.setDoNotDiscovery(true); + } + } else { + rootOptions.setNoFetch(true); + } + rootOptions.setAllowNotFound(true); + Collection> options = SelectorOptions.createCollection(rootOptions); + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("Loading shadow {} for projection {}, options={}", projectionObjectOid, projContext.getHumanReadableName(), options); + } + + try { + PrismObject objectOld = provisioningService.getObject( + projContext.getObjectTypeClass(), projectionObjectOid, options, task, result); + if (LOGGER.isTraceEnabled()) { + if (!GetOperationOptions.isNoFetch(rootOptions) && !GetOperationOptions.isRaw(rootOptions)) { + LOGGER.trace("Full shadow loaded for {}:\n{}", projContext.getHumanReadableName(), objectOld.debugDump(1)); + } + } + Validate.notNull(objectOld.getOid()); + if (InternalsConfig.consistencyChecks) { + String resourceOid = projContext.getResourceOid(); + if (resourceOid != null && !resourceOid.equals(objectOld.asObjectable().getResourceRef().getOid())) { + throw new IllegalStateException("Loaded shadow with wrong resourceRef. Loading shadow "+projectionObjectOid+", got "+ + objectOld.getOid()+", expected resourceRef "+resourceOid+", but was "+objectOld.asObjectable().getResourceRef().getOid()+ + " for context "+projContext.getHumanReadableName()); + } + } + projContext.setLoadedObject(objectOld); + if (projContext.isDoReconciliation()) { + projContext.determineFullShadowFlag(objectOld); + } else { + projContext.setFullShadow(false); + } + projectionObject = objectOld; + if (ShadowUtil.isExists(objectOld.asObjectable())) { + projContext.setExists(true); + } else { + projContext.setExists(false); + if (ShadowUtil.isDead(objectOld.asObjectable())) { + projContext.markTombstone(); + } + LOGGER.debug("Foud only dead {} for projection context {}.", objectOld, projContext.getHumanReadableName()); + tombstone = true; + } + + } catch (ObjectNotFoundException ex) { + LOGGER.debug("Could not find object with oid {} for projection context {}.", projectionObjectOid, projContext.getHumanReadableName()); + // This does not mean BROKEN. The projection was there, but it gone now. + // Consistency mechanism might have kicked in and fixed the shadow. + // What we really want here is a thombstone projection or a refreshed projection. + result.muteLastSubresultError(); + projContext.setShadowExistsInRepo(false); + refreshContextAfterShadowNotFound(context, projContext, options, task, result); + + } catch (CommunicationException | SchemaException | ConfigurationException | SecurityViolationException + | RuntimeException | Error e) { + + LOGGER.warn("Problem while getting object with oid {}. Projection context {} is marked as broken: {}: {}", + projectionObjectOid, projContext.getHumanReadableName(), e.getClass().getSimpleName(), e.getMessage()); + projContext.setSynchronizationPolicyDecision(SynchronizationPolicyDecision.BROKEN); + + ResourceType resourceType = projContext.getResource(); + if (resourceType == null) { + throw e; + } else { + ErrorSelectorType errorSelector = null; + if (resourceType.getConsistency() != null) { + errorSelector = resourceType.getConsistency().getConnectorErrorCriticality(); + } + if (errorSelector == null) { + if (e instanceof SchemaException) { + // Just continue evaluation. The error is recorded in the result. + // The consistency mechanism has (most likely) already done the best. + // We cannot do any better. + return; + } else { + throw e; + } + } else { + if (CriticalityType.FATAL.equals(ExceptionUtil.getCriticality(errorSelector, e, CriticalityType.FATAL))) { + throw e; + } else { + return; + } + } + } + } + + } + projContext.setFresh(true); + } + } else { + projectionObject = projContext.getObjectCurrent(); + if (projectionObjectOid != null) { + projContext.setExists(ShadowUtil.isExists(projectionObject.asObjectable())); + } + } + + + // Determine Resource + ResourceType resourceType = projContext.getResource(); + String resourceOid = null; + if (resourceType == null) { + if (projectionObject != null) { + ShadowType shadowType = projectionObject.asObjectable(); + resourceOid = ShadowUtil.getResourceOid(shadowType); + } else if (projContext.getResourceShadowDiscriminator() != null) { + resourceOid = projContext.getResourceShadowDiscriminator().getResourceOid(); + } else if (!tombstone) { + throw new IllegalStateException("No shadow, no discriminator and not tombstone? That won't do. Projection "+projContext.getHumanReadableName()); + } + } else { + resourceOid = resourceType.getOid(); + } + + // Determine discriminator + ResourceShadowDiscriminator discr = projContext.getResourceShadowDiscriminator(); + if (discr == null) { + if (projectionObject != null) { + ShadowType accountShadowType = projectionObject.asObjectable(); + String intent = ShadowUtil.getIntent(accountShadowType); + ShadowKindType kind = ShadowUtil.getKind(accountShadowType); + discr = new ResourceShadowDiscriminator(resourceOid, kind, intent, accountShadowType.getTag(), tombstone); + } else { + discr = new ResourceShadowDiscriminator(null, null, null, null, tombstone); + } + projContext.setResourceShadowDiscriminator(discr); + } else { + if (tombstone) { + // We do not want to reset tombstone flag if it was set before + projContext.markTombstone(); + } + } + + // Load resource + if (resourceType == null && resourceOid != null) { + resourceType = LensUtil.getResourceReadOnly(context, resourceOid, provisioningService, task, result); + projContext.setResource(resourceType); + } + + //Determine refined schema and password policies for account type + RefinedObjectClassDefinition structuralObjectClassDef = projContext.getStructuralObjectClassDefinition(); + if (structuralObjectClassDef != null) { + LOGGER.trace("Finishing loading of projection context: security policy"); + SecurityPolicyType projectionSecurityPolicy = securityHelper.locateProjectionSecurityPolicy(projContext.getStructuralObjectClassDefinition(), task, result); + LOGGER.trace("Located security policy for: {},\n {}", projContext, projectionSecurityPolicy); + projContext.setProjectionSecurityPolicy(projectionSecurityPolicy); + } else { + LOGGER.trace("No structural object class definition, skipping determining security policy"); + } + + //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); + } + } + } + + setPrimaryDeltaOldValue(projContext); + } + + private boolean needToReload(LensContext context, + LensProjectionContext projContext) { + ResourceShadowDiscriminator discr = projContext.getResourceShadowDiscriminator(); + if (discr == null) { + return false; + } + // This is kind of brutal. But effective. We are reloading all higher-order dependencies + // before they are processed. This makes sure we have fresh state when they are re-computed. + // Because higher-order dependencies may have more than one projection context and the + // changes applied to one of them are not automatically reflected on on other. therefore we need to reload. + if (discr.getOrder() == 0) { + return false; + } + int executionWave = context.getExecutionWave(); + int projCtxWave = projContext.getWave(); + if (executionWave == projCtxWave - 1) { + // Reload right before its execution wave + return true; + } + return false; + } + + private void fullCheckConsistence(LensContext context) { + context.checkConsistence(); + for (LensProjectionContext projectionContext: context.getProjectionContexts()) { + if (projectionContext.getSynchronizationPolicyDecision() == SynchronizationPolicyDecision.BROKEN) { + continue; + } + if (projectionContext.getResourceShadowDiscriminator() == null) { + throw new IllegalStateException("No discriminator in "+projectionContext); + } + } + } + + public void loadFullShadow(LensContext context, LensProjectionContext projCtx, String reason, Task task, OperationResult parentResult) + throws ObjectNotFoundException, CommunicationException, SchemaException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { + if (projCtx.isFullShadow()) { + // already loaded + return; + } + if (projCtx.isAdd() && projCtx.getOid() == null) { + // nothing to load yet + return; + } + if (projCtx.isTombstone()) { + // loading is futile + return; + } + OperationResult result = parentResult.subresult(CLASS_DOT + "loadFullShadow") + .setMinor() + .build(); + FullShadowLoadedTraceType trace; + if (result.isTraced()) { + trace = new FullShadowLoadedTraceType(prismContext); + if (result.isTracingNormal(FullShadowLoadedTraceType.class)) { + trace.setInputLensContextText(context.debugDump()); + } + trace.setInputLensContext(context.toLensContextType(getExportType(trace, result))); + result.addTrace(trace); + } else { + trace = null; + } + try { + ResourceShadowDiscriminator discr = projCtx.getResourceShadowDiscriminator(); + if (discr != null && discr.getOrder() > 0) { + // It may be just too early to load the projection + if (LensUtil.hasLowerOrderContext(context, projCtx) && (context.getExecutionWave() < projCtx.getWave())) { + // We cannot reliably load the context now + result.addReturn(DEFAULT, "too early"); + return; + } + } + + GetOperationOptions getOptions = GetOperationOptions.createAllowNotFound(); + getOptions.setPointInTimeType(PointInTimeType.FUTURE); + if (projCtx.isDoReconciliation()) { + getOptions.setForceRefresh(true); + } + if (SchemaConstants.CHANGE_CHANNEL_DISCOVERY_URI.equals(context.getChannel())) { + LOGGER.trace("Loading full resource object {} from provisioning - with doNotDiscover to avoid loops; reason: {}", + projCtx, reason); + // Avoid discovery loops + getOptions.setDoNotDiscovery(true); + } else { + LOGGER.trace("Loading full resource object {} from provisioning (discovery enabled), reason: {}, channel: {}", + projCtx, reason, context.getChannel()); + } + Collection> options = SelectorOptions.createCollection(getOptions); + applyAttributesToGet(projCtx, options); + try { + PrismObject objectCurrent = provisioningService + .getObject(ShadowType.class, projCtx.getOid(), options, task, result); + Validate.notNull(objectCurrent.getOid()); + // TODO: use setLoadedObject() instead? + projCtx.setObjectCurrent(objectCurrent); + projCtx.determineFullShadowFlag(objectCurrent); + if (ShadowUtil.isExists(objectCurrent.asObjectable())) { + result.addReturn(DEFAULT, "found"); + } else { + LOGGER.debug("Load of full resource object {} ended with non-existent shadow (options={})", projCtx, + getOptions); + projCtx.setExists(false); + refreshContextAfterShadowNotFound(context, projCtx, options, task, result); + result.addReturn(DEFAULT, "not found"); + } + + } catch (ObjectNotFoundException ex) { + LOGGER.debug("Load of full resource object {} ended with ObjectNotFoundException (options={})", projCtx, + getOptions); + result.muteLastSubresultError(); + projCtx.setShadowExistsInRepo(false); + refreshContextAfterShadowNotFound(context, projCtx, options, task, result); + result.addReturn(DEFAULT, "not found"); + } + + projCtx.recompute(); + + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("Loaded full resource object:\n{}", projCtx.debugDump(1)); + } + } catch (Throwable t) { + result.recordFatalError(t); + throw t; + } finally { + if (trace != null) { + if (result.isTracingNormal(FullShadowLoadedTraceType.class)) { + trace.setOutputLensContextText(context.debugDump()); + } + trace.setOutputLensContext(context.toLensContextType(getExportType(trace, result))); + } + result.computeStatusIfUnknown(); + } + } + + public void refreshContextAfterShadowNotFound(LensContext context, LensProjectionContext projCtx, Collection> options, Task task, OperationResult result) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException { + if (projCtx.isDelete()){ + //this is OK, shadow was deleted, but we will continue in processing with old shadow..and set it as full so prevent from other full loading + projCtx.setFullShadow(true); + return; + } + + boolean compensated = false; + if (!GetOperationOptions.isDoNotDiscovery(SelectorOptions.findRootOptions(options))) { + // The account might have been re-created by the discovery. + // Reload focus, try to find out if there is a new matching link (and the old is gone) + LensFocusContext focusContext = context.getFocusContext(); + if (focusContext != null) { + Class focusClass = focusContext.getObjectTypeClass(); + if (FocusType.class.isAssignableFrom(focusClass)) { + LOGGER.trace("Reloading focus to check for new links"); + PrismObject focusCurrent; + try { + focusCurrent = cacheRepositoryService.getObject(focusContext.getObjectTypeClass(), focusContext.getOid(), null, result); + } catch (ObjectNotFoundException e) { + if (focusContext.isDelete()) { + // This may be OK. This may be later wave and the focus may be already deleted. + // Therefore let's just keep what we have. We have no way how to refresh context + // in that situation. + result.muteLastSubresultError(); + LOGGER.trace("ObjectNotFound error is not compensated (focus already deleted), setting context to tombstone"); + projCtx.markTombstone(); + return; + } else { + throw e; + } + } + FocusType focusType = (FocusType) focusCurrent.asObjectable(); + for (ObjectReferenceType linkRef: focusType.getLinkRef()) { + if (linkRef.getOid().equals(projCtx.getOid())) { + // The deleted shadow is still in the linkRef. This should not happen, but it obviously happens sometimes. + // Maybe some strange race condition? Anyway, we want a robust behavior and this linkRef should NOT be there. + // So simple remove it. + LOGGER.warn("The OID "+projCtx.getOid()+" of deleted shadow still exists in the linkRef after discovery ("+focusCurrent+"), removing it"); + ReferenceDelta unlinkDelta = prismContext.deltaFactory().reference().createModificationDelete( + FocusType.F_LINK_REF, focusContext.getObjectDefinition(), linkRef.asReferenceValue().clone()); + focusContext.swallowToSecondaryDelta(unlinkDelta); + continue; + } + boolean found = false; + for (LensProjectionContext pCtx: context.getProjectionContexts()) { + if (linkRef.getOid().equals(pCtx.getOid())) { + found = true; + break; + } + } + if (!found) { + // This link is new, it is not in the existing lens context + PrismObject newLinkRepoShadow = cacheRepositoryService.getObject(ShadowType.class, linkRef.getOid(), null, result); + if (ShadowUtil.matches(newLinkRepoShadow, projCtx.getResourceShadowDiscriminator())) { + LOGGER.trace("Found new matching link: {}, updating projection context", newLinkRepoShadow); + LOGGER.trace("Applying definition from provisioning first."); // MID-3317 + provisioningService.applyDefinition(newLinkRepoShadow, task, result); + projCtx.setObjectCurrent(newLinkRepoShadow); + projCtx.setOid(newLinkRepoShadow.getOid()); + projCtx.recompute(); + compensated = true; + break; + } else { + LOGGER.trace("Found new link: {}, but skipping it because it does not match the projection context", newLinkRepoShadow); + } + } + } + } + } + + } + + if (!compensated) { + LOGGER.trace("ObjectNotFound error is not compensated, setting context to tombstone"); + projCtx.markTombstone(); + } + } + + private void applyAttributesToGet(LensProjectionContext projCtx, Collection> options) throws SchemaException { + if ( !LensUtil.isPasswordReturnedByDefault(projCtx) + && LensUtil.needsFullShadowForCredentialProcessing(projCtx)) { + options.add(SelectorOptions.create(prismContext.toUniformPath(SchemaConstants.PATH_PASSWORD_VALUE), GetOperationOptions.createRetrieve())); + } + } + + public void reloadSecurityPolicyIfNeeded(@NotNull LensContext context, + @NotNull LensFocusContext focusContext, Task task, OperationResult result) + throws ExpressionEvaluationException, SchemaException, + CommunicationException, ConfigurationException, SecurityViolationException { + if (focusContext.hasOrganizationalChange()) { + loadSecurityPolicy(context, true, task, result); + } + } + + private void loadSecurityPolicy(LensContext context, + Task task, OperationResult result) throws ExpressionEvaluationException, + SchemaException, CommunicationException, ConfigurationException, SecurityViolationException { + loadSecurityPolicy(context, false, task, result); + } + + @SuppressWarnings("unchecked") + private void loadSecurityPolicy(LensContext context, boolean forceReload, + Task task, OperationResult result) throws ExpressionEvaluationException, + SchemaException, CommunicationException, ConfigurationException, SecurityViolationException { + LensFocusContext genericFocusContext = context.getFocusContext(); + if (genericFocusContext == null || !genericFocusContext.represents(FocusType.class)) { + LOGGER.trace("Skipping load of security policy because focus is not of FocusType"); + return; + } + LensFocusContext focusContext = (LensFocusContext) genericFocusContext; + PrismObject focus = focusContext.getObjectAny(); + SecurityPolicyType globalSecurityPolicy = determineAndSetGlobalSecurityPolicy(context, focus, task, result); + SecurityPolicyType focusSecurityPolicy = determineAndSetFocusSecurityPolicy(focusContext, focus, globalSecurityPolicy, + forceReload, task, result); + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("Security policy:\n Global:\n{}\n Focus:\n{}", + globalSecurityPolicy.asPrismObject().debugDump(2), + focusSecurityPolicy==null?null:focusSecurityPolicy.asPrismObject().debugDump(2)); + } else { + LOGGER.debug("Security policy: global: {}, focus: {}", globalSecurityPolicy, focusSecurityPolicy); + } + } + + @NotNull + private SecurityPolicyType determineAndSetGlobalSecurityPolicy(LensContext context, + PrismObject focus, Task task, OperationResult result) + throws CommunicationException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { + SecurityPolicyType existingPolicy = context.getGlobalSecurityPolicy(); + if (existingPolicy != null) { + return existingPolicy; + } else { + SecurityPolicyType loadedPolicy = securityHelper.locateGlobalSecurityPolicy(focus, context.getSystemConfiguration(), + task, result); + SecurityPolicyType resultingPolicy; + if (loadedPolicy != null) { + resultingPolicy = loadedPolicy; + } else { + // use empty policy to avoid repeated lookups + resultingPolicy = new SecurityPolicyType(); + } + context.setGlobalSecurityPolicy(resultingPolicy); + return resultingPolicy; + } + } + + private SecurityPolicyType determineAndSetFocusSecurityPolicy(LensFocusContext focusContext, + PrismObject focus, SecurityPolicyType globalSecurityPolicy, boolean forceReload, Task task, + OperationResult result) throws SchemaException { + SecurityPolicyType existingPolicy = focusContext.getSecurityPolicy(); + if (existingPolicy != null && !forceReload) { + return existingPolicy; + } else { + SecurityPolicyType loadedPolicy = securityHelper.locateFocusSecurityPolicy(focus, task, result); + SecurityPolicyType resultingPolicy; + if (loadedPolicy != null) { + resultingPolicy = loadedPolicy; + } else { + // Not very clean. In fact we should store focus security policy separate from global + // policy to avoid confusion. But need to do this to fix MID-4793 and backport the fix. + // Therefore avoiding big changes. TODO: fix properly later + resultingPolicy = globalSecurityPolicy; + } + focusContext.setSecurityPolicy(resultingPolicy); + return resultingPolicy; + } + } +} diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/security/SecurityHelper.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/security/SecurityHelper.java index c3a74c777e6..b9e4979d658 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/security/SecurityHelper.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/security/SecurityHelper.java @@ -1,317 +1,354 @@ -/* - * Copyright (c) 2015-2019 Evolveum and contributors - * - * This work is dual-licensed under the Apache License 2.0 - * and European Union Public License. See LICENSE file for details. - */ -package com.evolveum.midpoint.model.impl.security; - -import javax.xml.datatype.Duration; -import javax.xml.soap.SOAPMessage; - -import com.evolveum.midpoint.model.api.ModelAuditRecorder; -import com.evolveum.midpoint.model.impl.util.AuditHelper; -import com.evolveum.midpoint.security.api.HttpConnectionInformation; -import com.evolveum.midpoint.security.enforcer.api.SecurityEnforcer; - -import org.apache.cxf.binding.soap.SoapMessage; -import org.apache.cxf.binding.soap.saaj.SAAJInInterceptor; -import org.apache.wss4j.common.ext.WSSecurityException; -import org.apache.wss4j.dom.util.WSSecurityUtil; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -import com.evolveum.midpoint.audit.api.AuditEventRecord; -import com.evolveum.midpoint.audit.api.AuditEventStage; -import com.evolveum.midpoint.audit.api.AuditEventType; -import com.evolveum.midpoint.model.impl.ModelObjectResolver; -import com.evolveum.midpoint.prism.PrismObject; -import com.evolveum.midpoint.prism.xml.XmlTypeConverter; -import com.evolveum.midpoint.schema.result.OperationResult; -import com.evolveum.midpoint.schema.result.OperationResultStatus; -import com.evolveum.midpoint.security.api.ConnectionEnvironment; -import com.evolveum.midpoint.task.api.Task; -import com.evolveum.midpoint.task.api.TaskManager; -import com.evolveum.midpoint.util.exception.CommunicationException; -import com.evolveum.midpoint.util.exception.ConfigurationException; -import com.evolveum.midpoint.util.exception.ExpressionEvaluationException; -import com.evolveum.midpoint.util.exception.ObjectNotFoundException; -import com.evolveum.midpoint.util.exception.SchemaException; -import com.evolveum.midpoint.util.exception.SecurityViolationException; -import com.evolveum.midpoint.util.logging.Trace; -import com.evolveum.midpoint.util.logging.TraceManager; -import com.evolveum.midpoint.xml.ns._public.common.common_3.CredentialPolicyType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.CredentialsPolicyType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.FocusType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.NodeType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.NonceCredentialsPolicyType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.PasswordCredentialsPolicyType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.SecurityPolicyType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.SecurityQuestionsCredentialsPolicyType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.SystemConfigurationType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ValuePolicyType; - -/** - * @author semancik - */ -@Component -public class SecurityHelper implements ModelAuditRecorder { - - private static final Trace LOGGER = TraceManager.getTrace(SecurityHelper.class); - - public static final String CONTEXTUAL_PROPERTY_AUDITED_NAME = SecurityHelper.class.getName() + ".audited"; - - @Autowired private TaskManager taskManager; - @Autowired private AuditHelper auditHelper; - @Autowired private ModelObjectResolver objectResolver; - @Autowired private SecurityEnforcer securityEnforcer; - - @Override - public void auditLoginSuccess(@NotNull FocusType user, @NotNull ConnectionEnvironment connEnv) { - auditLogin(user.getName().getOrig(), user, connEnv, OperationResultStatus.SUCCESS, null); - } - - public void auditLoginSuccess(@NotNull NodeType node, @NotNull ConnectionEnvironment connEnv) { - auditLogin(node.getName().getOrig(), null, connEnv, OperationResultStatus.SUCCESS, null); - } - - @Override - public void auditLoginFailure(@Nullable String username, @Nullable FocusType focus, @NotNull ConnectionEnvironment connEnv, String message) { - auditLogin(username, focus, connEnv, OperationResultStatus.FATAL_ERROR, message); - } - - private void auditLogin(@Nullable String username, @Nullable FocusType focus, @NotNull ConnectionEnvironment connEnv, @NotNull OperationResultStatus status, - @Nullable String message) { - Task task = taskManager.createTaskInstance(); - task.setChannel(connEnv.getChannel()); - - LOGGER.debug("Login {} username={}, channel={}: {}", - status == OperationResultStatus.SUCCESS ? "success" : "failure", username, - connEnv.getChannel(), message); - - AuditEventRecord record = new AuditEventRecord(AuditEventType.CREATE_SESSION, AuditEventStage.REQUEST); - record.setParameter(username); - if (focus != null ) { - record.setInitiator(focus.asPrismObject()); - } - record.setTimestamp(System.currentTimeMillis()); - record.setOutcome(status); - record.setMessage(message); - storeConnectionEnvironment(record, connEnv); - - auditHelper.audit(record, null, task, new OperationResult(SecurityHelper.class.getName() + ".auditLogin")); - } - - @Override - public void auditLogout(ConnectionEnvironment connEnv, Task task) { - AuditEventRecord record = new AuditEventRecord(AuditEventType.TERMINATE_SESSION, AuditEventStage.REQUEST); - record.setInitiatorAndLoginParameter(task.getOwner()); - record.setTimestamp(System.currentTimeMillis()); - record.setOutcome(OperationResultStatus.SUCCESS); - storeConnectionEnvironment(record, connEnv); - auditHelper.audit(record, null, task, new OperationResult(SecurityHelper.class.getName() + ".auditLogout")); - } - - private void storeConnectionEnvironment(AuditEventRecord record, ConnectionEnvironment connEnv) { - record.setChannel(connEnv.getChannel()); - record.setSessionIdentifier(connEnv.getSessionId()); - HttpConnectionInformation connInfo = connEnv.getConnectionInformation(); - if (connInfo != null) { - record.setRemoteHostAddress(connInfo.getRemoteHostAddress()); - record.setHostIdentifier(connInfo.getLocalHostName()); - } - } - - public String getUsernameFromMessage(SOAPMessage saajSoapMessage) throws WSSecurityException { - if (saajSoapMessage == null) { - return null; - } - Element securityHeader = WSSecurityUtil.getSecurityHeader(saajSoapMessage.getSOAPPart(), ""); - return getUsernameFromSecurityHeader(securityHeader); - } - - private String getUsernameFromSecurityHeader(Element securityHeader) { - if (securityHeader == null) { - return null; - } - - String username = ""; - NodeList list = securityHeader.getChildNodes(); - int len = list.getLength(); - Node elem; - for (int i = 0; i < len; i++) { - elem = list.item(i); - if (elem.getNodeType() != Node.ELEMENT_NODE) { - continue; - } - if ("UsernameToken".equals(elem.getLocalName())) { - NodeList nodes = elem.getChildNodes(); - int len2 = nodes.getLength(); - for (int j = 0; j < len2; j++) { - Node elem2 = nodes.item(j); - if ("Username".equals(elem2.getLocalName())) { - username = elem2.getTextContent(); - } - } - } - } - return username; - } - - public SOAPMessage getSOAPMessage(SoapMessage msg) { - SAAJInInterceptor.INSTANCE.handleMessage(msg); - return msg.getContent(SOAPMessage.class); - } - - /** - * Returns security policy applicable for the specified user. It looks for organization and global policies and takes into account - * deprecated properties and password policy references. The resulting security policy has all the (non-deprecated) properties set. - * If there is also referenced value policy, it is will be stored as "object" in the value policy reference inside the - * returned security policy. - */ - public SecurityPolicyType locateSecurityPolicy(PrismObject focus, PrismObject systemConfiguration, - Task task, OperationResult result) throws SchemaException, CommunicationException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { - - SecurityPolicyType focusSecurityPolicy = locateFocusSecurityPolicy(focus, task, result); - if (focusSecurityPolicy != null) { - traceSecurityPolicy(focusSecurityPolicy, focus); - return focusSecurityPolicy; - } - - SecurityPolicyType globalSecurityPolicy = locateGlobalSecurityPolicy(focus, systemConfiguration, task, result); - if (globalSecurityPolicy != null) { - traceSecurityPolicy(globalSecurityPolicy, focus); - return globalSecurityPolicy; - } - - return null; - } - - public SecurityPolicyType locateFocusSecurityPolicy(PrismObject focus, Task task, - OperationResult result) throws SchemaException { - PrismObject orgSecurityPolicy = objectResolver.searchOrgTreeWidthFirstReference(focus, - o -> o.asObjectable().getSecurityPolicyRef(), "security policy", task, result); - LOGGER.trace("Found organization security policy: {}", orgSecurityPolicy); - if (orgSecurityPolicy != null) { - SecurityPolicyType orgSecurityPolicyType = orgSecurityPolicy.asObjectable(); - postProcessSecurityPolicy(orgSecurityPolicyType, task, result); - return orgSecurityPolicyType; - } else { - return null; - } - } - - public SecurityPolicyType locateGlobalSecurityPolicy(PrismObject focus, - PrismObject systemConfiguration, Task task, OperationResult result) - throws CommunicationException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { - if (systemConfiguration != null) { - return resolveGlobalSecurityPolicy(focus, systemConfiguration.asObjectable(), task, result); - } else { - return null; - } - } - - private SecurityPolicyType resolveGlobalSecurityPolicy(PrismObject focus, - SystemConfigurationType systemConfiguration, Task task, OperationResult result) - throws CommunicationException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { - ObjectReferenceType globalSecurityPolicyRef = systemConfiguration.getGlobalSecurityPolicyRef(); - if (globalSecurityPolicyRef != null) { - try { - SecurityPolicyType globalSecurityPolicyType = objectResolver.resolve(globalSecurityPolicyRef, SecurityPolicyType.class, null, "global security policy reference in system configuration", task, result); - LOGGER.trace("Using global security policy: {}", globalSecurityPolicyType); - postProcessSecurityPolicy(globalSecurityPolicyType, task, result); - traceSecurityPolicy(globalSecurityPolicyType, focus); - return globalSecurityPolicyType; - } catch (ObjectNotFoundException | SchemaException e) { - LOGGER.error(e.getMessage(), e); - traceSecurityPolicy(null, focus); - return null; - } - } - - return null; - } - - private void traceSecurityPolicy(SecurityPolicyType securityPolicyType, PrismObject user) { - if (LOGGER.isTraceEnabled()) { - if (user != null) { - if (securityPolicyType == null) { - LOGGER.trace("Located security policy for {}: null", user); - } else { - LOGGER.trace("Located security policy for {}:\n{}", user, securityPolicyType.asPrismObject().debugDump(1)); - } - } else { - if (securityPolicyType == null) { - LOGGER.trace("Located global security policy null"); - } else { - LOGGER.trace("Located global security policy :\n{}", securityPolicyType.asPrismObject().debugDump(1)); - } - } - } - - } - - private void postProcessSecurityPolicy(SecurityPolicyType securityPolicyType, Task task, OperationResult result) { - CredentialsPolicyType creds = securityPolicyType.getCredentials(); - if (creds != null) { - PasswordCredentialsPolicyType passwd = creds.getPassword(); - if (passwd != null) { - postProcessPasswordCredentialPolicy(securityPolicyType, passwd, task, result); - } - for (NonceCredentialsPolicyType nonce: creds.getNonce()) { - postProcessCredentialPolicy(securityPolicyType, nonce, "nonce credential policy", task, result); - } - SecurityQuestionsCredentialsPolicyType securityQuestions = creds.getSecurityQuestions(); - if (securityQuestions != null) { - postProcessCredentialPolicy(securityPolicyType, securityQuestions, "security questions credential policy", task, result); - } - } - } - - private void postProcessPasswordCredentialPolicy(SecurityPolicyType securityPolicyType, PasswordCredentialsPolicyType passwd, Task task, OperationResult result) { - postProcessCredentialPolicy(securityPolicyType, passwd, "password credential policy", task, result); - } - - private ValuePolicyType postProcessCredentialPolicy(SecurityPolicyType securityPolicyType, CredentialPolicyType credPolicy, String credShortDesc, Task task, OperationResult result) { - ObjectReferenceType valuePolicyRef = credPolicy.getValuePolicyRef(); - if (valuePolicyRef == null) { - return null; - } - ValuePolicyType valuePolicyType; - try { - valuePolicyType = objectResolver.resolve(valuePolicyRef, ValuePolicyType.class, null, credShortDesc + " in " + securityPolicyType, task, result); - } catch (ObjectNotFoundException | SchemaException | CommunicationException | ConfigurationException | SecurityViolationException | ExpressionEvaluationException e) { - LOGGER.warn("{} {} referenced from {} was not found", credShortDesc, valuePolicyRef.getOid(), securityPolicyType); - return null; - } - valuePolicyRef.asReferenceValue().setObject(valuePolicyType.asPrismObject()); - return valuePolicyType; - } - - private SecurityPolicyType postProcessPasswordPolicy(ValuePolicyType passwordPolicyType) { - SecurityPolicyType securityPolicyType = new SecurityPolicyType(); - CredentialsPolicyType creds = new CredentialsPolicyType(); - PasswordCredentialsPolicyType passwd = new PasswordCredentialsPolicyType(); - ObjectReferenceType passwordPolicyRef = new ObjectReferenceType(); - passwordPolicyRef.asReferenceValue().setObject(passwordPolicyType.asPrismObject()); - passwd.setValuePolicyRef(passwordPolicyRef); - creds.setPassword(passwd); - securityPolicyType.setCredentials(creds); - return securityPolicyType; - } - - private Duration daysToDuration(int days) { - return XmlTypeConverter.createDuration((long) days * 1000 * 60 * 60 * 24); - } - - public SecurityEnforcer getSecurityEnforcer() { - return securityEnforcer; - } -} +/* + * Copyright (c) 2015-2019 Evolveum and contributors + * + * This work is dual-licensed under the Apache License 2.0 + * and European Union Public License. See LICENSE file for details. + */ +package com.evolveum.midpoint.model.impl.security; + +import javax.xml.datatype.Duration; +import javax.xml.soap.SOAPMessage; + +import com.evolveum.midpoint.common.refinery.RefinedObjectClassDefinition; +import com.evolveum.midpoint.model.api.ModelAuditRecorder; +import com.evolveum.midpoint.model.impl.lens.LensContext; +import com.evolveum.midpoint.model.impl.lens.LensProjectionContext; +import com.evolveum.midpoint.model.impl.util.AuditHelper; +import com.evolveum.midpoint.prism.PrismContext; +import com.evolveum.midpoint.security.api.HttpConnectionInformation; +import com.evolveum.midpoint.security.enforcer.api.SecurityEnforcer; + +import com.evolveum.midpoint.xml.ns._public.common.common_3.*; + +import org.apache.cxf.binding.soap.SoapMessage; +import org.apache.cxf.binding.soap.saaj.SAAJInInterceptor; +import org.apache.wss4j.common.ext.WSSecurityException; +import org.apache.wss4j.dom.util.WSSecurityUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import com.evolveum.midpoint.audit.api.AuditEventRecord; +import com.evolveum.midpoint.audit.api.AuditEventStage; +import com.evolveum.midpoint.audit.api.AuditEventType; +import com.evolveum.midpoint.model.impl.ModelObjectResolver; +import com.evolveum.midpoint.prism.PrismObject; +import com.evolveum.midpoint.prism.xml.XmlTypeConverter; +import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.schema.result.OperationResultStatus; +import com.evolveum.midpoint.security.api.ConnectionEnvironment; +import com.evolveum.midpoint.task.api.Task; +import com.evolveum.midpoint.task.api.TaskManager; +import com.evolveum.midpoint.util.exception.CommunicationException; +import com.evolveum.midpoint.util.exception.ConfigurationException; +import com.evolveum.midpoint.util.exception.ExpressionEvaluationException; +import com.evolveum.midpoint.util.exception.ObjectNotFoundException; +import com.evolveum.midpoint.util.exception.SchemaException; +import com.evolveum.midpoint.util.exception.SecurityViolationException; +import com.evolveum.midpoint.util.logging.Trace; +import com.evolveum.midpoint.util.logging.TraceManager; + +/** + * @author semancik + */ +@Component +public class SecurityHelper implements ModelAuditRecorder { + + private static final Trace LOGGER = TraceManager.getTrace(SecurityHelper.class); + + public static final String CONTEXTUAL_PROPERTY_AUDITED_NAME = SecurityHelper.class.getName() + ".audited"; + + @Autowired private TaskManager taskManager; + @Autowired private AuditHelper auditHelper; + @Autowired private ModelObjectResolver objectResolver; + @Autowired private SecurityEnforcer securityEnforcer; + @Autowired private PrismContext prismContext; + + @Override + public void auditLoginSuccess(@NotNull FocusType user, @NotNull ConnectionEnvironment connEnv) { + auditLogin(user.getName().getOrig(), user, connEnv, OperationResultStatus.SUCCESS, null); + } + + public void auditLoginSuccess(@NotNull NodeType node, @NotNull ConnectionEnvironment connEnv) { + auditLogin(node.getName().getOrig(), null, connEnv, OperationResultStatus.SUCCESS, null); + } + + @Override + public void auditLoginFailure(@Nullable String username, @Nullable FocusType focus, @NotNull ConnectionEnvironment connEnv, String message) { + auditLogin(username, focus, connEnv, OperationResultStatus.FATAL_ERROR, message); + } + + private void auditLogin(@Nullable String username, @Nullable FocusType focus, @NotNull ConnectionEnvironment connEnv, @NotNull OperationResultStatus status, + @Nullable String message) { + Task task = taskManager.createTaskInstance(); + task.setChannel(connEnv.getChannel()); + + LOGGER.debug("Login {} username={}, channel={}: {}", + status == OperationResultStatus.SUCCESS ? "success" : "failure", username, + connEnv.getChannel(), message); + + AuditEventRecord record = new AuditEventRecord(AuditEventType.CREATE_SESSION, AuditEventStage.REQUEST); + record.setParameter(username); + if (focus != null ) { + record.setInitiator(focus.asPrismObject()); + } + record.setTimestamp(System.currentTimeMillis()); + record.setOutcome(status); + record.setMessage(message); + storeConnectionEnvironment(record, connEnv); + + auditHelper.audit(record, null, task, new OperationResult(SecurityHelper.class.getName() + ".auditLogin")); + } + + @Override + public void auditLogout(ConnectionEnvironment connEnv, Task task) { + AuditEventRecord record = new AuditEventRecord(AuditEventType.TERMINATE_SESSION, AuditEventStage.REQUEST); + record.setInitiatorAndLoginParameter(task.getOwner()); + record.setTimestamp(System.currentTimeMillis()); + record.setOutcome(OperationResultStatus.SUCCESS); + storeConnectionEnvironment(record, connEnv); + auditHelper.audit(record, null, task, new OperationResult(SecurityHelper.class.getName() + ".auditLogout")); + } + + private void storeConnectionEnvironment(AuditEventRecord record, ConnectionEnvironment connEnv) { + record.setChannel(connEnv.getChannel()); + record.setSessionIdentifier(connEnv.getSessionId()); + HttpConnectionInformation connInfo = connEnv.getConnectionInformation(); + if (connInfo != null) { + record.setRemoteHostAddress(connInfo.getRemoteHostAddress()); + record.setHostIdentifier(connInfo.getLocalHostName()); + } + } + + public String getUsernameFromMessage(SOAPMessage saajSoapMessage) throws WSSecurityException { + if (saajSoapMessage == null) { + return null; + } + Element securityHeader = WSSecurityUtil.getSecurityHeader(saajSoapMessage.getSOAPPart(), ""); + return getUsernameFromSecurityHeader(securityHeader); + } + + private String getUsernameFromSecurityHeader(Element securityHeader) { + if (securityHeader == null) { + return null; + } + + String username = ""; + NodeList list = securityHeader.getChildNodes(); + int len = list.getLength(); + Node elem; + for (int i = 0; i < len; i++) { + elem = list.item(i); + if (elem.getNodeType() != Node.ELEMENT_NODE) { + continue; + } + if ("UsernameToken".equals(elem.getLocalName())) { + NodeList nodes = elem.getChildNodes(); + int len2 = nodes.getLength(); + for (int j = 0; j < len2; j++) { + Node elem2 = nodes.item(j); + if ("Username".equals(elem2.getLocalName())) { + username = elem2.getTextContent(); + } + } + } + } + return username; + } + + public SOAPMessage getSOAPMessage(SoapMessage msg) { + SAAJInInterceptor.INSTANCE.handleMessage(msg); + return msg.getContent(SOAPMessage.class); + } + + /** + * Returns security policy applicable for the specified user. It looks for organization and global policies and takes into account + * deprecated properties and password policy references. The resulting security policy has all the (non-deprecated) properties set. + * If there is also referenced value policy, it is will be stored as "object" in the value policy reference inside the + * returned security policy. + */ + public SecurityPolicyType locateSecurityPolicy(PrismObject focus, PrismObject systemConfiguration, + Task task, OperationResult result) throws SchemaException, CommunicationException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { + + SecurityPolicyType focusSecurityPolicy = locateFocusSecurityPolicy(focus, task, result); + if (focusSecurityPolicy != null) { + traceSecurityPolicy(focusSecurityPolicy, focus); + return focusSecurityPolicy; + } + + SecurityPolicyType globalSecurityPolicy = locateGlobalSecurityPolicy(focus, systemConfiguration, task, result); + if (globalSecurityPolicy != null) { + traceSecurityPolicy(globalSecurityPolicy, focus); + return globalSecurityPolicy; + } + + return null; + } + + public SecurityPolicyType locateFocusSecurityPolicy(PrismObject focus, Task task, + OperationResult result) throws SchemaException { + PrismObject orgSecurityPolicy = objectResolver.searchOrgTreeWidthFirstReference(focus, + o -> o.asObjectable().getSecurityPolicyRef(), "security policy", task, result); + LOGGER.trace("Found organization security policy: {}", orgSecurityPolicy); + if (orgSecurityPolicy != null) { + SecurityPolicyType orgSecurityPolicyType = orgSecurityPolicy.asObjectable(); + postProcessSecurityPolicy(orgSecurityPolicyType, task, result); + return orgSecurityPolicyType; + } else { + return null; + } + } + + public SecurityPolicyType locateGlobalSecurityPolicy(PrismObject focus, + PrismObject systemConfiguration, Task task, OperationResult result) + throws CommunicationException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { + if (systemConfiguration != null) { + return resolveGlobalSecurityPolicy(focus, systemConfiguration.asObjectable(), task, result); + } else { + return null; + } + } + + public SecurityPolicyType locateProjectionSecurityPolicy(RefinedObjectClassDefinition structuralObjectClassDefinition, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, SecurityViolationException, CommunicationException, ConfigurationException, ExpressionEvaluationException { + LOGGER.trace("Finishing loading of projection context: security policy"); + ObjectReferenceType securityPolicyRef = structuralObjectClassDefinition.getSecurityPolicyRef(); + if (securityPolicyRef == null || securityPolicyRef.getOid() == null) { + LOGGER.trace("Security policy not defined for the projection context."); + return loadProjectionLegacyPasswordPolicy(structuralObjectClassDefinition, task, result); + } + LOGGER.trace("Loading security policy {} from: {}", securityPolicyRef, structuralObjectClassDefinition); + SecurityPolicyType securityPolicy = objectResolver.resolve(securityPolicyRef, SecurityPolicyType.class, null, " projection security policy", task, result); + if (securityPolicy == null) { + LOGGER.debug("Security policy {} defined for the projection does not exist", securityPolicyRef); + return null; + } + postProcessSecurityPolicy(securityPolicy, task, result); + return securityPolicy; + } + + + private SecurityPolicyType loadProjectionLegacyPasswordPolicy(RefinedObjectClassDefinition structuralObjectClassDefinition, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, SecurityViolationException, CommunicationException, ConfigurationException, ExpressionEvaluationException { + ObjectReferenceType passwordPolicyRef = structuralObjectClassDefinition.getPasswordPolicy(); + if (passwordPolicyRef == null || passwordPolicyRef.getOid() == null) { + LOGGER.trace("Legacy password policy not defined for the projection context."); + return null; + } + LOGGER.trace("Loading legacy password policy {} from: {}", passwordPolicyRef, structuralObjectClassDefinition); + ValuePolicyType passwordPolicy = objectResolver.resolve(passwordPolicyRef, + ValuePolicyType.class, null, " projection legacy password policy ", task, result); + if (passwordPolicy == null) { + LOGGER.debug("Legacy password policy {} defined for the projection does not exist", passwordPolicyRef); + return null; + } + ObjectReferenceType dummyPasswordPolicyRef = new ObjectReferenceType(); + dummyPasswordPolicyRef.asReferenceValue().setObject(passwordPolicy.asPrismObject()); + PrismObject securityPolicy = prismContext.createObject(SecurityPolicyType.class); + securityPolicy.asObjectable() + .beginCredentials() + .beginPassword() + .valuePolicyRef(dummyPasswordPolicyRef); + return securityPolicy.asObjectable(); + } + + + private SecurityPolicyType resolveGlobalSecurityPolicy(PrismObject focus, + SystemConfigurationType systemConfiguration, Task task, OperationResult result) + throws CommunicationException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { + ObjectReferenceType globalSecurityPolicyRef = systemConfiguration.getGlobalSecurityPolicyRef(); + if (globalSecurityPolicyRef != null) { + try { + SecurityPolicyType globalSecurityPolicyType = objectResolver.resolve(globalSecurityPolicyRef, SecurityPolicyType.class, null, "global security policy reference in system configuration", task, result); + LOGGER.trace("Using global security policy: {}", globalSecurityPolicyType); + postProcessSecurityPolicy(globalSecurityPolicyType, task, result); + traceSecurityPolicy(globalSecurityPolicyType, focus); + return globalSecurityPolicyType; + } catch (ObjectNotFoundException | SchemaException e) { + LOGGER.error(e.getMessage(), e); + traceSecurityPolicy(null, focus); + return null; + } + } + + return null; + } + + private void traceSecurityPolicy(SecurityPolicyType securityPolicyType, PrismObject user) { + if (LOGGER.isTraceEnabled()) { + if (user != null) { + if (securityPolicyType == null) { + LOGGER.trace("Located security policy for {}: null", user); + } else { + LOGGER.trace("Located security policy for {}:\n{}", user, securityPolicyType.asPrismObject().debugDump(1)); + } + } else { + if (securityPolicyType == null) { + LOGGER.trace("Located global security policy null"); + } else { + LOGGER.trace("Located global security policy :\n{}", securityPolicyType.asPrismObject().debugDump(1)); + } + } + } + + } + + private void postProcessSecurityPolicy(SecurityPolicyType securityPolicyType, Task task, OperationResult result) { + CredentialsPolicyType creds = securityPolicyType.getCredentials(); + if (creds != null) { + PasswordCredentialsPolicyType passwd = creds.getPassword(); + if (passwd != null) { + postProcessPasswordCredentialPolicy(securityPolicyType, passwd, task, result); + } + for (NonceCredentialsPolicyType nonce: creds.getNonce()) { + postProcessCredentialPolicy(securityPolicyType, nonce, "nonce credential policy", task, result); + } + SecurityQuestionsCredentialsPolicyType securityQuestions = creds.getSecurityQuestions(); + if (securityQuestions != null) { + postProcessCredentialPolicy(securityPolicyType, securityQuestions, "security questions credential policy", task, result); + } + } + } + + private void postProcessPasswordCredentialPolicy(SecurityPolicyType securityPolicyType, PasswordCredentialsPolicyType passwd, Task task, OperationResult result) { + postProcessCredentialPolicy(securityPolicyType, passwd, "password credential policy", task, result); + } + + private ValuePolicyType postProcessCredentialPolicy(SecurityPolicyType securityPolicyType, CredentialPolicyType credPolicy, String credShortDesc, Task task, OperationResult result) { + ObjectReferenceType valuePolicyRef = credPolicy.getValuePolicyRef(); + if (valuePolicyRef == null) { + return null; + } + ValuePolicyType valuePolicyType; + try { + valuePolicyType = objectResolver.resolve(valuePolicyRef, ValuePolicyType.class, null, credShortDesc + " in " + securityPolicyType, task, result); + } catch (ObjectNotFoundException | SchemaException | CommunicationException | ConfigurationException | SecurityViolationException | ExpressionEvaluationException e) { + LOGGER.warn("{} {} referenced from {} was not found", credShortDesc, valuePolicyRef.getOid(), securityPolicyType); + return null; + } + valuePolicyRef.asReferenceValue().setObject(valuePolicyType.asPrismObject()); + return valuePolicyType; + } + + private SecurityPolicyType postProcessPasswordPolicy(ValuePolicyType passwordPolicyType) { + SecurityPolicyType securityPolicyType = new SecurityPolicyType(); + CredentialsPolicyType creds = new CredentialsPolicyType(); + PasswordCredentialsPolicyType passwd = new PasswordCredentialsPolicyType(); + ObjectReferenceType passwordPolicyRef = new ObjectReferenceType(); + passwordPolicyRef.asReferenceValue().setObject(passwordPolicyType.asPrismObject()); + passwd.setValuePolicyRef(passwordPolicyRef); + creds.setPassword(passwd); + securityPolicyType.setCredentials(creds); + return securityPolicyType; + } + + private Duration daysToDuration(int days) { + return XmlTypeConverter.createDuration((long) days * 1000 * 60 * 60 * 24); + } + + public SecurityEnforcer getSecurityEnforcer() { + return securityEnforcer; + } +} From bdb74c8beb7951a13d8396b54a993f03ec387652 Mon Sep 17 00:00:00 2001 From: lskublik Date: Mon, 16 Mar 2020 08:42:28 +0100 Subject: [PATCH 02/21] disabling of two schrodinger tests (test001changeTime, checkJVMPropertiesMidpointHome) --- .../midpoint/testing/schrodinger/page/AboutPageTest.java | 3 +-- .../schrodinger/page/InternalsConfigurationPageTest.java | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/testing/schrodingertest/src/test/java/com/evolveum/midpoint/testing/schrodinger/page/AboutPageTest.java b/testing/schrodingertest/src/test/java/com/evolveum/midpoint/testing/schrodinger/page/AboutPageTest.java index 32a4fa59e1c..82cecdf5a9f 100644 --- a/testing/schrodingertest/src/test/java/com/evolveum/midpoint/testing/schrodinger/page/AboutPageTest.java +++ b/testing/schrodingertest/src/test/java/com/evolveum/midpoint/testing/schrodinger/page/AboutPageTest.java @@ -106,9 +106,8 @@ public void checkReindexRepositoryObjectsDisplayName() { // @formatter:on } - @Test + @Test (enabled = false) public void checkJVMPropertiesMidpointHome(){ - Selenide.sleep(2000); Assert.assertFalse( aboutPage.getJVMproperty(AbstractSchrodingerTest.PROPERTY_NAME_MIDPOINT_HOME).isEmpty()); } diff --git a/testing/schrodingertest/src/test/java/com/evolveum/midpoint/testing/schrodinger/page/InternalsConfigurationPageTest.java b/testing/schrodingertest/src/test/java/com/evolveum/midpoint/testing/schrodinger/page/InternalsConfigurationPageTest.java index 0df18bb694a..968e237ce53 100644 --- a/testing/schrodingertest/src/test/java/com/evolveum/midpoint/testing/schrodinger/page/InternalsConfigurationPageTest.java +++ b/testing/schrodingertest/src/test/java/com/evolveum/midpoint/testing/schrodinger/page/InternalsConfigurationPageTest.java @@ -28,7 +28,7 @@ public void afterClass() { super.afterClass(); } - @Test + @Test (enabled = false) public void test001changeTime() { InternalsConfigurationPage configPage = basicPage.internalsConfiguration(); ClockTab clockTab = configPage.clockTab(); From 0844ea784b5c98fa635964615592c0d6f2195249 Mon Sep 17 00:00:00 2001 From: Richard Richter Date: Mon, 16 Mar 2020 10:11:56 +0100 Subject: [PATCH 03/21] MidpointTestMixin#display(title, value) renamed to displayValue() Later we should unify various overloaded displayValue methods, along with various pretty printer mechanisms. --- .../midpoint/prism/AbstractPrismTest.java | 4 +- .../evolveum/midpoint/prism/TestDelta.java | 42 ++--- .../evolveum/midpoint/prism/TestEquals.java | 4 +- .../midpoint/prism/TestPolyString.java | 2 +- .../midpoint/schema/AbstractSchemaTest.java | 4 +- .../midpoint/schema/TestSchemaDelta.java | 8 +- .../evolveum/midpoint/util/PrettyPrinter.java | 3 +- .../model/common/AbstractModelCommonTest.java | 4 +- .../common/mapping/TestMappingDomain.java | 2 +- .../mapping/TestMappingDynamicSimple.java | 10 +- .../model/impl/TestRefinedSchema.java | 6 +- .../model/impl/lens/AbstractLensTest.java | 2 +- .../lens/TestAbstractAssignmentEvaluator.java | 22 +-- .../impl/lens/TestAssignmentProcessor.java | 6 +- .../model/impl/lens/TestClockwork.java | 6 +- .../model/impl/lens/TestPasswordPolicy.java | 12 +- .../TestAbstractAuthenticationEvaluator.java | 4 +- .../model/intest/TestConnectorDummyFake.java | 6 +- .../midpoint/model/intest/TestIteration.java | 18 +-- .../midpoint/model/intest/TestMerge.java | 8 +- .../intest/TestModelServiceContract.java | 2 +- .../model/intest/TestModelVisualization.java | 4 +- .../midpoint/model/intest/TestResources.java | 6 +- .../model/intest/TestScriptHooks.java | 4 +- .../midpoint/model/intest/TestVolatility.java | 2 +- .../intest/archetypes/TestCollections.java | 4 +- .../async/TestAsyncUpdateTaskMechanics.java | 4 +- .../manual/AbstractManualResourceTest.java | 12 +- .../intest/manual/TestSemiManualGrouping.java | 4 +- .../TestSemiManualGroupingProposed.java | 4 +- .../model/intest/mapping/TestMapping.java | 2 +- .../intest/mapping/TestMappingInbound.java | 2 +- .../midpoint/model/intest/misc/TestMisc.java | 8 +- .../model/intest/multi/TestMultiResource.java | 2 +- .../intest/negative/TestAssignmentErrors.java | 8 +- .../intest/password/AbstractPasswordTest.java | 4 +- .../intest/scripting/TestScriptingBasic.java | 10 +- .../intest/security/AbstractSecurityTest.java | 2 +- .../intest/security/TestSecurityAdvanced.java | 4 +- .../intest/sync/AbstractInboundSyncTest.java | 18 +-- .../sync/AbstractObjTemplateSyncTest.java | 2 +- .../AbstractSynchronizationStoryTest.java | 2 +- .../model/intest/sync/TestImportRecon.java | 44 +++--- .../sync/TestLiveSyncTaskMechanics.java | 10 +- .../intest/sync/TestProgressReporting.java | 8 +- .../midpoint/model/intest/sync/TestUuid.java | 12 +- .../sync/TestValidityRecomputeTask.java | 22 +-- .../test/AbstractModelIntegrationTest.java | 42 ++--- .../notifications/impl/TestTextFormatter.java | 8 +- .../evolveum/midpoint/report/TestReport.java | 12 +- .../midpoint/report/TestReportWebService.java | 6 +- .../wf/impl/other/TestEscalation.java | 2 +- .../impl/TestConnectorManager.java | 2 +- .../provisioning/impl/TestDBTable.java | 4 +- .../impl/async/TestAsyncUpdate.java | 2 +- .../impl/csv/AbstractCsvTest.java | 4 +- .../impl/dummy/AbstractBasicDummyTest.java | 14 +- .../provisioning/impl/dummy/TestDummy.java | 34 ++-- .../impl/dummy/TestDummyConsistency.java | 2 +- .../impl/dummy/TestDummyLegacy.java | 4 +- .../impl/dummy/TestDummyParallelism.java | 2 +- .../TestDummyPrioritiesAndReadReplace.java | 4 +- .../impl/dummy/TestDummySchemaless.java | 8 +- .../dummy/TestDummyUuidNonUniqueName.java | 2 +- .../manual/AbstractManualResourceTest.java | 4 +- .../provisioning/impl/opendj/TestOpenDj.java | 20 +-- .../impl/opendj/TestOpenDjNegative.java | 2 +- .../ucf/impl/connid/AbstractUcfDummyTest.java | 4 +- .../ucf/impl/connid/TestUcfDummy.java | 24 +-- .../ucf/impl/connid/TestUcfDummyMulti.java | 20 +-- .../ucf/impl/connid/TestUcfOpenDj.java | 14 +- .../repo/cache/TestRepositoryCache.java | 2 +- .../midpoint/repo/sql/BaseSQLRepoTest.java | 6 +- .../midpoint/repo/sql/CertificationTest.java | 4 +- .../midpoint/repo/sql/ConcurrencyTest.java | 10 +- .../repo/sql/ModifyAssignmentTest.java | 8 +- .../midpoint/repo/sql/ModifyTest.java | 24 +-- .../midpoint/repo/sql/ModifyTestReindex.java | 4 +- .../test/AbstractIntegrationTest.java | 16 +- .../quartzimpl/AbstractTaskManagerTest.java | 8 +- .../midpoint/task/quartzimpl/CleanupTest.java | 2 +- .../task/quartzimpl/TestMiscellaneous.java | 4 +- .../task/quartzimpl/TestPartitioning.java | 8 +- .../quartzimpl/TestTaskManagerContract.java | 2 +- .../quartzimpl/TestWorkBucketStrategies.java | 58 +++---- .../task/quartzimpl/TestWorkDistribution.java | 148 +++++++++--------- .../quartzimpl/TestWorkersManagement.java | 62 ++++---- .../testing/conntest/AbstractEDirTest.java | 8 +- .../conntest/AbstractLdapConnTest.java | 38 ++--- .../testing/conntest/TestOpenLdap.java | 10 +- .../ad/AbstractAdLdapMultidomainTest.java | 20 +-- .../conntest/ad/AbstractAdLdapTest.java | 6 +- .../testing/conntest/ad/AdTestMixin.java | 2 +- .../longtest/TestGenericSynchronization.java | 2 +- .../midpoint/testing/longtest/TestLdap.java | 10 +- .../testing/longtest/TestLdapComplex.java | 6 +- .../testing/longtest/TestLdapUniversity.java | 6 +- .../midpoint/testing/longtest/TestRunAs.java | 2 +- .../testing/rest/TestAbstractRestService.java | 6 +- .../midpoint/testing/sanity/TestSanity.java | 32 ++-- .../testing/story/AbstractStoryTest.java | 4 +- .../story/TestConsistencyMechanism.java | 4 +- .../testing/story/TestOperationPerf.java | 10 +- .../story/TestPlentyOfAssignments.java | 70 ++++----- .../testing/story/TestReconNullValue.java | 6 +- .../testing/story/TestRetirement.java | 12 +- .../testing/story/TestShadowsPerformance.java | 8 +- .../testing/story/TestThresholds.java | 2 +- .../story/TestThresholdsReconFull.java | 4 +- .../midpoint/testing/story/TestVillage.java | 4 +- .../testing/story/ldap/AbstractLdapTest.java | 4 +- .../ldap/TestLdapAssociationPerformance.java | 4 +- .../story/ldap/TestLdapDependency.java | 2 +- .../story/ldap/TestLdapReconPerformance.java | 2 +- .../story/ldap/TestLdapSyncMassive.java | 6 +- .../story/ldap/TestLdapVirtualGroup.java | 6 +- .../hierarchy/AbstractLdapHierarchyTest.java | 10 +- .../hierarchy/TestLdapDeeplyHierarchical.java | 4 +- .../ldap/hierarchy/TestLdapHierarchical.java | 4 +- .../notorious/AbstractNotoriousTest.java | 60 +++---- .../testing/story/perf/TestImport.java | 6 +- .../tools/testng/MidpointTestMixin.java | 5 +- 122 files changed, 684 insertions(+), 686 deletions(-) diff --git a/infra/prism-impl/src/test/java/com/evolveum/midpoint/prism/AbstractPrismTest.java b/infra/prism-impl/src/test/java/com/evolveum/midpoint/prism/AbstractPrismTest.java index f9a6913d098..6c6ab1ab565 100644 --- a/infra/prism-impl/src/test/java/com/evolveum/midpoint/prism/AbstractPrismTest.java +++ b/infra/prism-impl/src/test/java/com/evolveum/midpoint/prism/AbstractPrismTest.java @@ -47,11 +47,11 @@ public void initPrismContext() throws SchemaException, SAXException, IOException PrismTestUtil.resetPrismContext(new PrismInternalTestUtil()); } - protected void display(String title, DebugDumpable value) { + protected void displayValue(String title, DebugDumpable value) { PrismTestUtil.display(title, value); } - protected void display(String title, Object value) { + public void displayValue(String title, Object value) { PrismTestUtil.display(title, value); } diff --git a/infra/prism-impl/src/test/java/com/evolveum/midpoint/prism/TestDelta.java b/infra/prism-impl/src/test/java/com/evolveum/midpoint/prism/TestDelta.java index 60fbcf69145..cd6dc41f455 100644 --- a/infra/prism-impl/src/test/java/com/evolveum/midpoint/prism/TestDelta.java +++ b/infra/prism-impl/src/test/java/com/evolveum/midpoint/prism/TestDelta.java @@ -1543,10 +1543,10 @@ public void testObjectDeltaNarrow01() throws Exception { ObjectDelta userDelta = getPrismContext().deltaFactory().object() .createModificationAddProperty(UserType.class, USER_FOO_OID, UserType.F_ADDITIONAL_NAMES, "blabla", "bubu"); - display("userDelta", userDelta); + displayValue("userDelta", userDelta); PrismObject user = createUserFoo(); - display("user", user); + displayValue("user", user); // WHEN when(); @@ -1554,7 +1554,7 @@ public void testObjectDeltaNarrow01() throws Exception { // THEN then(); - display("Narrowed delta", narrowedDelta); + displayValue("Narrowed delta", narrowedDelta); PrismAsserts.assertIsModify(narrowedDelta); PrismAsserts.assertModifications(narrowedDelta, 1); @@ -1572,11 +1572,11 @@ public void testObjectDeltaNarrow02() throws Exception { ObjectDelta userDelta = getPrismContext().deltaFactory().object() .createModificationAddProperty(UserType.class, USER_FOO_OID, UserType.F_ADDITIONAL_NAMES, "blabla", "bubu"); - display("userDelta", userDelta); + displayValue("userDelta", userDelta); PrismObject user = createUserFoo(); user.setPropertyRealValue(UserType.F_ADDITIONAL_NAMES, "bubu"); - display("user", user); + displayValue("user", user); // WHEN when(); @@ -1584,7 +1584,7 @@ public void testObjectDeltaNarrow02() throws Exception { // THEN then(); - display("Narrowed delta", narrowedDelta); + displayValue("Narrowed delta", narrowedDelta); PrismAsserts.assertIsModify(narrowedDelta); PrismAsserts.assertModifications(narrowedDelta, 1); @@ -1602,11 +1602,11 @@ public void testObjectDeltaNarrow03() throws Exception { ObjectDelta userDelta = getPrismContext().deltaFactory().object() .createModificationAddProperty(UserType.class, USER_FOO_OID, UserType.F_ADDITIONAL_NAMES, "blabla", "bubu"); - display("userDelta", userDelta); + displayValue("userDelta", userDelta); PrismObject user = createUserFoo(); user.setPropertyRealValues(UserType.F_ADDITIONAL_NAMES, "bubu", "blabla"); - display("user", user); + displayValue("user", user); // WHEN when(); @@ -1614,7 +1614,7 @@ public void testObjectDeltaNarrow03() throws Exception { // THEN then(); - display("Narrowed delta", narrowedDelta); + displayValue("Narrowed delta", narrowedDelta); PrismAsserts.assertIsModify(narrowedDelta); PrismAsserts.assertModifications(narrowedDelta, 0); @@ -1628,11 +1628,11 @@ public void testObjectDeltaNarrowAssignmen01() throws Exception { .createModificationDeleteContainer(UserType.class, USER_FOO_OID, UserType.F_ASSIGNMENT, createAssignmentValue(null, ASSIGNMENT_PATLAMA_DESCRIPTION)); - display("userDelta", userDelta); + displayValue("userDelta", userDelta); PrismObject user = createUserFoo(); addAssignment(user, ASSIGNMENT_ABRAKADABRA_ID, ASSIGNMENT_ABRAKADABRA_DESCRIPTION); - display("user", user); + displayValue("user", user); // WHEN when(); @@ -1640,7 +1640,7 @@ public void testObjectDeltaNarrowAssignmen01() throws Exception { // THEN then(); - display("Narrowed delta", narrowedDelta); + displayValue("Narrowed delta", narrowedDelta); PrismAsserts.assertIsModify(narrowedDelta); PrismAsserts.assertModifications(narrowedDelta, 0); @@ -1654,11 +1654,11 @@ public void testObjectDeltaNarrowAssignmen02() throws Exception { .createModificationDeleteContainer(UserType.class, USER_FOO_OID, UserType.F_ASSIGNMENT, createAssignmentValue(ASSIGNMENT_PATLAMA_ID, null)); - display("userDelta", userDelta); + displayValue("userDelta", userDelta); PrismObject user = createUserFoo(); addAssignment(user, ASSIGNMENT_ABRAKADABRA_ID, ASSIGNMENT_ABRAKADABRA_DESCRIPTION); - display("user", user); + displayValue("user", user); // WHEN when(); @@ -1666,7 +1666,7 @@ public void testObjectDeltaNarrowAssignmen02() throws Exception { // THEN then(); - display("Narrowed delta", narrowedDelta); + displayValue("Narrowed delta", narrowedDelta); PrismAsserts.assertIsModify(narrowedDelta); PrismAsserts.assertModifications(narrowedDelta, 0); @@ -1680,12 +1680,12 @@ public void testObjectDeltaNarrowAssignmen11() throws Exception { .createModificationDeleteContainer(UserType.class, USER_FOO_OID, UserType.F_ASSIGNMENT, createAssignmentValue(null, ASSIGNMENT_PATLAMA_DESCRIPTION)); - display("userDelta", userDelta); + displayValue("userDelta", userDelta); PrismObject user = createUserFoo(); addAssignment(user, ASSIGNMENT_PATLAMA_ID, ASSIGNMENT_PATLAMA_DESCRIPTION); addAssignment(user, ASSIGNMENT_ABRAKADABRA_ID, ASSIGNMENT_ABRAKADABRA_DESCRIPTION); - display("user", user); + displayValue("user", user); // WHEN when(); @@ -1693,7 +1693,7 @@ public void testObjectDeltaNarrowAssignmen11() throws Exception { // THEN then(); - display("Narrowed delta", narrowedDelta); + displayValue("Narrowed delta", narrowedDelta); PrismAsserts.assertIsModify(narrowedDelta); PrismAsserts.assertModifications(narrowedDelta, 1); @@ -1711,12 +1711,12 @@ public void testObjectDeltaNarrowAssignmen12() throws Exception { .createModificationDeleteContainer(UserType.class, USER_FOO_OID, UserType.F_ASSIGNMENT, createAssignmentValue(ASSIGNMENT_PATLAMA_ID, null)); - display("userDelta", userDelta); + displayValue("userDelta", userDelta); PrismObject user = createUserFoo(); addAssignment(user, ASSIGNMENT_PATLAMA_ID, ASSIGNMENT_PATLAMA_DESCRIPTION); addAssignment(user, ASSIGNMENT_ABRAKADABRA_ID, ASSIGNMENT_ABRAKADABRA_DESCRIPTION); - display("user", user); + displayValue("user", user); // WHEN when(); @@ -1724,7 +1724,7 @@ public void testObjectDeltaNarrowAssignmen12() throws Exception { // THEN then(); - display("Narrowed delta", narrowedDelta); + displayValue("Narrowed delta", narrowedDelta); PrismAsserts.assertIsModify(narrowedDelta); PrismAsserts.assertModifications(narrowedDelta, 1); diff --git a/infra/prism-impl/src/test/java/com/evolveum/midpoint/prism/TestEquals.java b/infra/prism-impl/src/test/java/com/evolveum/midpoint/prism/TestEquals.java index 99e836894bb..e63cf0c3272 100644 --- a/infra/prism-impl/src/test/java/com/evolveum/midpoint/prism/TestEquals.java +++ b/infra/prism-impl/src/test/java/com/evolveum/midpoint/prism/TestEquals.java @@ -28,12 +28,12 @@ public void testContainsEquivalentValue01() throws Exception { .createModificationDeleteContainer(UserType.class, USER_FOO_OID, UserType.F_ASSIGNMENT, createAssignmentValue(ASSIGNMENT_PATLAMA_ID, null)); - display("userDelta", userDelta); + displayValue("userDelta", userDelta); PrismObject user = createUserFoo(); addAssignment(user, ASSIGNMENT_PATLAMA_ID, ASSIGNMENT_PATLAMA_DESCRIPTION); addAssignment(user, ASSIGNMENT_ABRAKADABRA_ID, ASSIGNMENT_ABRAKADABRA_DESCRIPTION); - display("user", user); + displayValue("user", user); PrismContainer assignmentContainer = user.findContainer(UserType.F_ASSIGNMENT); diff --git a/infra/prism-impl/src/test/java/com/evolveum/midpoint/prism/TestPolyString.java b/infra/prism-impl/src/test/java/com/evolveum/midpoint/prism/TestPolyString.java index d9ac4711680..b345954b1af 100644 --- a/infra/prism-impl/src/test/java/com/evolveum/midpoint/prism/TestPolyString.java +++ b/infra/prism-impl/src/test/java/com/evolveum/midpoint/prism/TestPolyString.java @@ -203,7 +203,7 @@ private void testNormalization(PolyStringNormalizer normalizer, String orig, Str PolyString polyString = new PolyString(orig); polyString.recompute(normalizer); String norm = polyString.getNorm(); - display("X: "+orig+" -> "+norm, unicodeEscape(orig)+"\n"+unicodeEscape(norm)); + displayValue("X: "+orig+" -> "+norm, unicodeEscape(orig)+"\n"+unicodeEscape(norm)); assertEquals("orig have changed", orig, polyString.getOrig()); assertEquals("wrong norm", expectedNorm, polyString.getNorm()); assertEquals("wrong toString", orig, polyString.toString()); diff --git a/infra/schema/src/test/java/com/evolveum/midpoint/schema/AbstractSchemaTest.java b/infra/schema/src/test/java/com/evolveum/midpoint/schema/AbstractSchemaTest.java index 4b8fbd4251a..769402ef392 100644 --- a/infra/schema/src/test/java/com/evolveum/midpoint/schema/AbstractSchemaTest.java +++ b/infra/schema/src/test/java/com/evolveum/midpoint/schema/AbstractSchemaTest.java @@ -54,11 +54,11 @@ protected PrismObjectDefinition getUserDefinition() { return getPrismContext().getSchemaRegistry().findObjectDefinitionByCompileTimeClass(UserType.class); } - protected void display(String title, DebugDumpable value) { + protected void displayValue(String title, DebugDumpable value) { PrismTestUtil.display(title, value); } - protected void display(String title, Object value) { + public void displayValue(String title, Object value) { PrismTestUtil.display(title, value); } } diff --git a/infra/schema/src/test/java/com/evolveum/midpoint/schema/TestSchemaDelta.java b/infra/schema/src/test/java/com/evolveum/midpoint/schema/TestSchemaDelta.java index 2bd14c541c4..35171bba6e4 100644 --- a/infra/schema/src/test/java/com/evolveum/midpoint/schema/TestSchemaDelta.java +++ b/infra/schema/src/test/java/com/evolveum/midpoint/schema/TestSchemaDelta.java @@ -540,19 +540,19 @@ public void testObjectDeltaUnion() throws Exception { ObjectDelta userDeltaUnion = ObjectDeltaCollectionsUtil.union(userDelta1, userDelta2); // THEN - display("result", userDeltaUnion); + displayValue("result", userDeltaUnion); PrismObject userWithSeparateDeltas = new UserType(getPrismContext()).asPrismObject(); userDelta1.applyTo(userWithSeparateDeltas); userDelta2.applyTo(userWithSeparateDeltas); - display("userWithSeparateDeltas after", userWithSeparateDeltas); + displayValue("userWithSeparateDeltas after", userWithSeparateDeltas); PrismObject userWithUnion = new UserType(getPrismContext()).asPrismObject(); userDeltaUnion.applyTo(userWithUnion); - display("userWithUnion after", userWithUnion); + displayValue("userWithUnion after", userWithUnion); ObjectDelta diff = userWithSeparateDeltas.diff(userWithUnion, EquivalenceStrategy.LITERAL); // set to isLiteral = false after fixing MID-4688 - display("diff", diff.debugDump()); + displayValue("diff", diff.debugDump()); assertTrue("Deltas have different effects:\n" + diff.debugDump(), diff.isEmpty()); } } diff --git a/infra/util/src/main/java/com/evolveum/midpoint/util/PrettyPrinter.java b/infra/util/src/main/java/com/evolveum/midpoint/util/PrettyPrinter.java index 37a4e526584..666d2f980d9 100644 --- a/infra/util/src/main/java/com/evolveum/midpoint/util/PrettyPrinter.java +++ b/infra/util/src/main/java/com/evolveum/midpoint/util/PrettyPrinter.java @@ -333,14 +333,13 @@ public static String debugDump(Object value, int indent) { if (value == null) { return "null"; } - String out = null; if (value instanceof DebugDumpable) { return ((DebugDumpable) value).debugDump(indent); } if (value instanceof Collection) { return DebugUtil.debugDump((Collection) value, indent); } - out = tryDebugDumpMethod(value, indent); + String out = tryDebugDumpMethod(value, indent); if (out != null) { return out; } diff --git a/model/model-common/src/test/java/com/evolveum/midpoint/model/common/AbstractModelCommonTest.java b/model/model-common/src/test/java/com/evolveum/midpoint/model/common/AbstractModelCommonTest.java index 5f767a8dc87..d2e454cedb6 100644 --- a/model/model-common/src/test/java/com/evolveum/midpoint/model/common/AbstractModelCommonTest.java +++ b/model/model-common/src/test/java/com/evolveum/midpoint/model/common/AbstractModelCommonTest.java @@ -30,11 +30,11 @@ protected Task createTask() { return new NullTaskImpl(); } - protected void display(String title, DebugDumpable value) { + public void displayValue(String title, DebugDumpable value) { PrismTestUtil.display(title, value); } - protected void display(String title, Object value) { + public void displayValue(String title, Object value) { PrismTestUtil.display(title, value); } } diff --git a/model/model-common/src/test/java/com/evolveum/midpoint/model/common/mapping/TestMappingDomain.java b/model/model-common/src/test/java/com/evolveum/midpoint/model/common/mapping/TestMappingDomain.java index 10c9620a5dc..65b99731a0d 100644 --- a/model/model-common/src/test/java/com/evolveum/midpoint/model/common/mapping/TestMappingDomain.java +++ b/model/model-common/src/test/java/com/evolveum/midpoint/model/common/mapping/TestMappingDomain.java @@ -256,7 +256,7 @@ protected void display(String title, DebugDumpable value) { PrismTestUtil.display(title, value); } - protected void display(String title, Object value) { + public void displayValue(String title, Object value) { PrismTestUtil.display(title, value); } } diff --git a/model/model-common/src/test/java/com/evolveum/midpoint/model/common/mapping/TestMappingDynamicSimple.java b/model/model-common/src/test/java/com/evolveum/midpoint/model/common/mapping/TestMappingDynamicSimple.java index 58dd11f431d..2bfbb13d886 100644 --- a/model/model-common/src/test/java/com/evolveum/midpoint/model/common/mapping/TestMappingDynamicSimple.java +++ b/model/model-common/src/test/java/com/evolveum/midpoint/model/common/mapping/TestMappingDynamicSimple.java @@ -917,8 +917,8 @@ public void testScriptTransformMultiAddDelete() throws Exception { PrismObject user = (PrismObject) mapping.getSourceContext().getOldObject(); user.asObjectable().getEmployeeType().add("LANDLUBER"); mapping.getSourceContext().recompute(); - display("user before", user); - display("delta", delta); + displayValue("user before", user); + displayValue("delta", delta); // WHEN when(); @@ -951,8 +951,8 @@ public void testScriptTransformMultiReplace() throws Exception { PrismObject user = (PrismObject) mapping.getSourceContext().getOldObject(); - display("user before", user); - display("delta", delta); + displayValue("user before", user); + displayValue("delta", delta); // WHEN when(); @@ -961,7 +961,7 @@ public void testScriptTransformMultiReplace() throws Exception { // THEN then(); PrismValueDeltaSetTriple> outputTriple = mapping.getOutputTriple(); - display("output triple", outputTriple); + displayValue("output triple", outputTriple); outputTriple.checkConsistence(); PrismAsserts.assertTripleNoZero(outputTriple); PrismAsserts.assertTriplePlus(outputTriple, PrismTestUtil.createPolyString("The captain deck")); diff --git a/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/TestRefinedSchema.java b/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/TestRefinedSchema.java index 2b3c2cc729e..9e63f5c0f45 100644 --- a/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/TestRefinedSchema.java +++ b/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/TestRefinedSchema.java @@ -187,7 +187,7 @@ public void test120DetermineObjectClassObjectClassModel() throws Exception { // THEN display("Object class", objectClass); - display("Object class (toString)", objectClass.toString()); + displayValue("Object class (toString)", objectClass.toString()); deleteObject(TaskType.class, TASK_RECONCILE_DUMMY_OBJECTCLASS_OID); @@ -208,7 +208,7 @@ public void test122DetermineObjectClassKindIntentModel() throws Exception { // THEN display("Object class", objectClass); - display("Object class (toString)", objectClass.toString()); + displayValue("Object class (toString)", objectClass.toString()); deleteObject(TaskType.class, TASK_RECONCILE_DUMMY_KIND_INTENT_OID); @@ -230,7 +230,7 @@ public void test124DetermineObjectClassKindIntentObjectClassModel() throws Excep // THEN display("Object class", objectClass); - display("Object class (toString)", objectClass.toString()); + displayValue("Object class (toString)", objectClass.toString()); deleteObject(TaskType.class, TASK_RECONCILE_DUMMY_KIND_INTENT_OBJECTCLASS_OID); diff --git a/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/AbstractLensTest.java b/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/AbstractLensTest.java index 9bf9843c602..364cd0ae1e4 100644 --- a/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/AbstractLensTest.java +++ b/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/AbstractLensTest.java @@ -331,7 +331,7 @@ void forEvaluatedFocusPolicyRule(LensContext context, Consu } protected void dumpPolicyRules(LensContext context) { - display("Policy rules", context.dumpAssignmentPolicyRules(3)); + displayValue("Policy rules", context.dumpAssignmentPolicyRules(3)); } protected void dumpPolicySituations(LensContext context) { diff --git a/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestAbstractAssignmentEvaluator.java b/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestAbstractAssignmentEvaluator.java index 816aee847c3..e73ee4949f1 100644 --- a/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestAbstractAssignmentEvaluator.java +++ b/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestAbstractAssignmentEvaluator.java @@ -124,7 +124,7 @@ public void test100Direct() throws Exception { TestUtil.assertSuccess(result); assertNotNull(evaluatedAssignment); - display("Evaluated assignment", evaluatedAssignment.debugDump()); + displayValue("Evaluated assignment", evaluatedAssignment.debugDump()); assertEquals(1, evaluatedAssignment.getConstructionTriple().size()); PrismAsserts.assertParentConsistency(userTypeJack.asPrismObject()); @@ -342,7 +342,7 @@ public void test140RoleVisitor() throws Exception { assertSuccess(result); assertNotNull(evaluatedAssignment); - display("Evaluated assignment", evaluatedAssignment.debugDump()); + displayValue("Evaluated assignment", evaluatedAssignment.debugDump()); assertEquals(1, evaluatedAssignment.getConstructionTriple().size()); PrismAsserts.assertParentConsistency(userTypeJack.asPrismObject()); @@ -388,7 +388,7 @@ public void test142RoleVisitorDisabledAssignment() throws Exception { TestUtil.assertSuccess(result); assertNotNull(evaluatedAssignment); - display("Evaluated assignment", evaluatedAssignment.debugDump()); + displayValue("Evaluated assignment", evaluatedAssignment.debugDump()); assertEquals(1, evaluatedAssignment.getConstructionTriple().size()); PrismAsserts.assertParentConsistency(userTypeJack.asPrismObject()); @@ -431,7 +431,7 @@ public void test150RoleEngineer() throws Exception { assertSuccess(result); assertNotNull(evaluatedAssignment); - display("Evaluated assignment", evaluatedAssignment.debugDump()); + displayValue("Evaluated assignment", evaluatedAssignment.debugDump()); assertEquals(4, evaluatedAssignment.getConstructionTriple().size()); PrismAsserts.assertParentConsistency(userTypeJack.asPrismObject()); @@ -483,7 +483,7 @@ public void test160AddRoleEngineer() throws Exception { assertSuccess(result); assertNotNull(evaluatedAssignment); - display("Evaluated assignment", evaluatedAssignment.debugDump()); + displayValue("Evaluated assignment", evaluatedAssignment.debugDump()); assertEquals("Wrong number of constructions", 4, evaluatedAssignment.getConstructionTriple().size()); PrismAsserts.assertParentConsistency(userTypeJack.asPrismObject()); @@ -556,7 +556,7 @@ public void test170RoleManagerChangeCostCenter() throws Exception { TestUtil.assertSuccess(result); assertNotNull(evaluatedAssignment); - display("Evaluated assignment", evaluatedAssignment.debugDump()); + displayValue("Evaluated assignment", evaluatedAssignment.debugDump()); assertEquals(4, evaluatedAssignment.getConstructionTriple().size()); PrismAsserts.assertParentConsistency(userTypeJack.asPrismObject()); @@ -618,7 +618,7 @@ public void test180RoleManagerRemoveCostCenter() throws Exception { TestUtil.assertSuccess(result); assertNotNull(evaluatedAssignment); - display("Evaluated assignment", evaluatedAssignment.debugDump()); + displayValue("Evaluated assignment", evaluatedAssignment.debugDump()); assertEquals(4, evaluatedAssignment.getConstructionTriple().size()); PrismAsserts.assertParentConsistency(userTypeJack.asPrismObject()); @@ -675,7 +675,7 @@ public void test200DisableEngineerEmployeeInducement() throws Exception { TestUtil.assertSuccess(result); assertNotNull(evaluatedAssignment); - display("Evaluated assignment", evaluatedAssignment.debugDump()); + displayValue("Evaluated assignment", evaluatedAssignment.debugDump()); // TODO } @@ -732,7 +732,7 @@ public void test300DisableRoleEmployee() throws Exception { TestUtil.assertSuccess(result); assertNotNull(evaluatedAssignment); - display("Evaluated assignment", evaluatedAssignment.debugDump()); + displayValue("Evaluated assignment", evaluatedAssignment.debugDump()); assertEquals(2, evaluatedAssignment.getConstructionTriple().size()); PrismAsserts.assertParentConsistency(userTypeJack.asPrismObject()); @@ -785,7 +785,7 @@ public void test310DisableRoleEngineer() throws Exception { TestUtil.assertSuccess(result); assertNotNull(evaluatedAssignment); - display("Evaluated assignment", evaluatedAssignment.debugDump()); + displayValue("Evaluated assignment", evaluatedAssignment.debugDump()); assertEquals(2, evaluatedAssignment.getConstructionTriple().size()); PrismAsserts.assertParentConsistency(userTypeJack.asPrismObject()); @@ -842,7 +842,7 @@ public void test400UserFred() throws Exception { assertSuccess(result); DeltaSetTriple> triple = lensContext.getEvaluatedAssignmentTriple(); - display("Evaluated assignment triple", triple.debugDump()); + displayValue("Evaluated assignment triple", triple.debugDump()); assertEquals("Wrong # of evaluated assignments zero set", 0, triple.getZeroSet().size()); assertEquals("Wrong # of evaluated assignments plus set", 1, triple.getPlusSet().size()); assertEquals("Wrong # of evaluated assignments minus set", 1, triple.getMinusSet().size()); diff --git a/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestAssignmentProcessor.java b/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestAssignmentProcessor.java index 07de2079881..0211c17b6fe 100644 --- a/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestAssignmentProcessor.java +++ b/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestAssignmentProcessor.java @@ -364,7 +364,7 @@ public void test031DeleteAssignmentModifyAccount() throws Exception { // THEN then(); - display("Output context", context.dump(true)); + displayValue("Output context", context.dump(true)); display("result", result); assertSuccess(result); @@ -649,7 +649,7 @@ public void test200AssignVisitor() throws Exception { DeltaSetTriple> evaluatedAssignmentTriple = context.getEvaluatedAssignmentTriple(); assertEquals("Wrong # of added assignments", 1, evaluatedAssignmentTriple.getPlusSet().size()); - display("Policy rules", context.dumpAssignmentPolicyRules(3)); + displayValue("Policy rules", context.dumpAssignmentPolicyRules(3)); EvaluatedAssignmentImpl evaluatedAssignment = evaluatedAssignmentTriple.getPlusSet().iterator().next(); assertEquals("Wrong # of focus policy rules", 0, evaluatedAssignment.getFocusPolicyRules().size()); @@ -702,7 +702,7 @@ public void test210AssignEngineer() throws Exception { DeltaSetTriple> evaluatedAssignmentTriple = context.getEvaluatedAssignmentTriple(); assertEquals("Wrong # of added assignments", 1, evaluatedAssignmentTriple.getPlusSet().size()); - display("Policy rules", context.dumpAssignmentPolicyRules(3)); + displayValue("Policy rules", context.dumpAssignmentPolicyRules(3)); EvaluatedAssignmentImpl evaluatedAssignment = evaluatedAssignmentTriple.getPlusSet().iterator().next(); assertEquals("Wrong # of focus policy rules", 0, evaluatedAssignment.getFocusPolicyRules().size()); diff --git a/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestClockwork.java b/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestClockwork.java index 66e23f16192..914b83c2bd9 100644 --- a/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestClockwork.java +++ b/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestClockwork.java @@ -87,7 +87,7 @@ public void test010SerializeAddUserBarbossa() throws Exception { LensContextType lensContextType = context.toLensContextType(); String xml = prismContext.xmlSerializer().serializeRealValue(lensContextType, SchemaConstants.C_MODEL_CONTEXT); - display("Serialized form", xml); + displayValue("Serialized form", xml); LensContextType unmarshalledContainer = prismContext.parserFor(xml).xml().parseRealValue(LensContextType.class); LensContext context2 = LensContext.fromLensContextType( @@ -270,14 +270,14 @@ private void assignAccountToJackAsync(boolean serialize) throws Exception { String xml = prismContext.xmlSerializer().serializeRealValue( lensContextType, SchemaConstants.C_MODEL_CONTEXT); - display("Serialized form", xml); + displayValue("Serialized form", xml); LensContextType unmarshalledContainer = prismContext.parserFor(xml).xml().parseRealValue(LensContextType.class); context = LensContext.fromLensContextType(unmarshalledContainer, context.getPrismContext(), provisioningService, task, result); - display("Context after deserialization", context.debugDump()); + displayValue("Context after deserialization", context.debugDump()); context.checkConsistence(); } diff --git a/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestPasswordPolicy.java b/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestPasswordPolicy.java index 0cfc6e870e5..f0501777088 100644 --- a/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestPasswordPolicy.java +++ b/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestPasswordPolicy.java @@ -99,7 +99,7 @@ public void testPasswordGeneratorComplexNegative() throws Exception { // THEN then(); - display("Generated password", psswd); + displayValue("Generated password", psswd); result.computeStatus(); AssertJUnit.assertTrue(result.isAcceptable()); assertNotNull(psswd); @@ -151,7 +151,7 @@ public void testValueGenerateRandomPin() throws Exception { // THEN then(); - display("Generated password", psswd); + displayValue("Generated password", psswd); result.computeStatus(); TestUtil.assertSuccess(result); assertNotNull(psswd); @@ -172,7 +172,7 @@ public void testValueGenerate() throws Exception { // THEN then(); - display("Generated password", psswd); + displayValue("Generated password", psswd); result.computeStatus(); TestUtil.assertSuccess(result); assertNotNull(psswd); @@ -195,7 +195,7 @@ public void testValueGenerateEmpty() throws Exception { // THEN then(); - display("Generated password", psswd); + displayValue("Generated password", psswd); result.computeStatus(); TestUtil.assertSuccess(result); assertNotNull(psswd); @@ -300,7 +300,7 @@ public void testUsername() throws Exception { OperationResult result = task.getResult(); String psswd = valuePolicyProcessor.generate(SchemaConstants.PATH_PASSWORD_VALUE, pp, 10, true, createUserOriginResolver(user), getTestNameShort(), task, result); - display("Generated password (" + i + ")", psswd); + displayValue("Generated password (" + i + ")", psswd); result.computeStatus(); TestUtil.assertSuccess(result); @@ -331,7 +331,7 @@ public void testUserProps() throws Exception { OperationResult result = task.getResult(); String psswd = valuePolicyProcessor.generate(SchemaConstants.PATH_PASSWORD_VALUE, pp, 10, true, createUserOriginResolver(user), getTestNameShort(), task, result); - display("Generated password (" + i + ")", psswd); + displayValue("Generated password (" + i + ")", psswd); result.computeStatus(); TestUtil.assertSuccess(result); diff --git a/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/security/TestAbstractAuthenticationEvaluator.java b/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/security/TestAbstractAuthenticationEvaluator.java index 98dcb11e75a..cd5d135f4de 100644 --- a/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/security/TestAbstractAuthenticationEvaluator.java +++ b/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/security/TestAbstractAuthenticationEvaluator.java @@ -1034,7 +1034,7 @@ private void assertPrincipalJack(MidPointPrincipal principal) { private void loginJackGoodPasswordExpectSuccess() throws ObjectNotFoundException, SchemaException, SecurityViolationException, CommunicationException, ConfigurationException, ExpressionEvaluationException { - display("now", clock.currentTimeXMLGregorianCalendar()); + displayValue("now", clock.currentTimeXMLGregorianCalendar()); ConnectionEnvironment connEnv = createConnectionEnvironment(); XMLGregorianCalendar startTs = clock.currentTimeXMLGregorianCalendar(); @@ -1054,7 +1054,7 @@ private void loginJackGoodPasswordExpectSuccess() } private void loginJackGoodPasswordExpectDenied() throws ObjectNotFoundException, SchemaException, SecurityViolationException, CommunicationException, ConfigurationException, ExpressionEvaluationException { - display("now", clock.currentTimeXMLGregorianCalendar()); + displayValue("now", clock.currentTimeXMLGregorianCalendar()); ConnectionEnvironment connEnv = createConnectionEnvironment(); // WHEN diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestConnectorDummyFake.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestConnectorDummyFake.java index 0bbc07329ef..06955cb4d01 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestConnectorDummyFake.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestConnectorDummyFake.java @@ -96,10 +96,10 @@ public void test010ListConnectors() throws Exception { if (CONNECTOR_DUMMY_TYPE.equals(connectorType.getConnectorType())) { String connectorVersion = connectorType.getConnectorVersion(); if (connectorVersion.contains("fake")) { - display("Fake Dummy Connector OID", connector.getOid()); + displayValue("Fake Dummy Connector OID", connector.getOid()); connectorDummyFakeOid = connector.getOid(); } else { - display("Dummy Connector OID", connector.getOid()); + displayValue("Dummy Connector OID", connector.getOid()); connectorDummyOid = connector.getOid(); } } @@ -455,7 +455,7 @@ private void assertUpgrade(PrismObject dummyResourceModelBefore) t resourceDummyFake = modelService.getObject(ResourceType.class, RESOURCE_DUMMY_FAKE_OID, null, task, result); display("Upgraded fake resource (model)", resourceDummyFake); Element resourceDummyFakeSchemaElement = ResourceTypeUtil.getResourceXsdSchema(resourceDummyFake); - display("Upgraded fake resource schema (model)", DOMUtil.serializeDOMToString(resourceDummyFakeSchemaElement)); + displayValue("Upgraded fake resource schema (model)", DOMUtil.serializeDOMToString(resourceDummyFakeSchemaElement)); assertNotNull("Null fake resource after getObject (model)", resourceDummyFake); assertEquals("Oooops. The OID of fake resource mysteriously changed. Call the police! (model)", RESOURCE_DUMMY_FAKE_OID, resourceDummyFake.getOid()); assertEquals("Wrong connectorRef in fake resource (model)", connectorDummyOid, diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestIteration.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestIteration.java index cfe2abcc01c..381c6b3c799 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestIteration.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestIteration.java @@ -1602,7 +1602,7 @@ public void test710DarkVioletAddLeChuck() throws Exception { // WHEN when(); - display("Adding dummy account", account.debugDump()); + displayValue("Adding dummy account", account.debugDump()); getDummyResource(RESOURCE_DUMMY_DARK_VIOLET_NAME).addAccount(account); waitForTaskNextRunAssertSuccess(TASK_LIVE_SYNC_DUMMY_DARK_VIOLET_OID, true); @@ -1627,7 +1627,7 @@ public void test712DarkVioletAddCharles() throws Exception { // WHEN when(); - display("Adding dummy account", account.debugDump()); + displayValue("Adding dummy account", account.debugDump()); getDummyResource(RESOURCE_DUMMY_DARK_VIOLET_NAME).addAccount(account); waitForTaskNextRunAssertSuccess(TASK_LIVE_SYNC_DUMMY_DARK_VIOLET_OID, true); @@ -1654,7 +1654,7 @@ public void test714DarkVioletAddShinetop() throws Exception { // WHEN when(); - display("Adding dummy account", account.debugDump()); + displayValue("Adding dummy account", account.debugDump()); getDummyResource(RESOURCE_DUMMY_DARK_VIOLET_NAME).addAccount(account); waitForTaskNextRunAssertSuccess(TASK_LIVE_SYNC_DUMMY_DARK_VIOLET_OID, true); @@ -1750,7 +1750,7 @@ public void test724DarkVioletAddLe_Chuck() throws Exception { // WHEN when(); - display("Adding dummy account", account.debugDump()); + displayValue("Adding dummy account", account.debugDump()); getDummyResource(RESOURCE_DUMMY_DARK_VIOLET_NAME).addAccount(account); waitForTaskNextRunAssertSuccess(TASK_LIVE_SYNC_DUMMY_DARK_VIOLET_OID, true); @@ -1780,7 +1780,7 @@ public void test730DarkVioletAddBarbossa() throws Exception { // WHEN when(); - display("Adding dummy account", account.debugDump()); + displayValue("Adding dummy account", account.debugDump()); getDummyResource(RESOURCE_DUMMY_DARK_VIOLET_NAME).addAccount(account); waitForTaskNextRunAssertSuccess(TASK_LIVE_SYNC_DUMMY_DARK_VIOLET_OID, true); @@ -1808,7 +1808,7 @@ public void test732DarkVioletAddBarbossa() throws Exception { // WHEN when(); - display("Adding dummy account", account.debugDump()); + displayValue("Adding dummy account", account.debugDump()); getDummyResource(RESOURCE_DUMMY_DARK_VIOLET_NAME).addAccount(account); waitForTaskNextRunAssertSuccess(TASK_LIVE_SYNC_DUMMY_DARK_VIOLET_OID, true); @@ -1837,7 +1837,7 @@ public void test750DarkVioletAddMatusalem() throws Exception { // WHEN when(); - display("Adding dummy account", account.debugDump()); + displayValue("Adding dummy account", account.debugDump()); getDummyResource(RESOURCE_DUMMY_DARK_VIOLET_NAME).addAccount(account); waitForTaskNextRunAssertSuccess(TASK_LIVE_SYNC_DUMMY_DARK_VIOLET_OID, true); @@ -1862,7 +1862,7 @@ public void test752DarkVioletAddDiplomatico() throws Exception { // WHEN when(); - display("Adding dummy account", account.debugDump()); + displayValue("Adding dummy account", account.debugDump()); getDummyResource(RESOURCE_DUMMY_DARK_VIOLET_NAME).addAccount(account); waitForTaskNextRunAssertSuccess(TASK_LIVE_SYNC_DUMMY_DARK_VIOLET_OID, true); @@ -1893,7 +1893,7 @@ public void test754DarkVioletAddMilionario() throws Exception { // WHEN when(); - display("Adding dummy account", account.debugDump()); + displayValue("Adding dummy account", account.debugDump()); getDummyResource(RESOURCE_DUMMY_DARK_VIOLET_NAME).addAccount(account); waitForTaskNextRunAssertSuccess(TASK_LIVE_SYNC_DUMMY_DARK_VIOLET_OID, true); diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestMerge.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestMerge.java index 269485b6e2c..5d17a039583 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestMerge.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestMerge.java @@ -79,10 +79,10 @@ public void test000Sanity() throws Exception { guybrushDummyAccountCyanOid = assertAccount(userGuybrushBefore, RESOURCE_DUMMY_CYAN_OID); assertLinks(userGuybrushBefore, 2); - display("Jack DUMMY account", jackDummyAccountOid); - display("Jack RED account", jackDummyAccountRedOid); - display("Guybrush DUMMY account", guybrushDummyAccountOid); - display("Guybrush CYAN account", guybrushDummyAccountCyanOid); + displayValue("Jack DUMMY account", jackDummyAccountOid); + displayValue("Jack RED account", jackDummyAccountRedOid); + displayValue("Guybrush DUMMY account", guybrushDummyAccountOid); + displayValue("Guybrush CYAN account", guybrushDummyAccountCyanOid); } /** diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestModelServiceContract.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestModelServiceContract.java index 2e624b724f1..a5703c41c8a 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestModelServiceContract.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestModelServiceContract.java @@ -3325,7 +3325,7 @@ private void preTestCleanup(AssignmentPolicyEnforcementType enforcementPolicy) t private void assertResultSerialization(OperationResult result) throws SchemaException { OperationResultType resultType = result.createOperationResultType(); String serialized = prismContext.serializerFor(PrismContext.LANG_XML).serializeAnyData(resultType, SchemaConstants.C_RESULT); - display("OperationResultType serialized", serialized); + displayValue("OperationResultType serialized", serialized); } } diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestModelVisualization.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestModelVisualization.java index b475c587a70..48b7fef0862 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestModelVisualization.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestModelVisualization.java @@ -44,7 +44,7 @@ public void test100VisualizeOneResource() throws Exception { DataModelVisualizer.Target.DOT, task, result); // THEN - display("Visualization output", output); + displayValue("Visualization output", output); result.computeStatus(); TestUtil.assertSuccess(result); } @@ -60,7 +60,7 @@ public void test110VisualizeTwoResources() throws Exception { DataModelVisualizer.Target.DOT, task, result); // THEN - display("Visualization output", output); + displayValue("Visualization output", output); result.computeStatus(); TestUtil.assertSuccess(result); } diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestResources.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestResources.java index 36a4159df6a..865ef461b36 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestResources.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestResources.java @@ -784,7 +784,7 @@ public void test200GetResourceRawAfterSchema() throws Exception { IntegrationTestTools.assertNoRepoCache(); SqlRepoTestUtil.assertVersionProgress(null, resource.getVersion()); lastVersion = resource.getVersion(); - display("Initial version", lastVersion); + displayValue("Initial version", lastVersion); assertSuccess(result); @@ -999,7 +999,7 @@ private void modifyConfigurationDiffExpressionRaw( String serializedResource = prismContext.serializerFor(PrismContext.LANG_XML).serialize(resourceBefore); String modifiedResourceXml = serializedResource.replace("whatever raw wherever", "useless"); - display("New resource XML", modifiedResourceXml); + displayValue("New resource XML", modifiedResourceXml); PrismObject modifiedResource = parser.apply(modifiedResourceXml); display("New resource", modifiedResource); @@ -1133,7 +1133,7 @@ private void singleModify(CarefulAnt ant, int iteration, Task task PrismObject resourceAfter = modelService.getObject(ResourceType.class, RESOURCE_DUMMY_OID, getOptions, task, result); SqlRepoTestUtil.assertVersionProgress(lastVersion, resourceAfter.getVersion()); lastVersion = resourceAfter.getVersion(); - display("Version", lastVersion); + displayValue("Version", lastVersion); Element xsdSchema = ResourceTypeUtil.getResourceXsdSchema(resourceAfter); if (xsdSchema != null) { diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestScriptHooks.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestScriptHooks.java index b3b5f34a650..4415e52722c 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestScriptHooks.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestScriptHooks.java @@ -103,7 +103,7 @@ public void test100JackAssignHookAccount() throws Exception { // Check account in dummy resource assertDummyAccount(RESOURCE_DUMMY_HOOK_NAME, ACCOUNT_JACK_DUMMY_USERNAME, "Jack Sparrow", true); - display("StaticHookRecorder", StaticHookRecorder.dump()); + displayValue("StaticHookRecorder", StaticHookRecorder.dump()); StaticHookRecorder.assertInvocationCount("org", 1); StaticHookRecorder.assertInvocationCount("foo", 5); StaticHookRecorder.assertInvocationCount("bar", 5); @@ -160,7 +160,7 @@ public void test110JackAddOrganization() throws Exception { assertAssignedOrg(userJack, brethrenOrg); - display("StaticHookRecorder", StaticHookRecorder.dump()); + displayValue("StaticHookRecorder", StaticHookRecorder.dump()); StaticHookRecorder.assertInvocationCount("org", 1); StaticHookRecorder.assertInvocationCount("foo", 10); StaticHookRecorder.assertInvocationCount("bar", 10); diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestVolatility.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestVolatility.java index f84eab55123..e4608402da1 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestVolatility.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestVolatility.java @@ -159,7 +159,7 @@ public void test120UpdateDummyHrAccountMancomb() throws Exception { DummyAccount account = getDummyResource(RESOURCE_DUMMY_HR_NAME).getAccountByUsername(ACCOUNT_MANCOMB_DUMMY_USERNAME); account.replaceAttributeValue(DummyAccount.ATTR_FULLNAME_NAME, "Sir Mancomb Seepgood"); - display("Dummy HR resource", getDummyResource(RESOURCE_DUMMY_HR_NAME).debugDump()); + displayValue("Dummy HR resource", getDummyResource(RESOURCE_DUMMY_HR_NAME).debugDump()); // Make sure we have steady state waitForSyncTaskNextRun(); diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/archetypes/TestCollections.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/archetypes/TestCollections.java index d75f22cd9b9..b9d9a824cd2 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/archetypes/TestCollections.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/archetypes/TestCollections.java @@ -125,7 +125,7 @@ public void test110CollectionStatsAllEnabled() throws Exception { // THEN then(); - display("Collection stats", stats); + displayValue("Collection stats", stats); assertSuccess(result); assertNotNull("Null stats", stats); @@ -168,7 +168,7 @@ public void test120CollectionStatsOneDisabled() throws Exception { // THEN then(); - display("Collection stats", stats); + displayValue("Collection stats", stats); assertSuccess(result); assertNotNull("Null stats", stats); diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/async/TestAsyncUpdateTaskMechanics.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/async/TestAsyncUpdateTaskMechanics.java index f799064bea3..0202a08fc17 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/async/TestAsyncUpdateTaskMechanics.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/async/TestAsyncUpdateTaskMechanics.java @@ -102,7 +102,7 @@ public void test100SmallTaskNoWorkers() throws IOException, TimeoutException, Co displayTaskWithOperationStats("Task after", taskAfter); int usersAdded = getObjectCount(UserType.class) - usersBefore; - display("Users added", usersAdded); + displayValue("Users added", usersAdded); assertEquals("Wrong # of users added", 10, usersAdded); assertEquals("Wrong task progress", 10, taskAfter.asObjectable().getProgress().intValue()); @@ -126,7 +126,7 @@ public void test110SmallTaskOneWorker() throws IOException, TimeoutException, Co displayTaskWithOperationStats("Task after", taskAfter); int usersAdded = getObjectCount(UserType.class) - usersBefore; - display("Users added", usersAdded); + displayValue("Users added", usersAdded); assertEquals("Wrong # of users added", 10, usersAdded); assertNotNull("No task progress", taskAfter.asObjectable().getProgress()); diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/manual/AbstractManualResourceTest.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/manual/AbstractManualResourceTest.java index fadbc318e97..c9bbe7c9998 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/manual/AbstractManualResourceTest.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/manual/AbstractManualResourceTest.java @@ -169,7 +169,7 @@ public void initSystem(Task initTask, OperationResult initResult) throws Excepti if (backingStore != null) { backingStore.initialize(); } - display("Backing store", backingStore); + displayValue("Backing store", backingStore); repoAddObjectFromFile(SECURITY_POLICY_FILE, initResult); @@ -303,7 +303,7 @@ public void testConnection(boolean initialized) throws Exception { assertNotNull("No schema after test connection", resourceXsdSchemaElementAfter); String resourceXml = prismContext.serializeObjectToString(resourceRepoAfter, PrismContext.LANG_XML); - display("Resource XML after test connection", resourceXml); + displayValue("Resource XML after test connection", resourceXml); CachingMetadataType schemaCachingMetadata = xmlSchemaTypeAfter.getCachingMetadata(); assertNotNull("No caching metadata", schemaCachingMetadata); @@ -413,7 +413,7 @@ public void testCapabilities() throws Exception { // THEN display("Resource from model", resource); - display("Resource from model (XML)", PrismTestUtil.serializeObjectToString(resource.asPrismObject(), PrismContext.LANG_XML)); + displayValue("Resource from model (XML)", PrismTestUtil.serializeObjectToString(resource.asPrismObject(), PrismContext.LANG_XML)); assertSteadyResources(); @@ -565,7 +565,7 @@ public void test032UseResource() throws Exception { assertNotNull("No schema after test connection", resourceXsdSchemaElementAfter); String resourceXml = prismContext.serializeObjectToString(resourceRepoAfter, PrismContext.LANG_XML); - display("Resource XML after test connection", resourceXml); + displayValue("Resource XML after test connection", resourceXml); CachingMetadataType schemaCachingMetadata = xmlSchemaTypeAfter.getCachingMetadata(); assertNotNull("No schema caching metadata", schemaCachingMetadata); @@ -1609,7 +1609,7 @@ public void test418AssignPhoenixAccountAgain() throws Exception { } } catch (ObjectNotFoundException e) { - display("Shadow after", "NOT FOUND: " + linkRef.getOid()); + displayValue("Shadow after", "NOT FOUND: " + linkRef.getOid()); } } assertEquals("Unexpected number of dead shadows", 1, deadShadows); @@ -1851,7 +1851,7 @@ protected boolean isActivationStatusModifyDelta(ObjectDeltaType delta, Activatio PrismProperty parsedItem = (PrismProperty) (Item) value.get(0).getParsedItem(getUserDefinition().findPropertyDefinition(SchemaConstants.PATH_ACTIVATION_ADMINISTRATIVE_STATUS)); ActivationStatusType status = parsedItem.getRealValue(); - display("Delta status " + status, itemDelta); + displayValue("Delta status " + status, itemDelta); if (expected.equals(status)) { return true; } diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/manual/TestSemiManualGrouping.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/manual/TestSemiManualGrouping.java index b4e4921a978..f06abc9e1a0 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/manual/TestSemiManualGrouping.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/manual/TestSemiManualGrouping.java @@ -135,7 +135,7 @@ public void test400PhantomAccount() throws Exception { // THEN (mid1) then("mid1"); String caseOid1 = assertInProgress(result); - display("Case 1", caseOid1); + displayValue("Case 1", caseOid1); // No case OID yet. The case would be created after propagation is run. assertNull("Unexpected case 1 OID", caseOid1); @@ -165,7 +165,7 @@ public void test400PhantomAccount() throws Exception { // THEN (mid2) then("mid2"); String caseOid2 = assertInProgress(result); - display("Case 2", caseOid2); + displayValue("Case 2", caseOid2); // No case OID yet. The case will be created after propagation is run. assertNull("Unexpected case 2 OID", caseOid2); diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/manual/TestSemiManualGroupingProposed.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/manual/TestSemiManualGroupingProposed.java index 01b5789d324..4f0b6edd465 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/manual/TestSemiManualGroupingProposed.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/manual/TestSemiManualGroupingProposed.java @@ -76,7 +76,7 @@ public void test020ResourcesSanity() throws Exception { OperationResult result = task.getResult(); SearchResultList> resources = repositoryService.searchObjects(ResourceType.class, null, null, result); - display("Resources", resources.size() + ": " + resources); + displayValue("Resources", resources.size() + ": " + resources); assertEquals("Unexpected number of resources", 3, resources.size()); ObjectQuery query = prismContext.queryFor(ResourceType.class) @@ -84,7 +84,7 @@ public void test020ResourcesSanity() throws Exception { .build(); SearchResultList> propagatedResources = repositoryService.searchObjects(ResourceType.class, query, null, result); - display("Propagated resources", propagatedResources.size() + ": " + propagatedResources); + displayValue("Propagated resources", propagatedResources.size() + ": " + propagatedResources); assertEquals("Unexpected number of propagated resources", 1, propagatedResources.size()); } diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/mapping/TestMapping.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/mapping/TestMapping.java index 6c27f506818..ae72befcea3 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/mapping/TestMapping.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/mapping/TestMapping.java @@ -212,7 +212,7 @@ public void test100ModifyUserAssignAccountDummyBlue() throws Exception { assertNotNull("No blue drink", drinkBlue); UUID drinkUuidBlue = UUID.fromString(drinkBlue); assertNotNull("No drink UUID", drinkUuidBlue); - display("Drink UUID", drinkUuidBlue.toString()); + displayValue("Drink UUID", drinkUuidBlue.toString()); assertAccountShip(userJack, ACCOUNT_JACK_DUMMY_FULLNAME, null, RESOURCE_DUMMY_BLUE_NAME, task); assertDummyAccountAttribute(RESOURCE_DUMMY_BLUE_NAME, USER_JACK_USERNAME, diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/mapping/TestMappingInbound.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/mapping/TestMappingInbound.java index 46175f45d8b..b2f05c86dd8 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/mapping/TestMappingInbound.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/mapping/TestMappingInbound.java @@ -356,7 +356,7 @@ public void test300DeleteDummyTeaGreenAccountMancomb() throws Exception { when(); getDummyResource(RESOURCE_DUMMY_TEA_GREEN_NAME).deleteAccountByName(ACCOUNT_MANCOMB_DUMMY_USERNAME); - display("Dummy (tea green) resource", getDummyResource(RESOURCE_DUMMY_TEA_GREEN_NAME).debugDump()); + displayValue("Dummy (tea green) resource", getDummyResource(RESOURCE_DUMMY_TEA_GREEN_NAME).debugDump()); // Make sure we have steady state resumeTaskAndWaitForNextFinish(TASK_LIVE_SYNC_DUMMY_TEA_GREEN_OID, false, 20000); diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/misc/TestMisc.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/misc/TestMisc.java index b6c3e330dff..058aa335850 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/misc/TestMisc.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/misc/TestMisc.java @@ -89,7 +89,7 @@ public void test100GetRepositoryDiag() { // THEN then(); - display("Diag", diag); + displayValue("Diag", diag); assertSuccess(result); assertEquals("Wrong implementationShortName", "SQL", diag.getImplementationShortName()); @@ -135,7 +135,7 @@ public void test200ExportUsers() throws Exception { assertNotNull("Null definition in " + user, user.getDefinition()); display("Definition", user.getDefinition()); String xmlString = prismContext.serializerFor(PrismContext.LANG_XML).serialize(user); - display("Exported user", xmlString); + displayValue("Exported user", xmlString); Document xmlDocument = DOMUtil.parseDocument(xmlString); Schema javaxSchema = prismContext.getSchemaRegistry().getJavaxSchema(); @@ -502,7 +502,7 @@ public void test506ModifyResourceGetAccountJackResourceScripty() throws Exceptio assertAssignments(userBefore, 1); String accountOid = getSingleLinkOid(userBefore); PrismObject resourceBefore = getObject(ResourceType.class, RESOURCE_SCRIPTY_OID); - display("Resource version before", resourceBefore.getVersion()); + displayValue("Resource version before", resourceBefore.getVersion()); // WHEN when(); @@ -514,7 +514,7 @@ public void test506ModifyResourceGetAccountJackResourceScripty() throws Exceptio assertSuccess(result); PrismObject resourceAfter = getObject(ResourceType.class, RESOURCE_SCRIPTY_OID); - display("Resource version after", resourceAfter.getVersion()); + displayValue("Resource version after", resourceAfter.getVersion()); assertThat(resourceAfter.getVersion()) .withFailMessage("Resource version is still the same") .isNotEqualTo(resourceBefore.getVersion()); diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/multi/TestMultiResource.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/multi/TestMultiResource.java index 13c83574bc3..9199ef7896e 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/multi/TestMultiResource.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/multi/TestMultiResource.java @@ -1162,7 +1162,7 @@ public void jackUnassignRoleDummiesError( assertUserProperty(USER_JACK_OID, UserType.F_ORGANIZATIONAL_UNIT, PrismTestUtil.createPolyString("The crew of The Lost Souls")); - display("FORCE DELETE", dummyShadowOid); + displayValue("FORCE DELETE", dummyShadowOid); // Force delete of dead shadow forceDeleteShadow(dummyShadowOid); diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/negative/TestAssignmentErrors.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/negative/TestAssignmentErrors.java index 85c291714eb..0cf2d760efc 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/negative/TestAssignmentErrors.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/negative/TestAssignmentErrors.java @@ -483,7 +483,7 @@ public void test220UserAssignAccountDeletedShadowRecomputeSync() throws Exceptio user = getUser(user.getOid()); display("User after", user); String shadowOidAfter = getSingleLinkOid(user); - display("Shadow OID after", shadowOidAfter); + displayValue("Shadow OID after", shadowOidAfter); PrismObject shadowAfter = repositoryService.getObject(ShadowType.class, shadowOidAfter, null, result); display("Shadow after", shadowAfter); @@ -507,7 +507,7 @@ public void test220UserAssignAccountDeletedShadowRecomputeSync() throws Exceptio user = getUser(user.getOid()); display("User after", user); String shadowOidAfterAfter = getSingleLinkOid(user); - display("Shadow OID after the second time", shadowOidAfterAfter); + displayValue("Shadow OID after the second time", shadowOidAfterAfter); assertEquals("The shadow OIDs has changed after second recompute", shadowOidAfter, shadowOidAfterAfter); } @@ -591,7 +591,7 @@ public void test224UserAssignAccountDeletedShadowRecomputeReducedSync() throws E user = getUser(user.getOid()); display("User after", user); String shadowOidAfter = getSingleLinkOid(user); - display("Shadow OID after", shadowOidAfter); + displayValue("Shadow OID after", shadowOidAfter); PrismObject shadowAfter = repositoryService.getObject(ShadowType.class, shadowOidAfter, null, result); display("Shadow after", shadowAfter); @@ -614,7 +614,7 @@ public void test224UserAssignAccountDeletedShadowRecomputeReducedSync() throws E user = getUser(user.getOid()); display("User after", user); String shadowOidAfterAfter = getSingleLinkOid(user); - display("Shadow OID after the second time", shadowOidAfterAfter); + displayValue("Shadow OID after the second time", shadowOidAfterAfter); assertEquals("The shadow OIDs has changed after second recompute", shadowOidAfter, shadowOidAfterAfter); diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/password/AbstractPasswordTest.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/password/AbstractPasswordTest.java index d0c686b3e11..65dd3b4dfcf 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/password/AbstractPasswordTest.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/password/AbstractPasswordTest.java @@ -163,14 +163,14 @@ public void test000Sanity() throws Exception { SystemObjectsType.SYSTEM_CONFIGURATION.value()).asObjectable(); IntegrationTestTools.displayXml("system config", systemConfig.asPrismObject()); for (EventHandlerType handler : systemConfig.getNotificationConfiguration().getHandler()) { - display("Handler: ", handler); + displayValue("Handler: ", handler); List accountActivationNotifiers = handler.getAccountActivationNotifier(); if (!accountActivationNotifiers.isEmpty()) { accountActivationNotifier = accountActivationNotifiers.get(0); } } - display("Account activation notifier", accountActivationNotifier); + displayValue("Account activation notifier", accountActivationNotifier); assertNotNull("No accountActivationNotifier", accountActivationNotifier); } diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/scripting/TestScriptingBasic.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/scripting/TestScriptingBasic.java index 8dc4cd7d194..11db5ad9ddd 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/scripting/TestScriptingBasic.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/scripting/TestScriptingBasic.java @@ -1156,7 +1156,7 @@ public void test600ModifyJackPasswordInBackground() throws Exception { assertEncryptedUserPassword(jack, PASSWORD_PLAINTEXT_1); String xml = prismContext.xmlSerializer().serialize(task.getUpdatedTaskObject()); - display("task", xml); + displayValue("task", xml); assertFalse("Plaintext password is present in the task", xml.contains(PASSWORD_PLAINTEXT_FRAGMENT)); display("Dummy transport", dummyTransport); @@ -1192,7 +1192,7 @@ public void test610ModifyJackPasswordImportingTask() throws Exception { assertEncryptedUserPassword(jack, PASSWORD_PLAINTEXT_2); String xml = prismContext.xmlSerializer().serialize(task.getUpdatedTaskObject()); - display("task", xml); + displayValue("task", xml); assertFalse("Plaintext password is present in the task", xml.contains(PASSWORD_PLAINTEXT_FRAGMENT)); display("Dummy transport", dummyTransport); @@ -1233,7 +1233,7 @@ public void test620ModifyJackPasswordViaExecuteChangesAsynchronously() throws Ex assertEncryptedUserPassword(jack, PASSWORD_PLAINTEXT_3); String xml = prismContext.xmlSerializer().serialize(task.getUpdatedTaskObject()); - display("task", xml); + displayValue("task", xml); assertFalse("Plaintext password is present in the task", xml.contains(PASSWORD_PLAINTEXT_FRAGMENT)); display("Dummy transport", dummyTransport); @@ -1276,11 +1276,11 @@ private void assertAttributesFetched(List data) { private void dumpOutput(ExecutionContext output, OperationResult result) throws JAXBException, SchemaException { display("output", output.getFinalOutput()); - display("stdout", output.getConsoleOutput()); + displayValue("stdout", output.getConsoleOutput()); display(result); if (output.getFinalOutput() != null) { PipelineDataType bean = ModelWebService.prepareXmlData(output.getFinalOutput().getData(), null); - display("output in XML", prismContext.xmlSerializer().root(new QName("output")).serializeRealValue(bean)); + displayValue("output in XML", prismContext.xmlSerializer().root(new QName("output")).serializeRealValue(bean)); } } diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/security/AbstractSecurityTest.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/security/AbstractSecurityTest.java index 6da5e724a9a..0764e01fc25 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/security/AbstractSecurityTest.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/security/AbstractSecurityTest.java @@ -882,7 +882,7 @@ void assertContainerSearch(Class type, ObjectQuery query, try { logAttempt("searchContainers", type, query); List objects = modelService.searchContainers(type, query, options, task, result); - display("Search returned", objects.toString()); + displayValue("Search returned", objects.toString()); if (objects.size() > expectedResults) { failDeny("search", type, query, expectedResults, objects.size()); } else if (objects.size() < expectedResults) { diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/security/TestSecurityAdvanced.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/security/TestSecurityAdvanced.java index 585cf3d7840..9415c3b7186 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/security/TestSecurityAdvanced.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/security/TestSecurityAdvanced.java @@ -761,7 +761,7 @@ public void test150AutzJackApproverUnassignRoles() throws Exception { assertGetDeny(RoleType.class, ROLE_APPROVER_UNASSIGN_ROLES_OID); // assignment exists, but wrong relation PrismObject userRum = assertGetAllow(UserType.class, userRumRogersOid); // member of ROLE_ORDINARY_OID - display("User Rum Rogers", userRumRogersOid); + displayValue("User Rum Rogers", userRumRogersOid); assertRoleMembershipRef(userRum, ROLE_ORDINARY_OID, ROLE_UNINTERESTING_OID, ORG_MINISTRY_OF_RUM_OID); assertGetAllow(UserType.class, userCobbOid); // member of ROLE_ORDINARY_OID assertGetDeny(UserType.class, USER_JACK_OID); // assignment exists, but wrong relation @@ -801,7 +801,7 @@ public void test151AutzJackApproverUnassignRolesAndRead() throws Exception { assertGetAllow(RoleType.class, ROLE_APPROVER_UNASSIGN_ROLES_OID); // assignment exists, but wrong relation PrismObject userRum = assertGetAllow(UserType.class, userRumRogersOid); // member of ROLE_ORDINARY_OID - display("User Rum Rogers", userRumRogersOid); + displayValue("User Rum Rogers", userRumRogersOid); assertRoleMembershipRef(userRum, ROLE_ORDINARY_OID, ROLE_UNINTERESTING_OID, ORG_MINISTRY_OF_RUM_OID); assertGetAllow(UserType.class, userCobbOid); // member of ROLE_ORDINARY_OID PrismObject userJack = assertGetAllow(UserType.class, USER_JACK_OID); // assignment exists, but wrong relation diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/sync/AbstractInboundSyncTest.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/sync/AbstractInboundSyncTest.java index ab4ad95900d..04066765afd 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/sync/AbstractInboundSyncTest.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/sync/AbstractInboundSyncTest.java @@ -105,7 +105,7 @@ public void test110AddDummyEmeraldAccountMancomb() throws Exception { /// WHEN when(); - display("Adding dummy account", account.debugDump()); + displayValue("Adding dummy account", account.debugDump()); dummyResourceEmerald.addAccount(account); @@ -153,7 +153,7 @@ public void test120ModifyDummyEmeraldAccountMancombSeepbad() throws Exception { account.replaceAttributeValue(DummyResourceContoller.DUMMY_ACCOUNT_ATTRIBUTE_FULLNAME_NAME, "Mancomb Seepbad"); - display("Modified dummy account", account.debugDump()); + displayValue("Modified dummy account", account.debugDump()); waitForSyncTaskNextRun(resourceDummyEmerald); @@ -203,7 +203,7 @@ public void test122ModifyDummyEmeraldAccountMancombSeepNULL() throws Exception { account.replaceAttributeValue(DummyResourceContoller.DUMMY_ACCOUNT_ATTRIBUTE_FULLNAME_NAME, "Mancomb SeepNULL"); - display("Modified dummy account", account.debugDump()); + displayValue("Modified dummy account", account.debugDump()); waitForSyncTaskNextRun(resourceDummyEmerald); @@ -253,7 +253,7 @@ public void test124ModifyDummyEmeraldAccountMancombSeepevil() throws Exception { account.replaceAttributeValue(DummyResourceContoller.DUMMY_ACCOUNT_ATTRIBUTE_FULLNAME_NAME, "Mancomb Seepevil"); - display("Modified dummy account", account.debugDump()); + displayValue("Modified dummy account", account.debugDump()); waitForSyncTaskNextRun(resourceDummyEmerald); @@ -303,7 +303,7 @@ public void test126ModifyDummyEmeraldAccountMancombTitlePirate() throws Exceptio account.replaceAttributeValues(DummyResourceContoller.DUMMY_ACCOUNT_ATTRIBUTE_TITLE_NAME, "Pirate"); - display("Modified dummy account", account.debugDump()); + displayValue("Modified dummy account", account.debugDump()); waitForSyncTaskNextRun(resourceDummyEmerald); @@ -354,7 +354,7 @@ public void test127ModifyDummyEmeraldAccountMancombTitlePirateNull() throws Exce account.replaceAttributeValues(DummyResourceContoller.DUMMY_ACCOUNT_ATTRIBUTE_TITLE_NAME); - display("Modified dummy account", account.debugDump()); + displayValue("Modified dummy account", account.debugDump()); waitForSyncTaskNextRun(resourceDummyEmerald); @@ -405,7 +405,7 @@ public void test129ModifyDummyEmeraldAccountMancombSeepgood() throws Exception { account.replaceAttributeValue(DummyResourceContoller.DUMMY_ACCOUNT_ATTRIBUTE_FULLNAME_NAME, "Mancomb Seepgood"); - display("Modified dummy account", account.debugDump()); + displayValue("Modified dummy account", account.debugDump()); waitForSyncTaskNextRun(resourceDummyEmerald); @@ -468,7 +468,7 @@ public void test300AddDummyEmeraldAccountPosixUser() throws Exception { /// WHEN when(); - display("Adding dummy account", account.debugDump()); + displayValue("Adding dummy account", account.debugDump()); dummyResourceEmerald.addAccount(account); @@ -517,7 +517,7 @@ public void test310ModifyDummyEmeraldAccountPosixUserUidNumber() throws Exceptio account.replaceAttributeValue(DummyResourceContoller.DUMMY_ACCOUNT_ATTRIBUTE_POSIX_UID_NUMBER, 1002); - display("Modified dummy account", account.debugDump()); + displayValue("Modified dummy account", account.debugDump()); waitForSyncTaskNextRun(resourceDummyEmerald); diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/sync/AbstractObjTemplateSyncTest.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/sync/AbstractObjTemplateSyncTest.java index 0ce064131c5..6f003fe41fb 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/sync/AbstractObjTemplateSyncTest.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/sync/AbstractObjTemplateSyncTest.java @@ -133,7 +133,7 @@ public void test110AddDummyByzantineAccountMancomb() throws Exception { /// WHEN when(); - display("Adding dummy account", account.debugDump()); + displayValue("Adding dummy account", account.debugDump()); dummyResourceByzantine.addAccount(account); diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/sync/AbstractSynchronizationStoryTest.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/sync/AbstractSynchronizationStoryTest.java index ab794602987..012fe3e19a4 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/sync/AbstractSynchronizationStoryTest.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/sync/AbstractSynchronizationStoryTest.java @@ -639,7 +639,7 @@ public void test400DeleteDummyDefaultAccount() throws Exception { when(); getDummyResource().deleteAccountByName(ACCOUNT_WALLY_DUMMY_USERNAME); - display("Dummy (default) resource", getDummyResource().debugDump()); + displayValue("Dummy (default) resource", getDummyResource().debugDump()); // Make sure we have steady state waitForSyncTaskNextRunAssertSuccess(getDummyResourceObject()); diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/sync/TestImportRecon.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/sync/TestImportRecon.java index d15b4f1e996..5bbe5e4849e 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/sync/TestImportRecon.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/sync/TestImportRecon.java @@ -859,7 +859,7 @@ public void test200ReconcileDummy() throws Exception { assertEquals("Unexpected number of users", getNumberOfUsers() + 4, users.size()); - display("Dummy resource", getDummyResource().debugDump()); + displayValue("Dummy resource", getDummyResource().debugDump()); display("Script history", getDummyResource().getScriptHistory()); @@ -927,7 +927,7 @@ public void test210ReconcileDummyBroken() throws Exception { assertEquals("Unexpected number of users", getNumberOfUsers() + 4, users.size()); - display("Dummy resource", getDummyResource().debugDump()); + displayValue("Dummy resource", getDummyResource().debugDump()); display("Script history", getDummyResource().getScriptHistory()); @@ -1007,7 +1007,7 @@ public void test219ReconcileDummyFixed() throws Exception { assertEquals("Unexpected number of users", getNumberOfUsers() + 4, users.size()); - display("Dummy resource", getDummyResource().debugDump()); + displayValue("Dummy resource", getDummyResource().debugDump()); display("Script history", getDummyResource().getScriptHistory()); @@ -1089,7 +1089,7 @@ public void test220ReconcileDummyBrokenGuybrush() throws Exception { assertEquals("Unexpected number of users", getNumberOfUsers() + 4, users.size()); - display("Dummy resource", getDummyResource().debugDump()); + displayValue("Dummy resource", getDummyResource().debugDump()); display("Script history", getDummyResource().getScriptHistory()); ArrayList scripts = new ArrayList<>(); @@ -1178,7 +1178,7 @@ public void test229ReconcileDummyFixed() throws Exception { assertEquals("Unexpected number of users", getNumberOfUsers() + 4, users.size()); - display("Dummy resource", getDummyResource().debugDump()); + displayValue("Dummy resource", getDummyResource().debugDump()); display("Script history", getDummyResource().getScriptHistory()); @@ -1284,7 +1284,7 @@ public void test230ReconcileDummyRename() throws Exception { assertEquals("Unexpected number of users", getNumberOfUsers() + 5, users.size()); - display("Dummy resource", getDummyResource().debugDump()); + displayValue("Dummy resource", getDummyResource().debugDump()); display("Script history", getDummyResource().getScriptHistory()); @@ -1394,7 +1394,7 @@ public void test300ReconcileDummyAzureAddAccountOtis() throws Exception { assertEquals("Unexpected number of users", getNumberOfUsers() + 5, users.size()); - display("Dummy resource (azure)", dummyResourceAzure.debugDump()); + displayValue("Dummy resource (azure)", dummyResourceAzure.debugDump()); assertReconAuditModifications(1, TASK_RECONCILE_DUMMY_AZURE.oid); @@ -1459,7 +1459,7 @@ public void test310ReconcileDummyAzureAgain() throws Exception { assertEquals("Unexpected number of users", getNumberOfUsers() + 5, users.size()); - display("Dummy resource (azure)", dummyResourceAzure.debugDump()); + displayValue("Dummy resource (azure)", dummyResourceAzure.debugDump()); assertReconAuditModifications(0, TASK_RECONCILE_DUMMY_AZURE.oid); @@ -1528,7 +1528,7 @@ public void test320ReconcileDummyAzureDeleteOtis() throws Exception { assertEquals("Unexpected number of users", getNumberOfUsers() + 5, users.size()); - display("Dummy resource (azure)", dummyResourceAzure.debugDump()); + displayValue("Dummy resource (azure)", dummyResourceAzure.debugDump()); assertReconAuditModifications(0, TASK_RECONCILE_DUMMY_AZURE.oid); } @@ -1625,7 +1625,7 @@ public void test330ReconcileDummyAzureAddAccountRapp() throws Exception { assertEquals("Unexpected number of users", getNumberOfUsers() + 5, users.size()); - display("Dummy resource (azure)", dummyResourceAzure.debugDump()); + displayValue("Dummy resource (azure)", dummyResourceAzure.debugDump()); assertReconAuditModifications(1, TASK_RECONCILE_DUMMY_AZURE.oid); } @@ -1706,7 +1706,7 @@ public void test332ModifyUserRappAndReconcileDummyAzure() throws Exception { assertEquals("Unexpected number of users", getNumberOfUsers() + 5, users.size()); - display("Dummy resource (azure)", dummyResourceAzure.debugDump()); + displayValue("Dummy resource (azure)", dummyResourceAzure.debugDump()); assertReconAuditModifications(2, TASK_RECONCILE_DUMMY_AZURE.oid); } @@ -1779,7 +1779,7 @@ public void test334AssignRoleCorpseToRappAndReconcileDummyAzure() throws Excepti assertEquals("Unexpected number of users", getNumberOfUsers() + 5, users.size()); - display("Dummy resource (azure)", dummyResourceAzure.debugDump()); + displayValue("Dummy resource (azure)", dummyResourceAzure.debugDump()); assertReconAuditModifications(1, TASK_RECONCILE_DUMMY_AZURE.oid); } @@ -1853,7 +1853,7 @@ public void test339ReconcileDummyAzureDeleteRapp() throws Exception { assertEquals("Unexpected number of users", getNumberOfUsers() + 5, users.size()); - display("Dummy resource (azure)", dummyResourceAzure.debugDump()); + displayValue("Dummy resource (azure)", dummyResourceAzure.debugDump()); // deleting linkRef assertReconAuditModifications(1, TASK_RECONCILE_DUMMY_AZURE.oid); @@ -1906,7 +1906,7 @@ public void test400ReconcileDummyLimeAddAccount() throws Exception { assertEquals("Unexpected number of users", getNumberOfUsers() + 6, users.size()); - display("Dummy resource (lime)", dummyResourceLime.debugDump()); + displayValue("Dummy resource (lime)", dummyResourceLime.debugDump()); // Audit record structure is somehow complex here. // assertReconAuditModifications(4, TASK_RECONCILE_DUMMY_LIME.oid); @@ -1955,7 +1955,7 @@ public void test401ReconcileDummyLimeKateOnlyEmpty() throws Exception { assertUsers(getNumberOfUsers() + 6); - display("Dummy resource (lime)", dummyResourceLime.debugDump()); + displayValue("Dummy resource (lime)", dummyResourceLime.debugDump()); } @Test @@ -2000,7 +2000,7 @@ public void test402ReconcileDummyLimeKateOnlyGrog() throws Exception { assertUsers(getNumberOfUsers() + 6); - display("Dummy resource (lime)", dummyResourceLime.debugDump()); + displayValue("Dummy resource (lime)", dummyResourceLime.debugDump()); } @Test @@ -2012,7 +2012,7 @@ public void test403ReconcileDummyLimeKateOnlyNoValue() throws Exception { DummyAccount accountKate = dummyResourceLime.getAccountByUsername(ACCOUNT_CAPSIZE_NAME); accountKate.replaceAttributeValues(DummyResourceContoller.DUMMY_ACCOUNT_ATTRIBUTE_DRINK_NAME); - display("Dummy resource (lime)", dummyResourceLime.debugDump()); + displayValue("Dummy resource (lime)", dummyResourceLime.debugDump()); PrismObject userBefore = findUserByUsername(ACCOUNT_CAPSIZE_NAME); @@ -2089,7 +2089,7 @@ public void test404ReconcileDummyLimeKateOnlyRum() throws Exception { assertUsers(getNumberOfUsers() + 6); - display("Dummy resource (lime)", dummyResourceLime.debugDump()); + displayValue("Dummy resource (lime)", dummyResourceLime.debugDump()); } @Test @@ -2134,7 +2134,7 @@ public void test405ReconcileDummyLimeKateOnlyEmpty() throws Exception { assertUsers(getNumberOfUsers() + 6); - display("Dummy resource (lime)", dummyResourceLime.debugDump()); + displayValue("Dummy resource (lime)", dummyResourceLime.debugDump()); } @Test @@ -2174,7 +2174,7 @@ public void test406ReconcileDummyLimeKateOnlyEmptyAgain() throws Exception { assertUsers(getNumberOfUsers() + 6); - display("Dummy resource (lime)", dummyResourceLime.debugDump()); + displayValue("Dummy resource (lime)", dummyResourceLime.debugDump()); } @Test @@ -2218,7 +2218,7 @@ public void test410ReconcileDummyLimeKatePassword() throws Exception { assertUsers(getNumberOfUsers() + 6); - display("Dummy resource (lime)", dummyResourceLime.debugDump()); + displayValue("Dummy resource (lime)", dummyResourceLime.debugDump()); } @Test @@ -2265,7 +2265,7 @@ public void test420ReconcileDummyLimeDeleteLinkedAccount() throws Exception { assertEquals("Unexpected number of users", getNumberOfUsers() + 5, users.size()); - display("Dummy resource (lime)", dummyResourceLime.debugDump()); + displayValue("Dummy resource (lime)", dummyResourceLime.debugDump()); // Audit record structure is somehow complex here. // assertReconAuditModifications(4, TASK_RECONCILE_DUMMY_LIME.oid); diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/sync/TestLiveSyncTaskMechanics.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/sync/TestLiveSyncTaskMechanics.java index 7793f546d58..154855dfb18 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/sync/TestLiveSyncTaskMechanics.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/sync/TestLiveSyncTaskMechanics.java @@ -241,8 +241,8 @@ public void test110SuspendWhileProcessing() throws Exception { assertTrue("Token value is zero (should be greater)", token != null && token > 0); int progress = (int) taskAfter.getProgress(); - display("Token value", token); - display("Task progress", progress); + displayValue("Token value", token); + displayValue("Task progress", progress); if (getWorkerThreads() <= 1) { assertEquals("Wrong task progress", token, (Integer) progress); } else { @@ -289,11 +289,11 @@ public void test115SuspendWhileProcessingImprecise() throws Exception { displayTaskWithOperationStats("Task after", taskAfter); Integer token = taskAfter.getExtensionPropertyRealValue(SchemaConstants.SYNC_TOKEN); - display("Token value", token); + displayValue("Token value", token); assertEquals("Wrong token value", (Integer) 0, token); int progress = (int) taskAfter.getProgress(); - display("Task progress", progress); + displayValue("Task progress", progress); assertObjects(UserType.class, getStartsWithQuery(USER_I), progress); } @@ -626,7 +626,7 @@ public void test200NoPolicy() throws Exception { Task taskAfter = taskManager.getTaskWithResult(TASK_NO_POLICY.oid, result); display("Task after", taskAfter); SynchronizationInformationType syncInfo = taskAfter.getStoredOperationStats().getSynchronizationInformation(); - display("Sync info", SynchronizationInformation.format(syncInfo)); + displayValue("Sync info", SynchronizationInformation.format(syncInfo)); assertSuccess(taskAfter.getResult()); assertTaskClosed(taskAfter); diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/sync/TestProgressReporting.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/sync/TestProgressReporting.java index 9a343a267c4..65d5c7800b4 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/sync/TestProgressReporting.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/sync/TestProgressReporting.java @@ -105,7 +105,7 @@ private void executeReconciliation(TestResource reconciliationTask, String accou .item(TaskType.F_SUBTASK_REF).retrieve() .build(); PrismObject rootAfterSuspension1 = taskManager.getObject(TaskType.class, reconciliationTask.oid, getSubtasks, result); - display("Tree after suspension", TaskDebugUtil.dumpTaskTree(rootAfterSuspension1.asObjectable())); + displayValue("Tree after suspension", TaskDebugUtil.dumpTaskTree(rootAfterSuspension1.asObjectable())); TaskProgressExtract progress1 = TaskProgressExtract.fromTask(rootAfterSuspension1.asObjectable()); display("Progress after suspension", progress1); @@ -122,7 +122,7 @@ private void executeReconciliation(TestResource reconciliationTask, String accou System.out.println("Task tree suspended."); PrismObject rootAfterSuspension2 = taskManager.getObject(TaskType.class, reconciliationTask.oid, getSubtasks, result); - display("Tree after second suspension", TaskDebugUtil.dumpTaskTree(rootAfterSuspension2.asObjectable())); + displayValue("Tree after second suspension", TaskDebugUtil.dumpTaskTree(rootAfterSuspension2.asObjectable())); TaskProgressExtract progress2 = TaskProgressExtract.fromTask(rootAfterSuspension2.asObjectable()); display("Progress after second suspension", progress2); @@ -192,7 +192,7 @@ private void executeRecomputation(TestResource recomputationTask, String rolePre .item(TaskType.F_SUBTASK_REF).retrieve() .build(); PrismObject rootAfterSuspension1 = taskManager.getObject(TaskType.class, recomputationTask.oid, getSubtasks, result); - display("Tree after suspension", TaskDebugUtil.dumpTaskTree(rootAfterSuspension1.asObjectable())); + displayValue("Tree after suspension", TaskDebugUtil.dumpTaskTree(rootAfterSuspension1.asObjectable())); TaskProgressExtract progress1 = TaskProgressExtract.fromTask(rootAfterSuspension1.asObjectable()); display("Progress after suspension", progress1); @@ -209,7 +209,7 @@ private void executeRecomputation(TestResource recomputationTask, String rolePre System.out.println("Task tree suspended."); PrismObject rootAfterSuspension2 = taskManager.getObject(TaskType.class, recomputationTask.oid, getSubtasks, result); - display("Tree after second suspension", TaskDebugUtil.dumpTaskTree(rootAfterSuspension2.asObjectable())); + displayValue("Tree after second suspension", TaskDebugUtil.dumpTaskTree(rootAfterSuspension2.asObjectable())); TaskProgressExtract progress2 = TaskProgressExtract.fromTask(rootAfterSuspension2.asObjectable()); display("Progress after second suspension", progress2); diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/sync/TestUuid.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/sync/TestUuid.java index 0e3dd4948cb..4dd84882ae0 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/sync/TestUuid.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/sync/TestUuid.java @@ -131,7 +131,7 @@ public void test200ReconcileDummyUuid() throws Exception { assertEquals("Unexpected number of users", 6, users.size()); - display("Dummy resource", getDummyResource().debugDump()); + displayValue("Dummy resource", getDummyResource().debugDump()); assertReconAuditModifications(0, TASK_RECONCILE_DUMMY_UUID_OID); @@ -187,7 +187,7 @@ public void test210ReconcileDummyUuidAddAugustus() throws Exception { assertEquals("Unexpected number of users", 7, users.size()); - display("Dummy resource", getDummyResource().debugDump()); + displayValue("Dummy resource", getDummyResource().debugDump()); assertReconAuditModifications(1, TASK_RECONCILE_DUMMY_UUID_OID); @@ -230,7 +230,7 @@ public void test220ReconcileDummyUuidDeleteAddAugustus() throws Exception { assertFalse("Account IDs not changed", oldAccount.getId().equals(newAccount.getId())); - display("Old shadow OID", augustusShadowOid); + displayValue("Old shadow OID", augustusShadowOid); display("Account ID " + oldAccount.getId() + " -> " + newAccount.getId()); Task taskBefore = taskManager.getTaskPlain(TASK_RECONCILE_DUMMY_UUID_OID, result); @@ -266,7 +266,7 @@ public void test220ReconcileDummyUuidDeleteAddAugustus() throws Exception { assertEquals("Unexpected number of users", 7, users.size()); - display("Dummy resource", getDummyResource().debugDump()); + displayValue("Dummy resource", getDummyResource().debugDump()); assertReconAuditModifications(1, TASK_RECONCILE_DUMMY_UUID_OID); @@ -315,7 +315,7 @@ public void test230ReconcileDummyUuidDeleteAugustusAddAugustina() throws Excepti assertFalse("Account IDs not changed", oldAccount.getId().equals(account.getId())); - display("Old shadow OID", augustusShadowOid); + displayValue("Old shadow OID", augustusShadowOid); display("Account ID " + oldAccount.getId() + " -> " + account.getId()); Task taskBefore = taskManager.getTaskPlain(TASK_RECONCILE_DUMMY_UUID_OID, result); @@ -351,7 +351,7 @@ public void test230ReconcileDummyUuidDeleteAugustusAddAugustina() throws Excepti assertEquals("Unexpected number of users", 7, users.size()); - display("Dummy resource", getDummyResource().debugDump()); + displayValue("Dummy resource", getDummyResource().debugDump()); assertReconAuditModifications(1, TASK_RECONCILE_DUMMY_UUID_OID); diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/sync/TestValidityRecomputeTask.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/sync/TestValidityRecomputeTask.java index cc75bbd1946..77ec9825fe0 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/sync/TestValidityRecomputeTask.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/sync/TestValidityRecomputeTask.java @@ -1456,7 +1456,7 @@ public void test215JackDummyAccountDeleteAfterMonth() throws Exception { @Test public void test220AddDrake() throws Exception { XMLGregorianCalendar start = clock.currentTimeXMLGregorianCalendar(); - display("Start", start); + displayValue("Start", start); PrismObject userDrake = PrismTestUtil.parseObject(USER_DRAKE_FILE); UserType userDrakeType = userDrake.asObjectable(); @@ -1521,7 +1521,7 @@ public void test222Drake4DaysBeforeValidFrom() throws Exception { XMLGregorianCalendar start = (XMLGregorianCalendar) drakeValidFrom.clone(); start.add(XmlTypeConverter.createDuration(false, 0, 0, 4, 0, 0, 0)); clock.override(start); - display("Start", start); + displayValue("Start", start); // WHEN // just wait @@ -1546,7 +1546,7 @@ public void test224Drake1DaysAfterValidFrom() throws Exception { XMLGregorianCalendar start = (XMLGregorianCalendar) drakeValidFrom.clone(); start.add(XmlTypeConverter.createDuration(true, 0, 0, 1, 0, 0, 0)); clock.override(start); - display("Start", start); + displayValue("Start", start); // WHEN // just wait @@ -1570,7 +1570,7 @@ public void test226Drake1DayBeforeValidTo() throws Exception { XMLGregorianCalendar start = (XMLGregorianCalendar) drakeValidTo.clone(); start.add(XmlTypeConverter.createDuration(false, 0, 0, 1, 0, 0, 0)); clock.override(start); - display("Start", start); + displayValue("Start", start); // WHEN // just wait @@ -1594,7 +1594,7 @@ public void test228Drake1DayAfterValidTo() throws Exception { XMLGregorianCalendar start = (XMLGregorianCalendar) drakeValidTo.clone(); start.add(XmlTypeConverter.createDuration(true, 0, 0, 1, 0, 0, 0)); clock.override(start); - display("Start", start); + displayValue("Start", start); // WHEN // just wait @@ -1619,7 +1619,7 @@ public void test230Drake20DaysAfterValidTo() throws Exception { XMLGregorianCalendar start = (XMLGregorianCalendar) drakeValidTo.clone(); start.add(XmlTypeConverter.createDuration(true, 0, 0, 20, 0, 0, 0)); clock.override(start); - display("Start", start); + displayValue("Start", start); // WHEN // just wait @@ -1644,7 +1644,7 @@ public void test232Drake40DaysAfterValidTo() throws Exception { XMLGregorianCalendar start = (XMLGregorianCalendar) drakeValidTo.clone(); start.add(XmlTypeConverter.createDuration(true, 0, 0, 40, 0, 0, 0)); clock.override(start); - display("Start", start); + displayValue("Start", start); // WHEN // just wait @@ -1694,8 +1694,8 @@ public void test300HermanAssignJudgeNotYetValid() throws Exception { judgeAssignmentValidTo = clock.currentTimeXMLGregorianCalendar(); judgeAssignmentValidTo.add(XmlTypeConverter.createDuration(30 * 60 * 1000)); // 30 minutes ahead activationType.setValidTo(judgeAssignmentValidTo); - display("Assignment validFrom", judgeAssignmentValidFrom); - display("Assignment validTo", judgeAssignmentValidTo); + displayValue("Assignment validFrom", judgeAssignmentValidFrom); + displayValue("Assignment validTo", judgeAssignmentValidTo); // WHEN when(); @@ -1714,7 +1714,7 @@ public void test310HermanAssignJudgeBecomesValid() throws Exception { XMLGregorianCalendar start = (XMLGregorianCalendar) judgeAssignmentValidFrom.clone(); start.add(XmlTypeConverter.createDuration(60 * 1000)); clock.override(start); - display("Start", start); + displayValue("Start", start); // WHEN // just wait @@ -1729,7 +1729,7 @@ public void test315HermanAssignJudgeBecomesInValid() throws Exception { XMLGregorianCalendar start = (XMLGregorianCalendar) judgeAssignmentValidTo.clone(); start.add(XmlTypeConverter.createDuration(Duration.ofMinutes(1).toMillis())); clock.override(start); - display("Start", start); + displayValue("Start", start); // WHEN // just wait 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 042e29b75fe..ff14563687e 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 @@ -478,7 +478,7 @@ protected void searchObjectsIterative(Class type, } return true; }, null, task, result); - if (verbose) { display(type.getSimpleName() + "s", count.getValue()); } + if (verbose) { displayValue(type.getSimpleName() + "s", count.getValue()); } assertEquals("Unexpected number of " + type.getSimpleName() + "s", expectedNumberOfObjects, count.getValue()); } @@ -2437,7 +2437,7 @@ protected void dumpFocus(String message, PrismObject fo sb.append(target); } } - display(message, sb.toString()); + displayValue(message, sb.toString()); } protected void assertAssignments(PrismObject user, int expectedNumber) { @@ -3100,7 +3100,7 @@ protected void dumpTaskTree(String oid, OperationResult result) protected void dumpTaskAndSubtasks(TaskType task, int level) throws SchemaException { String xml = prismContext.xmlSerializer().serialize(task.asPrismObject()); - display("Task (level " + level + ")", xml); + displayValue("Task (level " + level + ")", xml); for (TaskType subtask : TaskTypeUtil.getResolvedSubtasks(task)) { dumpTaskAndSubtasks(subtask, level + 1); } @@ -3125,7 +3125,7 @@ protected long getTreeRunDurationMillis(String rootTaskOid) throws ObjectNotFoun } protected void displayOperationStatistics(OperationStatsType statistics) { - display("Task operation statistics for " + getTestNameShort(), StatisticsUtil.format(statistics)); + displayValue("Task operation statistics for " + getTestNameShort(), StatisticsUtil.format(statistics)); } @Nullable @@ -3159,14 +3159,14 @@ protected void displayTaskWithOperationStats(String message, PrismObject clazz, String oid, byte[] expectedValue, OperationResult result) @@ -3339,7 +3339,7 @@ public void timeout() { Task freshTask = taskManager.getTaskWithResult(origTask.getOid(), waitResult); OperationResult result = freshTask.getResult(); logger.debug("Timed-out task:\n{}", freshTask.debugDump()); - display("Times", "origLastRunStartTimestamp=" + longTimeToString(origLastRunStartTimestamp) + displayValue("Times", "origLastRunStartTimestamp=" + longTimeToString(origLastRunStartTimestamp) + ", origLastRunFinishTimestamp=" + longTimeToString(origLastRunFinishTimestamp) + ", freshTask.getLastRunStartTimestamp()=" + longTimeToString(freshTask.getLastRunStartTimestamp()) + ", freshTask.getLastRunFinishTimestamp()=" + longTimeToString(freshTask.getLastRunFinishTimestamp())); @@ -3353,7 +3353,7 @@ public void timeout() { Task freshTask = taskManager.getTaskWithResult(origTask.getOid(), waitResult); logger.debug("Final task:\n{}", freshTask.debugDump()); - display("Times", "origLastRunStartTimestamp=" + longTimeToString(origLastRunStartTimestamp) + displayValue("Times", "origLastRunStartTimestamp=" + longTimeToString(origLastRunStartTimestamp) + ", origLastRunFinishTimestamp=" + longTimeToString(origLastRunFinishTimestamp) + ", freshTask.getLastRunStartTimestamp()=" + longTimeToString(freshTask.getLastRunStartTimestamp()) + ", freshTask.getLastRunFinishTimestamp()=" + longTimeToString(freshTask.getLastRunFinishTimestamp())); @@ -3378,7 +3378,7 @@ protected OperationResult waitForTaskTreeNextFinishedRun(Task origRootTask, int Task freshRootTask = taskManager.getTaskWithResult(origRootTask.getOid(), waitResult); String s = TaskDebugUtil.dumpTaskTree(freshRootTask, waitResult); - display("task tree", s); + displayValue("task tree", s); long waiting = (System.currentTimeMillis() - start) / 1000; String description = @@ -3549,7 +3549,7 @@ public void timeout() { Task freshTask = taskManager.getTaskWithResult(origTask.getOid(), waitResult); OperationResult result = freshTask.getResult(); logger.debug("Timed-out task:\n{}", freshTask.debugDump()); - display("Times", "origLastRunStartTimestamp=" + longTimeToString(origLastRunStartTimestamp) + displayValue("Times", "origLastRunStartTimestamp=" + longTimeToString(origLastRunStartTimestamp) + ", origLastRunFinishTimestamp=" + longTimeToString(origLastRunFinishTimestamp) + ", freshTask.getLastRunStartTimestamp()=" + longTimeToString(freshTask.getLastRunStartTimestamp()) + ", freshTask.getLastRunFinishTimestamp()=" + longTimeToString(freshTask.getLastRunFinishTimestamp())); @@ -3563,7 +3563,7 @@ public void timeout() { Task freshTask = taskManager.getTaskWithResult(origTask.getOid(), waitResult); logger.debug("Final task:\n{}", freshTask.debugDump()); - display("Times", "origLastRunStartTimestamp=" + longTimeToString(origLastRunStartTimestamp) + displayValue("Times", "origLastRunStartTimestamp=" + longTimeToString(origLastRunStartTimestamp) + ", origLastRunFinishTimestamp=" + longTimeToString(origLastRunFinishTimestamp) + ", freshTask.getLastRunStartTimestamp()=" + longTimeToString(freshTask.getLastRunStartTimestamp()) + ", freshTask.getLastRunFinishTimestamp()=" + longTimeToString(freshTask.getLastRunFinishTimestamp())); @@ -5343,10 +5343,10 @@ protected void assertFocusModificationSanity(ModelContext< for (Object valueToDelete : itemMod.getValuesToDelete()) { if (!property.contains((PrismValue) valueToDelete, EquivalenceStrategy.REAL_VALUE)) { display("Deleted value " + valueToDelete + " is not in focus item " + itemMod.getParentPath() + "/" + itemMod.getElementName()); - display("Deleted value", valueToDelete); + displayValue("Deleted value", valueToDelete); display("HASHCODE: " + valueToDelete.hashCode()); for (Object value : property.getValues()) { - display("Existing value", value); + displayValue("Existing value", value); display("EQUALS: " + valueToDelete.equals(value)); display("HASHCODE: " + value.hashCode()); } @@ -5473,11 +5473,11 @@ protected PrismObject getOrg(String orgName) throws SchemaException, Ob } protected void dumpOrgTree() throws SchemaException, ObjectNotFoundException, SecurityViolationException, CommunicationException, ConfigurationException, ExpressionEvaluationException { - display("Org tree", dumpOrgTree(getTopOrgOid())); + displayValue("Org tree", dumpOrgTree(getTopOrgOid())); } protected void dumpOrgTreeAndUsers() throws SchemaException, ObjectNotFoundException, SecurityViolationException, CommunicationException, ConfigurationException, ExpressionEvaluationException { - display("Org tree", dumpOrgTree(getTopOrgOid(), true)); + displayValue("Org tree", dumpOrgTree(getTopOrgOid(), true)); } protected String getTopOrgOid() { @@ -5546,7 +5546,7 @@ protected void assertPasswordCompliesWithPolicy( protected void assertPasswordCompliesWithPolicy(PrismObject user, String passwordPolicyOid, Task task, OperationResult result) throws EncryptionException, ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException, SecurityViolationException { String password = getPassword(user); - display("Password of " + user, password); + displayValue("Password of " + user, password); PrismObject passwordPolicy = repositoryService.getObject(ValuePolicyType.class, passwordPolicyOid, null, result); List messages = new ArrayList<>(); boolean valid = valuePolicyProcessor.validateValue(password, passwordPolicy.asObjectable(), createUserOriginResolver(user), messages, "validating password of " + user, task, result); @@ -6134,7 +6134,7 @@ protected SearchResultList> assertSearch(C try { logAttempt("search", type, query); objects = modelService.searchObjects(type, query, options, task, result); - display("Search returned", objects.toString()); + displayValue("Search returned", objects.toString()); assertion.assertObjects("search", objects); assertSuccess(result); } catch (SecurityViolationException e) { @@ -6155,7 +6155,7 @@ protected SearchResultList> assertSearch(C return true; }; modelService.searchObjectsIterative(type, query, handler, options, task, result); - display("Search iterative returned", iterativeObjects.toString()); + displayValue("Search iterative returned", iterativeObjects.toString()); assertion.assertObjects("searchIterative", iterativeObjects); assertSuccess(result); } catch (SecurityViolationException e) { @@ -6171,7 +6171,7 @@ protected SearchResultList> assertSearch(C try { logAttempt("count", type, query); int numObjects = modelService.countObjects(type, query, options, task, result); - display("Count returned", numObjects); + displayValue("Count returned", numObjects); assertion.assertCount(numObjects); assertSuccess(result); } catch (SecurityViolationException e) { @@ -6517,9 +6517,9 @@ protected ExpressionVariables createVariables(Object... params) { protected void dumpStatistics(Task task) { OperationStatsType stats = task.getStoredOperationStats(); IterativeTaskInformationType iterativeInfo = stats.getIterativeTaskInformation(); - display("Iterative information", IterativeTaskInformation.format(iterativeInfo)); + displayValue("Iterative information", IterativeTaskInformation.format(iterativeInfo)); SynchronizationInformationType synchronizationInfo = stats.getSynchronizationInformation(); - display("Synchronization information", SynchronizationInformation.format(synchronizationInfo)); + displayValue("Synchronization information", SynchronizationInformation.format(synchronizationInfo)); } protected void dumpShadowSituations(String resourceOid, OperationResult result) throws SchemaException { 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 ee84e984c39..3c6398edaf5 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 @@ -262,7 +262,7 @@ public void test050FormatDeltaWithOperAndAuxItems() throws Exception { given(); PrismObject jack = PrismTestUtil.parseObject(new File(USER_JACK_FILE)); - display("jack", jack.debugDump()); + displayValue("jack", jack.debugDump()); // @formatter:off ObjectDelta delta = prismContext.deltaFor(UserType.class) @@ -273,7 +273,7 @@ public void test050FormatDeltaWithOperAndAuxItems() throws Exception { .asObjectDelta("some-user-oid"); // @formatter:on - display("delta", delta.debugDump()); + displayValue("delta", delta.debugDump()); when(); @@ -314,7 +314,7 @@ public void test060FormatDeltaWithSingleOperationalItemContainer() throws Except given(); PrismObject jack = PrismTestUtil.parseObject(new File(USER_JACK_FILE)); - display("jack", jack.debugDump()); + displayValue("jack", jack.debugDump()); // @formatter:off ObjectDelta delta = prismContext.deltaFor(UserType.class) @@ -326,7 +326,7 @@ public void test060FormatDeltaWithSingleOperationalItemContainer() throws Except .asObjectDelta("some-user-oid"); // @formatter:on - display("delta", delta.debugDump()); + displayValue("delta", delta.debugDump()); when(); diff --git a/model/report-impl/src/test/java/com/evolveum/midpoint/report/TestReport.java b/model/report-impl/src/test/java/com/evolveum/midpoint/report/TestReport.java index 48a8b32f902..96a10bff8fe 100644 --- a/model/report-impl/src/test/java/com/evolveum/midpoint/report/TestReport.java +++ b/model/report-impl/src/test/java/com/evolveum/midpoint/report/TestReport.java @@ -211,23 +211,23 @@ protected PrismObject runReport(PrismObject report, boolea protected void checkCsvUserReport(PrismObject report) throws IOException, SchemaException, ObjectNotFoundException, SecurityViolationException, CommunicationException, ConfigurationException, ExpressionEvaluationException { File outputFile = findOutputFile(report); - display("Found report file", outputFile); + displayValue("Found report file", outputFile); assertNotNull("No output file for "+report, outputFile); List lines = Files.readAllLines(Paths.get(outputFile.getPath())); - display("Report content ("+lines.size()+" lines)", String.join("\n", lines)); + displayValue("Report content ("+lines.size()+" lines)", String.join("\n", lines)); outputFile.renameTo(new File(outputFile.getParentFile(), "processed-"+outputFile.getName())); Task task = getTestTask(); OperationResult result = task.getResult(); SearchResultList> currentUsers = modelService.searchObjects(UserType.class, null, null, task, result); - display("Current users in midPoint ("+currentUsers.size()+" users)", currentUsers.toString()); + displayValue("Current users in midPoint ("+currentUsers.size()+" users)", currentUsers.toString()); assertEquals("Unexpected number of report lines", currentUsers.size() + 1, lines.size()); } protected void assertNoCsvReport(PrismObject report) { File outputFile = findOutputFile(report); - display("Found report file (expected null)", outputFile); + displayValue("Found report file (expected null)", outputFile); assertNull("Unexpected output file for "+report+": "+outputFile, outputFile); } @@ -254,10 +254,10 @@ protected void testReportAuditCsvFailure(String reportOid) throws Exception { protected void checkCsvAuditReport(PrismObject report) throws IOException { File outputFile = findOutputFile(report); - display("Found report file", outputFile); + displayValue("Found report file", outputFile); assertNotNull("No output file for "+report, outputFile); List lines = Files.readAllLines(Paths.get(outputFile.getPath())); - display("Report content ("+lines.size()+" lines)", String.join("\n", lines)); + displayValue("Report content ("+lines.size()+" lines)", String.join("\n", lines)); outputFile.renameTo(new File(outputFile.getParentFile(), "processed-"+outputFile.getName())); if (lines.size() < 10) { diff --git a/model/report-impl/src/test/java/com/evolveum/midpoint/report/TestReportWebService.java b/model/report-impl/src/test/java/com/evolveum/midpoint/report/TestReportWebService.java index b2ef7806060..f6584446cc4 100644 --- a/model/report-impl/src/test/java/com/evolveum/midpoint/report/TestReportWebService.java +++ b/model/report-impl/src/test/java/com/evolveum/midpoint/report/TestReportWebService.java @@ -70,7 +70,7 @@ public void test100ProcessReportUserList() throws Exception { // THEN then(); - display("Returned user list (" + userList.getObject().size() + " objects)", userList); + displayValue("Returned user list (" + userList.getObject().size() + " objects)", userList); assertUserList(userList); } @@ -192,7 +192,7 @@ public void test119ProcessReportUserListReaderRunner() throws Exception { // THEN then(); - display("Returned user list (" + userList.getObject().size() + " objects)", userList); + displayValue("Returned user list (" + userList.getObject().size() + " objects)", userList); assertUserList(userList); } @@ -211,7 +211,7 @@ private void assertUserList(ObjectListType userList) throws SchemaException, Obj Task task = getTestTask(); OperationResult result = task.getResult(); SearchResultList> currentUsers = modelService.searchObjects(UserType.class, null, null, task, result); - display("Current users in midPoint (" + currentUsers.size() + " users)", currentUsers.toString()); + displayValue("Current users in midPoint (" + currentUsers.size() + " users)", currentUsers.toString()); assertEquals("Unexpected number of returned objects", currentUsers.size(), userList.getObject().size()); } diff --git a/model/workflow-impl/src/test/java/com/evolveum/midpoint/wf/impl/other/TestEscalation.java b/model/workflow-impl/src/test/java/com/evolveum/midpoint/wf/impl/other/TestEscalation.java index 50a8aab4781..e2a8cd7b436 100644 --- a/model/workflow-impl/src/test/java/com/evolveum/midpoint/wf/impl/other/TestEscalation.java +++ b/model/workflow-impl/src/test/java/com/evolveum/midpoint/wf/impl/other/TestEscalation.java @@ -279,7 +279,7 @@ public void test220Reject() throws Exception { assertEquals("Wrong cause display name in "+c, "Automatic rejection at deadline", c.getCause().getDisplayName()); } } - display("completion event map", eventMap); + displayValue("completion event map", eventMap); assertEquals("Wrong # of completion events", 2, eventMap.size()); displayCollection("audit records", dummyAuditService.getRecords()); diff --git a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/TestConnectorManager.java b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/TestConnectorManager.java index e571352b298..c975508000f 100644 --- a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/TestConnectorManager.java +++ b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/TestConnectorManager.java @@ -56,7 +56,7 @@ public void test100ListConnectorFactories() { assertSuccess(result); for (ConnectorFactory connectorFactory : connectorFactories) { - display("Found connector factory " + connectorFactory, connectorFactory); + displayValue("Found connector factory " + connectorFactory, connectorFactory); } PrismAsserts.assertEqualsUnordered("Wrong connector factories", diff --git a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/TestDBTable.java b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/TestDBTable.java index b8813977f70..022262c9885 100644 --- a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/TestDBTable.java +++ b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/TestDBTable.java @@ -115,7 +115,7 @@ public void test001Connection() throws Exception { ResourceType resource = repositoryService.getObject(ResourceType.class, RESOURCE_DERBY_OID, null, result).asObjectable(); display("Resource after test", resource); - display("Resource after test (XML)", PrismTestUtil.serializeObjectToString(resource.asPrismObject(), PrismContext.LANG_XML)); + displayValue("Resource after test (XML)", PrismTestUtil.serializeObjectToString(resource.asPrismObject(), PrismContext.LANG_XML)); List nativeCapabilities = resource.getCapabilities().getNative().getAny(); CredentialsCapabilityType credentialsCapabilityType = CapabilityUtil.getCapability(nativeCapabilities, CredentialsCapabilityType.class); @@ -191,7 +191,7 @@ public void test005GetAccount() throws Exception { assertNotNull("No password", account.asObjectable().getCredentials().getPassword()); assertNotNull("No password value", account.asObjectable().getCredentials().getPassword().getValue()); ProtectedStringType password = account.asObjectable().getCredentials().getPassword().getValue(); - display("Password", password); + displayValue("Password", password); String clearPassword = protector.decryptString(password); assertEquals("Wrong password", ACCOUNT_WILL_PASSWORD, clearPassword); } diff --git a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/async/TestAsyncUpdate.java b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/async/TestAsyncUpdate.java index a41751798c9..951a59b7321 100644 --- a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/async/TestAsyncUpdate.java +++ b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/async/TestAsyncUpdate.java @@ -160,7 +160,7 @@ public void test003Connection() throws Exception { assertNotNull("No schema after test connection", resourceXsdSchemaElementAfter); String resourceXml = prismContext.xmlSerializer().serialize(resourceRepoAfter); - display("Resource XML", resourceXml); + displayValue("Resource XML", resourceXml); CachingMetadataType cachingMetadata = xmlSchemaTypeAfter.getCachingMetadata(); assertNotNull("No caching metadata", cachingMetadata); diff --git a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/csv/AbstractCsvTest.java b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/csv/AbstractCsvTest.java index dc32b967ac3..ebff89f2938 100644 --- a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/csv/AbstractCsvTest.java +++ b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/csv/AbstractCsvTest.java @@ -156,7 +156,7 @@ public void test003Connection() throws Exception { assertNotNull("No schema after test connection", resourceXsdSchemaElementAfter); String resourceXml = prismContext.serializeObjectToString(resourceRepoAfter, PrismContext.LANG_XML); - display("Resource XML", resourceXml); + displayValue("Resource XML", resourceXml); CachingMetadataType cachingMetadata = xmlSchemaTypeAfter.getCachingMetadata(); assertNotNull("No caching metadata", cachingMetadata); @@ -238,7 +238,7 @@ public void test006Capabilities() throws Exception { // THEN display("Resource from provisioninig", resource); - display("Resource from provisioninig (XML)", PrismTestUtil.serializeObjectToString(resource.asPrismObject(), PrismContext.LANG_XML)); + displayValue("Resource from provisioninig (XML)", PrismTestUtil.serializeObjectToString(resource.asPrismObject(), PrismContext.LANG_XML)); CapabilityCollectionType nativeCapabilities = resource.getCapabilities().getNative(); List nativeCapabilitiesList = nativeCapabilities.getAny(); diff --git a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/AbstractBasicDummyTest.java b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/AbstractBasicDummyTest.java index c3c4ff43686..7238f90e89f 100644 --- a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/AbstractBasicDummyTest.java +++ b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/AbstractBasicDummyTest.java @@ -111,7 +111,7 @@ public static void assertCleanShutdown() { @Test public void test000Integrity() throws Exception { - display("Dummy resource instance", dummyResource.toString()); + displayValue("Dummy resource instance", dummyResource.toString()); assertNotNull("Resource is null", resource); assertNotNull("ResourceType is null", resourceType); @@ -154,7 +154,7 @@ public void test010ListConnectors() throws Exception { ConnectorType conn = connPrism.asObjectable(); display("Found connector " + conn, conn); - display("XML " + conn, PrismTestUtil.serializeObjectToString(connPrism, PrismContext.LANG_XML)); + displayValue("XML " + conn, PrismTestUtil.serializeObjectToString(connPrism, PrismContext.LANG_XML)); XmlSchemaType xmlSchemaType = conn.getSchema(); assertNotNull("xmlSchemaType is null", xmlSchemaType); @@ -218,7 +218,7 @@ public void test015ListResourcesNoFetch() throws Exception { ResourceType resourceType = resource.asObjectable(); display("Found resource " + resourceType, resourceType); - display("XML " + resourceType, PrismTestUtil.serializeObjectToString(resource, PrismContext.LANG_XML)); + displayValue("XML " + resourceType, PrismTestUtil.serializeObjectToString(resource, PrismContext.LANG_XML)); XmlSchemaType xmlSchemaType = resourceType.getSchema(); if (xmlSchemaType != null) { @@ -547,7 +547,7 @@ public void test028Capabilities() throws Exception { // Check native capabilities CapabilityCollectionType nativeCapabilities = resourceType.getCapabilities().getNative(); - display("Native capabilities", PrismTestUtil.serializeAnyDataWrapped(nativeCapabilities)); + displayValue("Native capabilities", PrismTestUtil.serializeAnyDataWrapped(nativeCapabilities)); display("Resource", resourceType); List nativeCapabilitiesList = nativeCapabilities.getAny(); assertFalse("Empty capabilities returned", nativeCapabilitiesList.isEmpty()); @@ -1026,7 +1026,7 @@ public void test080TestAttributesToReturn() throws Exception { AttributesToReturn attributesToReturn = ProvisioningUtil.createAttributesToReturn(ctx); // THEN - display("attributesToReturn", attributesToReturn); + displayValue("attributesToReturn", attributesToReturn); assertFalse("wrong isReturnDefaultAttributes", attributesToReturn.isReturnDefaultAttributes()); Collection attrs = new ArrayList<>(); for (ResourceAttributeDefinition attributeToReturnDef : attributesToReturn.getAttributesToReturn()) { @@ -1101,7 +1101,7 @@ public void test100AddAccountWill() throws Exception { checkRepoAccountShadowWill(accountRepo, start, end); willIcfUid = getIcfUid(accountRepo); - display("Will ICF UID", willIcfUid); + displayValue("Will ICF UID", willIcfUid); assertNotNull("No will ICF UID", willIcfUid); ActivationType activationRepo = accountRepo.asObjectable().getActivation(); @@ -1154,7 +1154,7 @@ public void test100AddAccountWill() throws Exception { // Check if the shadow is still in the repo (e.g. that the consistency or sync haven't removed it) PrismObject shadowFromRepo = getShadowRepo(addedObjectOid); assertNotNull("Shadow was not created in the repository", shadowFromRepo); - display("Repository shadow", shadowFromRepo.debugDump()); + displayValue("Repository shadow", shadowFromRepo.debugDump()); checkRepoAccountShadow(shadowFromRepo); diff --git a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummy.java b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummy.java index 01fdb1d842e..4c92069e8a3 100644 --- a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummy.java +++ b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummy.java @@ -183,7 +183,7 @@ public void test101AddAccountWithoutName() throws Exception { // Check if the shadow is in the repo PrismObject shadowFromRepo = getShadowRepo(addedObjectOid); assertNotNull("Shadow was not created in the repository", shadowFromRepo); - display("Repository shadow", shadowFromRepo.debugDump()); + displayValue("Repository shadow", shadowFromRepo.debugDump()); checkRepoAccountShadow(shadowFromRepo); // MID-4397 @@ -1068,7 +1068,7 @@ protected void testComparePassword(String tag, String shadowOid, then(); assertSuccess(result); - display("Comparison result (" + tag + ")", comparisonResult); + displayValue("Comparison result (" + tag + ")", comparisonResult); assertEquals("Wrong comparison result (" + tag + ")", expectedResult, comparisonResult); syncServiceMock.assertNoNotifcations(); @@ -1115,7 +1115,7 @@ public void test131AddScript() throws Exception { display("Account before add", account); OperationProvisioningScriptsType scriptsType = unmarshalValueFromFile(SCRIPTS_FILE, OperationProvisioningScriptsType.class); - display("Provisioning scripts", PrismTestUtil.serializeAnyDataWrapped(scriptsType)); + displayValue("Provisioning scripts", PrismTestUtil.serializeAnyDataWrapped(scriptsType)); // WHEN String addedObjectOid = provisioningService.addObject(account.asPrismObject(), scriptsType, null, task, result); @@ -1164,7 +1164,7 @@ public void test132ModifyScript() throws Exception { dummyResource.purgeScriptHistory(); OperationProvisioningScriptsType scriptsType = unmarshalValueFromFile(SCRIPTS_FILE, OperationProvisioningScriptsType.class); - display("Provisioning scripts", PrismTestUtil.serializeAnyDataWrapped(scriptsType)); + displayValue("Provisioning scripts", PrismTestUtil.serializeAnyDataWrapped(scriptsType)); ObjectDelta delta = prismContext.deltaFactory().object().createModificationReplaceProperty(ShadowType.class, ACCOUNT_NEW_SCRIPT_OID, dummyResourceCtl.getAttributeFullnamePath(), "Will Turner"); @@ -1208,7 +1208,7 @@ public void test133ModifyScriptNoExec() throws Exception { dummyResource.purgeScriptHistory(); OperationProvisioningScriptsType scriptsType = unmarshalValueFromFile(SCRIPTS_FILE, OperationProvisioningScriptsType.class); - display("Provisioning scripts", PrismTestUtil.serializeAnyDataWrapped(scriptsType)); + displayValue("Provisioning scripts", PrismTestUtil.serializeAnyDataWrapped(scriptsType)); ObjectDelta delta = prismContext.deltaFactory().object().createModificationReplaceProperty(ShadowType.class, ACCOUNT_NEW_SCRIPT_OID, ShadowType.F_DESCRIPTION, "Blah blah"); @@ -1247,7 +1247,7 @@ public void test134DeleteScript() throws Exception { dummyResource.purgeScriptHistory(); OperationProvisioningScriptsType scriptsType = unmarshalValueFromFile(SCRIPTS_FILE, OperationProvisioningScriptsType.class); - display("Provisioning scripts", PrismTestUtil.serializeAnyDataWrapped(scriptsType)); + displayValue("Provisioning scripts", PrismTestUtil.serializeAnyDataWrapped(scriptsType)); // WHEN provisioningService.deleteObject(ShadowType.class, ACCOUNT_NEW_SCRIPT_OID, null, scriptsType, @@ -1281,7 +1281,7 @@ public void test135ExecuteScript() throws Exception { dummyResource.purgeScriptHistory(); OperationProvisioningScriptsType scriptsType = unmarshalValueFromFile(SCRIPTS_FILE, OperationProvisioningScriptsType.class); - display("Provisioning scripts", PrismTestUtil.serializeAnyDataWrapped(scriptsType)); + displayValue("Provisioning scripts", PrismTestUtil.serializeAnyDataWrapped(scriptsType)); ProvisioningScriptType script = scriptsType.getScript().get(0); @@ -2283,7 +2283,7 @@ public void test200AddGroup() throws Exception { // Check if the shadow is still in the repo (e.g. that the consistency or sync haven't removed it) PrismObject shadowFromRepo = getShadowRepo(addedObjectOid); assertNotNull("Shadow was not created in the repository", shadowFromRepo); - display("Repository shadow", shadowFromRepo.debugDump()); + displayValue("Repository shadow", shadowFromRepo.debugDump()); checkRepoEntitlementShadow(shadowFromRepo); @@ -2445,7 +2445,7 @@ public void test210AddPrivilege() throws Exception { // Check if the shadow is still in the repo (e.g. that the consistency or sync haven't removed it) PrismObject shadowFromRepo = getShadowRepo(addedObjectOid); assertNotNull("Shadow was not created in the repository", shadowFromRepo); - display("Repository shadow", shadowFromRepo.debugDump()); + displayValue("Repository shadow", shadowFromRepo.debugDump()); checkRepoEntitlementShadow(shadowFromRepo); @@ -2538,7 +2538,7 @@ public void test214AddPrivilegeBargain() throws Exception { // Check if the shadow is still in the repo (e.g. that the consistency or sync haven't removed it) PrismObject shadowFromRepo = getShadowRepo(addedObjectOid); assertNotNull("Shadow was not created in the repository", shadowFromRepo); - display("Repository shadow", shadowFromRepo.debugDump()); + displayValue("Repository shadow", shadowFromRepo.debugDump()); checkRepoEntitlementShadow(shadowFromRepo); @@ -3661,7 +3661,7 @@ protected void assertAccountWillGossip(String... values) throws ConnectException } protected void assertWillDummyGossipRecord(PlusMinusZero plusminus, String... expectedValues) { - display("Dummy resource deltas", dummyResource.dumpDeltas()); + displayValue("Dummy resource deltas", dummyResource.dumpDeltas()); List dummyDeltas = dummyResource.getDeltas(); assertFalse("Empty dummy resource deltas", dummyDeltas.isEmpty()); assertEquals("Too many dummy resource deltas", 1, dummyDeltas.size()); @@ -4022,7 +4022,7 @@ public void test801LiveSyncAddBlackbeard() throws Exception { dummyResource.addAccount(newAccount); blackbeardIcfUid = newAccount.getId(); - display("Resource before sync", dummyResource.debugDump()); + displayValue("Resource before sync", dummyResource.debugDump()); ResourceShadowDiscriminator coords = new ResourceShadowDiscriminator(RESOURCE_DUMMY_OID, ProvisioningTestUtil.getDefaultAccountObjectClass(resourceType)); @@ -4082,7 +4082,7 @@ public void test802LiveSyncModifyBlackbeard() throws Exception { DummyAccount dummyAccount = getDummyAccountAssert(BLACKBEARD_USERNAME, blackbeardIcfUid); dummyAccount.replaceAttributeValue("fullname", "Captain Blackbeard"); - display("Resource before sync", dummyResource.debugDump()); + displayValue("Resource before sync", dummyResource.debugDump()); ResourceShadowDiscriminator coords = new ResourceShadowDiscriminator(RESOURCE_DUMMY_OID, ProvisioningTestUtil.getDefaultAccountObjectClass(resourceType)); @@ -4244,7 +4244,7 @@ public void testLiveSyncAddDrake(DummySyncStyle syncStyle, QName objectClass) th dummyResource.addAccount(newAccount); drakeIcfUid = newAccount.getId(); - display("Resource before sync", dummyResource.debugDump()); + displayValue("Resource before sync", dummyResource.debugDump()); ResourceShadowDiscriminator coords = new ResourceShadowDiscriminator(RESOURCE_DUMMY_OID, objectClass); @@ -4374,7 +4374,7 @@ public void testLiveSyncAddCorsairs( dummyResource.addGroup(newGroup); corsairsIcfUid = newGroup.getId(); - display("Resource before sync", dummyResource.debugDump()); + displayValue("Resource before sync", dummyResource.debugDump()); ResourceShadowDiscriminator coords = new ResourceShadowDiscriminator(RESOURCE_DUMMY_OID, objectClass); @@ -4450,7 +4450,7 @@ public void testLiveSyncDeleteCorsairs( dummyResource.deleteGroupById(corsairsIcfUid); } - display("Resource before sync", dummyResource.debugDump()); + displayValue("Resource before sync", dummyResource.debugDump()); ResourceShadowDiscriminator coords = new ResourceShadowDiscriminator(RESOURCE_DUMMY_OID, objectClass); @@ -4516,7 +4516,7 @@ private void testLiveSyncDeleteDrake( dummyResource.deleteAccountById(drakeIcfUid); } - display("Resource before sync", dummyResource.debugDump()); + displayValue("Resource before sync", dummyResource.debugDump()); ResourceShadowDiscriminator coords = new ResourceShadowDiscriminator(RESOURCE_DUMMY_OID, objectClass); diff --git a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummyConsistency.java b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummyConsistency.java index fb4b2738b3e..942ff84f1bd 100644 --- a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummyConsistency.java +++ b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummyConsistency.java @@ -88,7 +88,7 @@ public void test000Integrity() throws Exception { Task task = getTestTask(); OperationResult result = task.getResult(); - display("Dummy resource instance", dummyResource.toString()); + displayValue("Dummy resource instance", dummyResource.toString()); OperationResult testResult = provisioningService.testResource(RESOURCE_DUMMY_OID, task); assertSuccess(testResult); diff --git a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummyLegacy.java b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummyLegacy.java index c9c3b37b2af..7c8e3938e73 100644 --- a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummyLegacy.java +++ b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummyLegacy.java @@ -96,7 +96,7 @@ public void initSystem(Task initTask, OperationResult initResult) throws Excepti @Test public void test100NativeIntegrity() throws Exception { - display("Dummy resource instance", dummyResourceNative.toString()); + displayValue("Dummy resource instance", dummyResourceNative.toString()); assertNotNull("Resource is null", resourceNative); assertNotNull("ResourceType is null", resourceTypeNative); @@ -173,7 +173,7 @@ public void test105NativeParsedSchema() throws Exception { @Test public void test200LegacyIntegrity() throws Exception { - display("Dummy resource instance", dummyResourceLegacy.toString()); + displayValue("Dummy resource instance", dummyResourceLegacy.toString()); assertNotNull("Resource is null", resourceLegacy); assertNotNull("ResourceType is null", resourceTypeLegacy); diff --git a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummyParallelism.java b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummyParallelism.java index 1c1af773c49..53584bf7f16 100644 --- a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummyParallelism.java +++ b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummyParallelism.java @@ -819,7 +819,7 @@ public void test800ParallelReadAndModifyResource() throws Exception { List stats = provisioningService.getConnectorOperationalStatus(RESOURCE_DUMMY_OID, task, result); display("Dummy connector stats after", stats); - display("Dummy resource connections", dummyResource.getConnectionCount()); + displayValue("Dummy resource connections", dummyResource.getConnectionCount()); assertDummyConnectorInstances(dummyResource.getConnectionCount()); } diff --git a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummyPrioritiesAndReadReplace.java b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummyPrioritiesAndReadReplace.java index 36a48e894e9..4e6147b542c 100644 --- a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummyPrioritiesAndReadReplace.java +++ b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummyPrioritiesAndReadReplace.java @@ -22,8 +22,6 @@ import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.test.DummyResourceContoller; import com.evolveum.midpoint.test.util.TestUtil; -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.OperationProvisioningScriptsType; @@ -160,7 +158,7 @@ public void test100AddAccount() throws Exception { PrismObject shadowFromRepo = repositoryService.getObject(ShadowType.class, addedObjectOid, null, result); assertNotNull("Shadow was not created in the repository", shadowFromRepo); - display("Repository shadow", shadowFromRepo.debugDump()); + displayValue("Repository shadow", shadowFromRepo.debugDump()); ProvisioningTestUtil.checkRepoAccountShadow(shadowFromRepo); diff --git a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummySchemaless.java b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummySchemaless.java index a21c32305e7..5dcc1e9ba82 100644 --- a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummySchemaless.java +++ b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummySchemaless.java @@ -133,7 +133,7 @@ protected PrismObject getResource() { @Test public void test000Integrity() throws Exception { - display("Dummy resource instance", dummyResourceSchemaless.toString()); + displayValue("Dummy resource instance", dummyResourceSchemaless.toString()); assertNotNull("Resource is null", resourceSchemaless); assertNotNull("ResourceType is null", resourceTypeSchemaless); @@ -664,7 +664,7 @@ public void test107Capabilities() throws Exception { // Check native capabilities CapabilityCollectionType nativeCapabilities = resourceType.getCapabilities().getNative(); - display("Native capabilities ", PrismTestUtil.serializeAnyDataWrapped(nativeCapabilities)); + displayValue("Native capabilities ", PrismTestUtil.serializeAnyDataWrapped(nativeCapabilities)); display("Resource", resourceType.asPrismObject()); List nativeCapabilitiesList = nativeCapabilities.getAny(); assertFalse("Empty capabilities returned", nativeCapabilitiesList.isEmpty()); @@ -701,7 +701,7 @@ public void test107Capabilities() throws Exception { List effectiveCapabilities = ResourceTypeUtil.getEffectiveCapabilities(resourceType); for (Object capability : effectiveCapabilities) { - display("Capability " + CapabilityUtil.getCapabilityDisplayName(capability), capability); + displayValue("Capability " + CapabilityUtil.getCapabilityDisplayName(capability), capability); } } @@ -750,7 +750,7 @@ public void test200AddAccount() throws Exception { PrismObject shadowFromRepo = repositoryService.getObject(ShadowType.class, addedObjectOid, null, result); assertNotNull("Shadow was not created in the repository", shadowFromRepo); - display("Repository shadow", shadowFromRepo.debugDump()); + displayValue("Repository shadow", shadowFromRepo.debugDump()); ProvisioningTestUtil.checkRepoAccountShadow(shadowFromRepo); } diff --git a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummyUuidNonUniqueName.java b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummyUuidNonUniqueName.java index 7f5892bd31c..92169bc07fc 100644 --- a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummyUuidNonUniqueName.java +++ b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummyUuidNonUniqueName.java @@ -162,7 +162,7 @@ private void addFettucini(File file, String oid, String expectedFullName) throws PrismObject shadowFromRepo = repositoryService.getObject(ShadowType.class, addedObjectOid, null, result); assertNotNull("Shadow was not created in the repository", shadowFromRepo); - display("Repository shadow", shadowFromRepo.debugDump()); + displayValue("Repository shadow", shadowFromRepo.debugDump()); ProvisioningTestUtil.checkRepoAccountShadow(shadowFromRepo); diff --git a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/manual/AbstractManualResourceTest.java b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/manual/AbstractManualResourceTest.java index bb6ad792bcf..89d13e58a55 100644 --- a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/manual/AbstractManualResourceTest.java +++ b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/manual/AbstractManualResourceTest.java @@ -211,7 +211,7 @@ public void test003Connection() throws Exception { assertNotNull("No schema after test connection", resourceXsdSchemaElementAfter); String resourceXml = prismContext.serializeObjectToString(resourceRepoAfter, PrismContext.LANG_XML); - display("Resource XML", resourceXml); + displayValue("Resource XML", resourceXml); CachingMetadataType cachingMetadata = xmlSchemaTypeAfter.getCachingMetadata(); assertNotNull("No caching metadata", cachingMetadata); @@ -306,7 +306,7 @@ public void test006Capabilities() throws Exception { // THEN display("Resource from provisioninig", resource); - display("Resource from provisioninig (XML)", PrismTestUtil.serializeObjectToString(resource.asPrismObject(), PrismContext.LANG_XML)); + displayValue("Resource from provisioninig (XML)", PrismTestUtil.serializeObjectToString(resource.asPrismObject(), PrismContext.LANG_XML)); CapabilityCollectionType nativeCapabilities = resource.getCapabilities().getNative(); List nativeCapabilitiesList = nativeCapabilities.getAny(); diff --git a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/opendj/TestOpenDj.java b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/opendj/TestOpenDj.java index ad675ad07d8..b6b965d22fa 100644 --- a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/opendj/TestOpenDj.java +++ b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/opendj/TestOpenDj.java @@ -187,7 +187,7 @@ public void test003Connection() throws Exception { display("Resource after testResource (repository)", resourceTypeRepoAfter); - display("Resource after testResource (repository, XML)", PrismTestUtil.serializeObjectToString(resourceTypeRepoAfter.asPrismObject(), PrismContext.LANG_XML)); + displayValue("Resource after testResource (repository, XML)", PrismTestUtil.serializeObjectToString(resourceTypeRepoAfter.asPrismObject(), PrismContext.LANG_XML)); XmlSchemaType xmlSchemaTypeAfter = resourceTypeRepoAfter.getSchema(); assertNotNull("No schema after test connection", xmlSchemaTypeAfter); @@ -270,7 +270,7 @@ public void test005Capabilities() throws Exception { // THEN display("Resource from provisioninig", resource); - display("Resource from provisioninig (XML)", PrismTestUtil.serializeObjectToString(resource.asPrismObject(), PrismContext.LANG_XML)); + displayValue("Resource from provisioninig (XML)", PrismTestUtil.serializeObjectToString(resource.asPrismObject(), PrismContext.LANG_XML)); CapabilityCollectionType nativeCapabilities = resource.getCapabilities().getNative(); List nativeCapabilitiesList = nativeCapabilities.getAny(); @@ -975,7 +975,7 @@ public void test145ModifyAccountJackJpegPhoto() throws Exception { OperationResult result = task.getResult(); byte[] bytesIn = Files.readAllBytes(Paths.get(ProvisioningTestUtil.DOT_JPG_FILENAME)); - display("Bytes in", MiscUtil.binaryToHex(bytesIn)); + displayValue("Bytes in", MiscUtil.binaryToHex(bytesIn)); ItemName jpegPhotoQName = new ItemName(RESOURCE_OPENDJ_NS, "jpegPhoto"); PropertyDelta jpegPhotoDelta = prismContext.deltaFactory().property().create(ItemPath.create(ShadowType.F_ATTRIBUTES, jpegPhotoQName), @@ -1011,7 +1011,7 @@ public void test145ModifyAccountJackJpegPhoto() throws Exception { PrismProperty jpegPhotoAttr = attributesContainer.findProperty(jpegPhotoQName); byte[] bytesOut = jpegPhotoAttr.getValues().get(0).getValue(); - display("Bytes out", MiscUtil.binaryToHex(bytesOut)); + displayValue("Bytes out", MiscUtil.binaryToHex(bytesOut)); assertEquals("Byte length changed (shadow)", bytesIn.length, bytesOut.length); assertTrue("Bytes do not match (shadow)", Arrays.equals(bytesIn, bytesOut)); @@ -1216,7 +1216,7 @@ public boolean handle(PrismObject prismObject, OperationResult paren // THEN then(); - display("Count", objects.size()); + displayValue("Count", objects.size()); assertEquals("Unexpected number of shadows", 9, objects.size()); // The extra shadow is a group shadow @@ -1261,7 +1261,7 @@ public boolean handle(PrismObject prismObject, OperationResult paren // THEN then(); - display("Count", objects.size()); + displayValue("Count", objects.size()); assertEquals("Unexpected number of shadows", 3, objects.size()); // The extra shadow is a group shadow @@ -1306,7 +1306,7 @@ public boolean handle(PrismObject prismObject, OperationResult paren // THEN then(); - display("Count", objects.size()); + displayValue("Count", objects.size()); assertEquals("Unexpected number of shadows", 3, objects.size()); // The extra shadow is a group shadow @@ -1934,7 +1934,7 @@ private void assertSearchResults(List> searchResults, St assertShadowSanity(searchResult); ResourceAttribute uidAttr = ShadowUtil.getAttribute(searchResult, new QName(RESOURCE_NS, "uid")); String uid = uidAttr.getRealValues().iterator().next(); - display("found uid", uid); + displayValue("found uid", uid); assertEquals("Wrong uid (index " + i + ")", expectedUids[i], uid); i++; } @@ -1959,7 +1959,7 @@ public void test250CountAccounts() throws Exception { // THEN then(); assertSuccess(result); - display("All accounts count", count); + displayValue("All accounts count", count); assertEquals("Unexpected number of search results", (Integer) 14, count); } @@ -1983,7 +1983,7 @@ public void test252CountLdapGroups() throws Exception { // THEN then(); assertSuccess(result); - display("All LDAP groups count", count); + displayValue("All LDAP groups count", count); assertEquals("Unexpected number of search results", getExpectedLdapGroupCountTest25x(), count); } diff --git a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/opendj/TestOpenDjNegative.java b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/opendj/TestOpenDjNegative.java index 7b13361579d..dba2afa6132 100644 --- a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/opendj/TestOpenDjNegative.java +++ b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/opendj/TestOpenDjNegative.java @@ -96,7 +96,7 @@ public void test003Connection() throws Exception { PrismObject resourceRepoAfter = repositoryService.getObject(ResourceType.class, RESOURCE_OPENDJ_OID, null, result); display("Resource after testResource (repository)", resourceRepoAfter); ResourceType resourceTypeRepoAfter = resourceRepoAfter.asObjectable(); - display("Resource after testResource (repository, XML)", PrismTestUtil.serializeObjectToString(resourceTypeRepoAfter.asPrismObject(), PrismContext.LANG_XML)); + displayValue("Resource after testResource (repository, XML)", PrismTestUtil.serializeObjectToString(resourceTypeRepoAfter.asPrismObject(), PrismContext.LANG_XML)); XmlSchemaType xmlSchemaTypeAfter = resourceTypeRepoAfter.getSchema(); // assertNull("The schema was generated after test connection but it should not be",xmlSchemaTypeAfter); diff --git a/provisioning/ucf-impl-connid/src/test/java/com/evolveum/midpoint/provisioning/ucf/impl/connid/AbstractUcfDummyTest.java b/provisioning/ucf-impl-connid/src/test/java/com/evolveum/midpoint/provisioning/ucf/impl/connid/AbstractUcfDummyTest.java index 183f79d2887..afe8a6ae961 100644 --- a/provisioning/ucf-impl-connid/src/test/java/com/evolveum/midpoint/provisioning/ucf/impl/connid/AbstractUcfDummyTest.java +++ b/provisioning/ucf-impl-connid/src/test/java/com/evolveum/midpoint/provisioning/ucf/impl/connid/AbstractUcfDummyTest.java @@ -102,11 +102,11 @@ protected void assertContainerDefinition(PrismContainer container, String con PrismAsserts.assertDefinition(container.getDefinition(), qName, xsdType, minOccurs, maxOccurs); } - protected void display(String title, DebugDumpable value) { + protected void displayValue(String title, DebugDumpable value) { PrismTestUtil.display(title, value); } - protected void display(String title, Object value) { + public void displayValue(String title, Object value) { PrismTestUtil.display(title, value); } } diff --git a/provisioning/ucf-impl-connid/src/test/java/com/evolveum/midpoint/provisioning/ucf/impl/connid/TestUcfDummy.java b/provisioning/ucf-impl-connid/src/test/java/com/evolveum/midpoint/provisioning/ucf/impl/connid/TestUcfDummy.java index b97f1c616e4..8fdb998ea61 100644 --- a/provisioning/ucf-impl-connid/src/test/java/com/evolveum/midpoint/provisioning/ucf/impl/connid/TestUcfDummy.java +++ b/provisioning/ucf-impl-connid/src/test/java/com/evolveum/midpoint/provisioning/ucf/impl/connid/TestUcfDummy.java @@ -71,7 +71,7 @@ public void test000PrismContextSanity() { @Test public void test001ResourceSanity() { - display("Resource", resource); + displayValue("Resource", resource); assertEquals("Wrong oid", "ef2bc95b-76e0-59e2-86d6-9999dddddddd", resource.getOid()); // assertEquals("Wrong version", "42", resource.getVersion()); @@ -107,7 +107,7 @@ public void test002ConnectorSchema() throws Exception { Document xsdSchemaDom = connectorSchema.serializeToXsd(); assertNotNull("No serialized connector schema", xsdSchemaDom); - display("Serialized XSD connector schema", DOMUtil.serializeDOMToString(xsdSchemaDom)); + displayValue("Serialized XSD connector schema", DOMUtil.serializeDOMToString(xsdSchemaDom)); // Try to re-parse PrismSchema reparsedConnectorSchema = PrismSchemaImpl.parse(DOMUtil.getFirstChildElement(xsdSchemaDom), true, "schema fetched from " + cc, PrismTestUtil.getPrismContext()); @@ -152,7 +152,7 @@ public void test020CreateConfiguredConnector() throws Exception { OperationResult result = createOperationResult(); PrismContainerValue configContainer = resourceType.getConnectorConfiguration().asPrismContainerValue(); - display("Configuration container", configContainer); + displayValue("Configuration container", configContainer); // WHEN cc.configure(configContainer, ResourceTypeUtil.getSchemaGenerationConstraints(resourceType), result); @@ -168,7 +168,7 @@ public void test022ConnectorStatsConfigured() throws Exception { ConnectorOperationalStatus operationalStatus = cc.getOperationalStatus(); // THEN - display("Connector operational status", operationalStatus); + displayValue("Connector operational status", operationalStatus); assertNotNull("null operational status", operationalStatus); assertEquals("Wrong connectorClassName", DummyConnector.class.getName(), operationalStatus.getConnectorClassName()); @@ -193,7 +193,7 @@ public void test030ResourceSchema() throws Exception { PrismContainerValue configContainer = resourceType.getConnectorConfiguration().asPrismContainerValue(); - display("Configuration container", configContainer); + displayValue("Configuration container", configContainer); //ResourceTypeUtil.getSchemaGenerationConstraints(resourceType) cc.configure(configContainer, null, result); @@ -201,19 +201,19 @@ public void test030ResourceSchema() throws Exception { resourceSchema = cc.fetchResourceSchema(result); // THEN - display("Generated resource schema", resourceSchema); + displayValue("Generated resource schema", resourceSchema); assertEquals("Unexpected number of definitions", 4, resourceSchema.getDefinitions().size()); dummyResourceCtl.assertDummyResourceSchemaSanityExtended(resourceSchema, resourceType, true); Document xsdSchemaDom = resourceSchema.serializeToXsd(); assertNotNull("No serialized resource schema", xsdSchemaDom); - display("Serialized XSD resource schema", DOMUtil.serializeDOMToString(xsdSchemaDom)); + displayValue("Serialized XSD resource schema", DOMUtil.serializeDOMToString(xsdSchemaDom)); // Try to re-parse ResourceSchema reparsedResourceSchema = ResourceSchemaImpl.parse(DOMUtil.getFirstChildElement(xsdSchemaDom), "serialized schema", PrismTestUtil.getPrismContext()); - display("Re-parsed resource schema", reparsedResourceSchema); + displayValue("Re-parsed resource schema", reparsedResourceSchema); assertEquals("Unexpected number of definitions in re-parsed schema", 4, reparsedResourceSchema.getDefinitions().size()); dummyResourceCtl.assertDummyResourceSchemaSanityExtended(reparsedResourceSchema, resourceType, true); @@ -230,7 +230,7 @@ public void test031ResourceSchemaAccountObjectClass() throws Exception { PrismContainerValue configContainer = resourceType.getConnectorConfiguration().asPrismContainerValue(); - display("Configuration container", configContainer); + displayValue("Configuration container", configContainer); List objectClassesToGenerate = new ArrayList<>(); QName accountObjectClass = new QName(resource.asObjectable().getNamespace(), "AccountObjectClass"); objectClassesToGenerate.add(accountObjectClass); @@ -241,7 +241,7 @@ public void test031ResourceSchemaAccountObjectClass() throws Exception { resourceSchema = cc.fetchResourceSchema(result); // THEN - display("Generated resource schema", resourceSchema); + displayValue("Generated resource schema", resourceSchema); assertEquals("Unexpected number of definitions", 1, resourceSchema.getDefinitions().size()); assertEquals("Unexpected number of object class definitions", 1, resourceSchema.getObjectClassDefinitions().size()); @@ -255,7 +255,7 @@ public void test033ConnectorStatsInitialized() throws Exception { ConnectorOperationalStatus operationalStatus = cc.getOperationalStatus(); // THEN - display("Connector operational status", operationalStatus); + displayValue("Connector operational status", operationalStatus); assertNotNull("null operational status", operationalStatus); assertEquals("Wrong connectorClassName", DummyConnector.class.getName(), operationalStatus.getConnectorClassName()); @@ -309,7 +309,7 @@ public void test050Search() throws Exception { @Override public boolean handle(PrismObject shadow) { - display("Search: found", shadow); + displayValue("Search: found", shadow); checkUcfShadow(shadow, accountDefinition); searchResults.add(shadow); return true; diff --git a/provisioning/ucf-impl-connid/src/test/java/com/evolveum/midpoint/provisioning/ucf/impl/connid/TestUcfDummyMulti.java b/provisioning/ucf-impl-connid/src/test/java/com/evolveum/midpoint/provisioning/ucf/impl/connid/TestUcfDummyMulti.java index 7c555ba8a4f..393c6bf61ec 100644 --- a/provisioning/ucf-impl-connid/src/test/java/com/evolveum/midpoint/provisioning/ucf/impl/connid/TestUcfDummyMulti.java +++ b/provisioning/ucf-impl-connid/src/test/java/com/evolveum/midpoint/provisioning/ucf/impl/connid/TestUcfDummyMulti.java @@ -73,7 +73,7 @@ public void test020CreateConfiguredConnector() throws Exception { OperationResult result = createOperationResult(); PrismContainerValue configContainer = resourceType.getConnectorConfiguration().asPrismContainerValue(); - display("Configuration container", configContainer); + displayValue("Configuration container", configContainer); // WHEN cc.configure(configContainer, ResourceTypeUtil.getSchemaGenerationConstraints(resourceType), result); @@ -142,7 +142,7 @@ public boolean handle(PrismObject shadow) { assertEquals("Unexpected number of search results", 1, searchResults.size()); ConnectorOperationalStatus opStat = cc.getOperationalStatus(); - display("stats", opStat); + displayValue("stats", opStat); assertEquals("Wrong pool active", (Integer) 0, opStat.getPoolStatusNumActive()); assertEquals("Wrong pool active", (Integer) 1, opStat.getPoolStatusNumIdle()); } @@ -190,7 +190,7 @@ public void run() { Thread.sleep(500); ConnectorOperationalStatus opStat = cc.getOperationalStatus(); - display("stats (blocked)", opStat); + displayValue("stats (blocked)", opStat); assertEquals("Wrong pool active", (Integer) 1, opStat.getPoolStatusNumActive()); assertEquals("Wrong pool active", (Integer) 0, opStat.getPoolStatusNumIdle()); @@ -206,12 +206,12 @@ public void run() { assertEquals("Unexpected number of search results", 1, searchResults.size()); opStat = cc.getOperationalStatus(); - display("stats (final)", opStat); + displayValue("stats (final)", opStat); assertEquals("Wrong pool active", (Integer) 0, opStat.getPoolStatusNumActive()); assertEquals("Wrong pool active", (Integer) 1, opStat.getPoolStatusNumIdle()); PrismObject searchResult = searchResults.get(0); - display("Search result", searchResult); + displayValue("Search result", searchResult); } @Test @@ -265,7 +265,7 @@ public void run() { Thread.sleep(500); ConnectorOperationalStatus opStat = cc.getOperationalStatus(); - display("stats (blocked 1)", opStat); + displayValue("stats (blocked 1)", opStat); assertEquals("Wrong pool active", (Integer) 1, opStat.getPoolStatusNumActive()); assertEquals("Wrong pool active", (Integer) 0, opStat.getPoolStatusNumIdle()); @@ -290,7 +290,7 @@ public void run() { Thread.sleep(500); opStat = cc.getOperationalStatus(); - display("stats (blocked 2)", opStat); + displayValue("stats (blocked 2)", opStat); assertEquals("Wrong pool active", (Integer) 2, opStat.getPoolStatusNumActive()); assertEquals("Wrong pool active", (Integer) 0, opStat.getPoolStatusNumIdle()); @@ -308,15 +308,15 @@ public void run() { assertEquals("Unexpected number of search results 2", 1, searchResults2.size()); opStat = cc.getOperationalStatus(); - display("stats (final)", opStat); + displayValue("stats (final)", opStat); assertEquals("Wrong pool active", (Integer) 0, opStat.getPoolStatusNumActive()); assertEquals("Wrong pool active", (Integer) 2, opStat.getPoolStatusNumIdle()); PrismObject searchResult1 = searchResults1.get(0); - display("Search result 1", searchResult1); + displayValue("Search result 1", searchResult1); PrismObject searchResult2 = searchResults2.get(0); - display("Search result 2", searchResult2); + displayValue("Search result 2", searchResult2); } private void checkUcfShadow(PrismObject shadow, ObjectClassComplexTypeDefinition objectClassDefinition) { diff --git a/provisioning/ucf-impl-connid/src/test/java/com/evolveum/midpoint/provisioning/ucf/impl/connid/TestUcfOpenDj.java b/provisioning/ucf-impl-connid/src/test/java/com/evolveum/midpoint/provisioning/ucf/impl/connid/TestUcfOpenDj.java index 8d90cbe2dae..b63fec34f29 100644 --- a/provisioning/ucf-impl-connid/src/test/java/com/evolveum/midpoint/provisioning/ucf/impl/connid/TestUcfOpenDj.java +++ b/provisioning/ucf-impl-connid/src/test/java/com/evolveum/midpoint/provisioning/ucf/impl/connid/TestUcfOpenDj.java @@ -137,7 +137,7 @@ public void initUcf() throws Exception { connectorSchema = factory.generateConnectorConfigurationSchema(connectorType); AssertJUnit.assertNotNull("Cannot generate connector schema", connectorSchema); - display("Connector schema", connectorSchema); + displayValue("Connector schema", connectorSchema); cc = factory.createConnectorInstance(connectorType, ResourceTypeUtil.getResourceNamespace(resourceType), "OpenDJ resource", @@ -149,7 +149,7 @@ public void initUcf() throws Exception { // TODO: assert something resourceSchema = cc.fetchResourceSchema(result); - display("Resource schema", resourceSchema); + displayValue("Resource schema", resourceSchema); AssertJUnit.assertNotNull(resourceSchema); @@ -347,7 +347,7 @@ public void test200FetchChanges() throws Exception { cc.fetchChanges(accountDefinition, lastToken, null, null, null, handler, result); List changes = handler.getChanges(); - display("Changes", changes); + displayValue("Changes", changes); // No changes (token-only changes are gone in 4.0.1) AssertJUnit.assertEquals(0, changes.size()); @@ -433,7 +433,7 @@ public void test310TestConnectionNegative() throws Exception { // THEN result.computeStatus("test failed"); - display("Test result (FAILURE EXPECTED)", result); + displayValue("Test result (FAILURE EXPECTED)", result); AssertJUnit.assertNotNull(result); OperationResult connectorConnectionResult = result.getSubresults().get(1); AssertJUnit.assertNotNull(connectorConnectionResult); @@ -594,7 +594,7 @@ public void test600CreateAccountWithPassword() throws Exception { String entryUuid = (String) resourceObject.getPrimaryIdentifier().getValue().getValue(); Entry entry = openDJController.searchAndAssertByEntryUuid(entryUuid); - display("Entry before change", entry); + displayValue("Entry before change", entry); String passwordAfter = OpenDJController.getAttributeValue(entry, "userPassword"); assertNotNull(passwordAfter); @@ -618,7 +618,7 @@ public void test610ChangePassword() throws Exception { String entryUuid = (String) resourceObject.getPrimaryIdentifier().getValue().getValue(); Entry entry = openDJController.searchAndAssertByEntryUuid(entryUuid); - display("Entry before change", entry); + displayValue("Entry before change", entry); String passwordBefore = OpenDJController.getAttributeValue(entry, "userPassword"); // We have set no password during create, therefore the password should // be empty @@ -661,7 +661,7 @@ public void test610ChangePassword() throws Exception { // THEN entry = openDJController.searchAndAssertByEntryUuid(entryUuid); - display("Entry after change", entry); + displayValue("Entry after change", entry); String passwordAfter = OpenDJController.getAttributeValue(entry, "userPassword"); assertNotNull(passwordAfter); diff --git a/repo/repo-cache/src/test/java/com/evolveum/midpoint/repo/cache/TestRepositoryCache.java b/repo/repo-cache/src/test/java/com/evolveum/midpoint/repo/cache/TestRepositoryCache.java index 7f5404ff40f..91a2603f893 100644 --- a/repo/repo-cache/src/test/java/com/evolveum/midpoint/repo/cache/TestRepositoryCache.java +++ b/repo/repo-cache/src/test/java/com/evolveum/midpoint/repo/cache/TestRepositoryCache.java @@ -237,7 +237,7 @@ private int getOperationCount(String operation) { private void dumpStatistics() { PerformanceInformation performanceInformation = repositoryCache.getPerformanceMonitor().getGlobalPerformanceInformation(); - display("Repository statistics", RepositoryPerformanceInformationUtil.format(performanceInformation.toRepositoryPerformanceInformationType())); + displayValue("Repository statistics", RepositoryPerformanceInformationUtil.format(performanceInformation.toRepositoryPerformanceInformationType())); } private void clearStatistics() { diff --git a/repo/repo-sql-impl-test/src/test/java/com/evolveum/midpoint/repo/sql/BaseSQLRepoTest.java b/repo/repo-sql-impl-test/src/test/java/com/evolveum/midpoint/repo/sql/BaseSQLRepoTest.java index 72b4fd515eb..8d49cda7f95 100644 --- a/repo/repo-sql-impl-test/src/test/java/com/evolveum/midpoint/repo/sql/BaseSQLRepoTest.java +++ b/repo/repo-sql-impl-test/src/test/java/com/evolveum/midpoint/repo/sql/BaseSQLRepoTest.java @@ -296,16 +296,16 @@ protected void assertSearch(ItemName item, String value, int expectedCount, Oper SearchResultList> found = repositoryService .searchObjects(UserType.class, query, null, result); if (verbose) { - display("Found", found); + displayValue("Found", found); } assertEquals("Wrong # of objects found", expectedCount, found.size()); } - protected void display(String title, DebugDumpable value) { + protected void displayValue(String title, DebugDumpable value) { PrismTestUtil.display(title, value); } - protected void display(String title, Object value) { + public void displayValue(String title, Object value) { PrismTestUtil.display(title, value); } } diff --git a/repo/repo-sql-impl-test/src/test/java/com/evolveum/midpoint/repo/sql/CertificationTest.java b/repo/repo-sql-impl-test/src/test/java/com/evolveum/midpoint/repo/sql/CertificationTest.java index 4c17cb66583..d2d55a2c2c0 100644 --- a/repo/repo-sql-impl-test/src/test/java/com/evolveum/midpoint/repo/sql/CertificationTest.java +++ b/repo/repo-sql-impl-test/src/test/java/com/evolveum/midpoint/repo/sql/CertificationTest.java @@ -204,7 +204,7 @@ public void test250DeleteCase() throws Exception { OperationResult result = createOperationResult(); PrismObject campaign10Before = getFullCampaign(campaign1Oid); - display("Campaign 10 before", campaign10Before); + displayValue("Campaign 10 before", campaign10Before); AccessCertificationCaseType case9 = new AccessCertificationCaseType(); case9.setId(CASE_9_ID); @@ -218,7 +218,7 @@ public void test250DeleteCase() throws Exception { // THEN PrismObject campaign10After = getFullCampaign(campaign1Oid); - display("Campaign 10 after", campaign10After); + displayValue("Campaign 10 after", campaign10After); checkCasesForCampaign(campaign1Oid, 8, result); checkCasesTotal(8, result); diff --git a/repo/repo-sql-impl-test/src/test/java/com/evolveum/midpoint/repo/sql/ConcurrencyTest.java b/repo/repo-sql-impl-test/src/test/java/com/evolveum/midpoint/repo/sql/ConcurrencyTest.java index ebabbc018aa..6f816329a12 100644 --- a/repo/repo-sql-impl-test/src/test/java/com/evolveum/midpoint/repo/sql/ConcurrencyTest.java +++ b/repo/repo-sql-impl-test/src/test/java/com/evolveum/midpoint/repo/sql/ConcurrencyTest.java @@ -517,7 +517,7 @@ public void test100AddOperationExecution() throws Exception { OperationResult result = new OperationResult("test100AddOperationExecution"); String oid = repositoryService.addObject(user.asPrismObject(), null, result); - display("object added", oid); + displayValue("object added", oid); logger.info("Starting worker threads"); @@ -572,7 +572,7 @@ public void test110AddAssignments() throws Exception { OperationResult result = new OperationResult("test110AddAssignments"); String oid = repositoryService.addObject(user.asPrismObject(), null, result); - display("object added", oid); + displayValue("object added", oid); logger.info("Starting worker threads"); @@ -596,7 +596,7 @@ public void test110AddAssignments() throws Exception { waitForThreads(threads, DURATION); PrismObject userAfter = repositoryService.getObject(UserType.class, oid, null, result); - display("user after", userAfter); + displayValue("user after", userAfter); } @Test @@ -611,7 +611,7 @@ public void test120AddApproverRef() throws Exception { OperationResult result = new OperationResult("test120AddApproverRef"); String oid = repositoryService.addObject(role.asPrismObject(), null, result); - display("object added", oid); + displayValue("object added", oid); logger.info("Starting worker threads"); @@ -634,7 +634,7 @@ public void test120AddApproverRef() throws Exception { waitForThreads(threads, DURATION); PrismObject roleAfter = repositoryService.getObject(RoleType.class, oid, null, result); - display("role after", roleAfter); + displayValue("role after", roleAfter); int totalExecutions = threads.stream().mapToInt(t -> t.counter.get()).sum(); int totalApprovers = roleAfter.asObjectable().getDelegatedRef().size(); diff --git a/repo/repo-sql-impl-test/src/test/java/com/evolveum/midpoint/repo/sql/ModifyAssignmentTest.java b/repo/repo-sql-impl-test/src/test/java/com/evolveum/midpoint/repo/sql/ModifyAssignmentTest.java index fe6ea83d743..5c0a578414d 100644 --- a/repo/repo-sql-impl-test/src/test/java/com/evolveum/midpoint/repo/sql/ModifyAssignmentTest.java +++ b/repo/repo-sql-impl-test/src/test/java/com/evolveum/midpoint/repo/sql/ModifyAssignmentTest.java @@ -347,7 +347,7 @@ public void test100AssignmentAdd() throws Exception { OperationResult result = createOperationResult(); PrismObject roleBefore = getObject(RoleType.class, ROLE_OID); - display("Role before", roleBefore); + displayValue("Role before", roleBefore); AssignmentType assignmentToAdd = new AssignmentType(); assignmentToAdd.targetRef(ROLE_A1_OID, RoleType.COMPLEX_TYPE); @@ -362,7 +362,7 @@ public void test100AssignmentAdd() throws Exception { assertSuccess(result); PrismObject roleAfter = getObject(RoleType.class, ROLE_OID); - display("Role after", roleAfter); + displayValue("Role after", roleAfter); PrismContainer assignment = roleAfter.findContainer(RoleType.F_ASSIGNMENT); assertNotNull(assignment); @@ -382,7 +382,7 @@ public void test110AssignmentAddDeleteIds() throws Exception { OperationResult result = createOperationResult(); PrismObject roleBefore = getObject(RoleType.class, ROLE_OID); - display("Role before", roleBefore); + displayValue("Role before", roleBefore); AssignmentType assignmentToAdd = new AssignmentType(); assignmentToAdd.targetRef(ROLE_A2_OID, RoleType.COMPLEX_TYPE); @@ -405,7 +405,7 @@ public void test110AssignmentAddDeleteIds() throws Exception { assertSuccess(result); PrismObject roleAfter = getObject(RoleType.class, ROLE_OID); - display("Role after", roleAfter); + displayValue("Role after", roleAfter); PrismContainer assignment = roleAfter.findContainer(RoleType.F_ASSIGNMENT); assertNotNull(assignment); diff --git a/repo/repo-sql-impl-test/src/test/java/com/evolveum/midpoint/repo/sql/ModifyTest.java b/repo/repo-sql-impl-test/src/test/java/com/evolveum/midpoint/repo/sql/ModifyTest.java index 8cc7dc14625..841d64789e9 100644 --- a/repo/repo-sql-impl-test/src/test/java/com/evolveum/midpoint/repo/sql/ModifyTest.java +++ b/repo/repo-sql-impl-test/src/test/java/com/evolveum/midpoint/repo/sql/ModifyTest.java @@ -370,7 +370,7 @@ public void test055DeleteUserEmployeeNumberWrong() throws Exception { repositoryService.modifyObject(UserType.class, user.getOid(), modifications, getModifyOptions(), result); PrismObject userAfter = repositoryService.getObject(UserType.class, user.getOid(), null, result); - display("user after", userAfter); + displayValue("user after", userAfter); assertEquals("Wrong employeeNumber after operation", "old", userAfter.asObjectable().getEmployeeNumber()); assertUserEmployeeNumber(user.getOid(), "old"); @@ -392,7 +392,7 @@ public void test056EmptyUserEmployeeNumberDelta() throws Exception { repositoryService.modifyObject(UserType.class, user.getOid(), modifications, getModifyOptions(), result); PrismObject userAfter = repositoryService.getObject(UserType.class, user.getOid(), null, result); - display("user after", userAfter); + displayValue("user after", userAfter); assertEquals("Wrong employeeNumber after operation", "old", userAfter.asObjectable().getEmployeeNumber()); assertUserEmployeeNumber(user.getOid(), "old"); @@ -1041,7 +1041,7 @@ public void test250AddShadowPendingOperations() throws Exception { List> objectsAfter = repositoryService.searchObjects(ShadowType.class, query, null, result); assertEquals("Wrong # of shadows found (after)", 1, objectsAfter.size()); - display("object found (after)", objectsAfter.get(0)); + displayValue("object found (after)", objectsAfter.get(0)); } /** @@ -1067,7 +1067,7 @@ public void test260DeleteShadowPendingOperations() throws Exception { .build(); List> objectsBefore = repositoryService.searchObjects(ShadowType.class, query, null, result); assertEquals("Wrong # of shadows found (before)", 1, objectsBefore.size()); - display("object found (before)", objectsBefore.get(0)); + displayValue("object found (before)", objectsBefore.get(0)); // WHEN @@ -1115,7 +1115,7 @@ public void test300AddCaseWorkItem() throws Exception { List> cases = repositoryService.searchObjects(CaseType.class, query, null, result); assertEquals("Wrong # of cases found", 1, cases.size()); - display("case fetched from repository", cases.get(0)); + displayValue("case fetched from repository", cases.get(0)); } @Test @@ -1279,7 +1279,7 @@ public void test360ReplaceModifyApprovers() throws Exception { // THEN PrismObject userAfter = repositoryService.getObject(UserType.class, user.getOid(), null, result); - display("user after", userAfter); + displayValue("user after", userAfter); ObjectQuery query = prismContext.queryFor(UserType.class) .item(UserType.F_METADATA, MetadataType.F_MODIFY_APPROVER_REF).ref(approver1.getOid()) @@ -1301,7 +1301,7 @@ public void test400RemoveCoreProtectedStringValueInMemory() throws Exception { .end() .end(); - display("jack before", jack.asPrismObject()); + displayValue("jack before", jack.asPrismObject()); ObjectDelta delta = prismContext.deltaFor(UserType.class) .item(UserType.F_CREDENTIALS, CredentialsType.F_PASSWORD, PasswordType.F_VALUE) @@ -1310,7 +1310,7 @@ public void test400RemoveCoreProtectedStringValueInMemory() throws Exception { delta.applyTo(jack.asPrismObject()); - display("jack after", jack.asPrismObject()); + displayValue("jack after", jack.asPrismObject()); jack.asPrismObject().checkConsistence(); } @@ -1326,7 +1326,7 @@ public void test410RemoveExtensionProtectedStringValueInMemory() throws Exceptio protectedProperty.setRealValue(protectedValue.clone()); jack.asPrismObject().addExtensionItem(protectedProperty); - display("jack before", jack.asPrismObject()); + displayValue("jack before", jack.asPrismObject()); ObjectDelta delta = prismContext.deltaFor(UserType.class) .item(UserType.F_EXTENSION, "protected") @@ -1335,7 +1335,7 @@ public void test410RemoveExtensionProtectedStringValueInMemory() throws Exceptio delta.applyTo(jack.asPrismObject()); - display("jack after", jack.asPrismObject()); + displayValue("jack after", jack.asPrismObject()); jack.asPrismObject().checkConsistence(); } @@ -1356,7 +1356,7 @@ public void test420RemoveExtensionProtectedStringValueInRepo() throws Exception repositoryService.addObject(jack.asPrismObject(), null, result); - display("jack before", jack.asPrismObject()); + displayValue("jack before", jack.asPrismObject()); // WHEN @@ -1371,7 +1371,7 @@ public void test420RemoveExtensionProtectedStringValueInRepo() throws Exception PrismObject jackAfter = repositoryService.getObject(UserType.class, jack.getOid(), null, result); - display("jack after", jackAfter); + displayValue("jack after", jackAfter); jackAfter.checkConsistence(); } diff --git a/repo/repo-sql-impl-test/src/test/java/com/evolveum/midpoint/repo/sql/ModifyTestReindex.java b/repo/repo-sql-impl-test/src/test/java/com/evolveum/midpoint/repo/sql/ModifyTestReindex.java index 41a7f322417..442a128a97d 100644 --- a/repo/repo-sql-impl-test/src/test/java/com/evolveum/midpoint/repo/sql/ModifyTestReindex.java +++ b/repo/repo-sql-impl-test/src/test/java/com/evolveum/midpoint/repo/sql/ModifyTestReindex.java @@ -90,14 +90,14 @@ public void testReindexIndexOnlyItem() throws Exception { UserType userBefore = repositoryService .getObject(UserType.class, oid, schemaHelper.getOperationOptionsBuilder().retrieve().build(), result) .asObjectable(); - display("user before", userBefore.asPrismObject()); + displayValue("user before", userBefore.asPrismObject()); repositoryService.modifyObject(UserType.class, oid, emptySet(), getModifyOptions(), result); UserType userAfter = repositoryService .getObject(UserType.class, oid, schemaHelper.getOperationOptionsBuilder().retrieve().build(), result) .asObjectable(); - display("user after", userAfter.asPrismObject()); + displayValue("user after", userAfter.asPrismObject()); ObjectQuery query = prismContext.queryFor(UserType.class) .item(INDEX_ONLY_PATH).eq("hi") diff --git a/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/AbstractIntegrationTest.java b/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/AbstractIntegrationTest.java index 2094214198f..566c8f46e18 100644 --- a/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/AbstractIntegrationTest.java +++ b/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/AbstractIntegrationTest.java @@ -1892,7 +1892,7 @@ public void display(String title, DebugDumpable dumpable) { PrismTestUtil.display(title, dumpable); } - public void display(String title, Object value) { + public void displayValue(String title, Object value) { PrismTestUtil.display(title, value); } @@ -2080,7 +2080,7 @@ protected void assertSuccess(OperationResult result) { if (result.isUnknown()) { result.computeStatus(); } - display("Operation " + result.getOperation() + " result status", result.getStatus()); + displayValue("Operation " + result.getOperation() + " result status", result.getStatus()); TestUtil.assertSuccess(result); } @@ -2088,7 +2088,7 @@ protected void assertHadnledError(OperationResult result) { if (result.isUnknown()) { result.computeStatus(); } - display("Operation " + result.getOperation() + " result status", result.getStatus()); + displayValue("Operation " + result.getOperation() + " result status", result.getStatus()); TestUtil.assertResultStatus(result, OperationResultStatus.HANDLED_ERROR); } @@ -2096,7 +2096,7 @@ protected void assertSuccess(OperationResult result, int depth) { if (result.isUnknown()) { result.computeStatus(); } - display("Operation " + result.getOperation() + " result status", result.getStatus()); + displayValue("Operation " + result.getOperation() + " result status", result.getStatus()); TestUtil.assertSuccess(result, depth); } @@ -2458,7 +2458,7 @@ protected void generateObjects(Class type, int numberO long endMillis = System.currentTimeMillis(); long duration = (endMillis - startMillis); - display(type.getSimpleName() + " import", "import of " + numberOfObjects + " roles took " + (duration / 1000) + " seconds (" + (duration / numberOfObjects) + "ms per object)"); + displayValue(type.getSimpleName() + " import", "import of " + numberOfObjects + " roles took " + (duration / 1000) + " seconds (" + (duration / numberOfObjects) + "ms per object)"); } protected String assignmentSummary(PrismObject user) { @@ -2509,7 +2509,7 @@ protected void displayCounters(InternalCounters... counters) { .append(" (").append(InternalMonitor.getCount(counter)).append(")") .append("\n"); } - display("Counters", sb.toString()); + displayValue("Counters", sb.toString()); } protected void assertMessageContains(String message, String string) { @@ -2740,7 +2740,7 @@ protected void clockForward(String duration) { XMLGregorianCalendar before = clock.currentTimeXMLGregorianCalendar(); clock.overrideDuration(duration); XMLGregorianCalendar after = clock.currentTimeXMLGregorianCalendar(); - display("Clock going forward", before + " --[" + duration + "]--> " + after); + displayValue("Clock going forward", before + " --[" + duration + "]--> " + after); } protected void assertRelationDef(List relations, QName qname, String expectedLabel) { @@ -2816,7 +2816,7 @@ protected XMLGregorianCalendar addDuration(XMLGregorianCalendar time, String dur } protected void displayCurrentTime() { - display("Current time", clock.currentTimeXMLGregorianCalendar()); + displayValue("Current time", clock.currentTimeXMLGregorianCalendar()); } protected QueryConverter getQueryConverter() { diff --git a/repo/task-quartz-impl/src/test/java/com/evolveum/midpoint/task/quartzimpl/AbstractTaskManagerTest.java b/repo/task-quartz-impl/src/test/java/com/evolveum/midpoint/task/quartzimpl/AbstractTaskManagerTest.java index 8c36c44cd55..95680a415d2 100644 --- a/repo/task-quartz-impl/src/test/java/com/evolveum/midpoint/task/quartzimpl/AbstractTaskManagerTest.java +++ b/repo/task-quartz-impl/src/test/java/com/evolveum/midpoint/task/quartzimpl/AbstractTaskManagerTest.java @@ -186,7 +186,7 @@ void waitForTaskCloseCheckingSubtasks(String taskOid, OperationResult result, lo CommonException { waitFor("Waiting for task manager to execute the task", () -> { Task task = taskManager.getTaskWithResult(taskOid, result); - display("Task tree while waiting", TaskDebugUtil.dumpTaskTree(task, result)); + displayValue("Task tree while waiting", TaskDebugUtil.dumpTaskTree(task, result)); if (task.getExecutionStatus() == TaskExecutionStatus.CLOSED) { display("Task is closed, finishing waiting: " + task); return true; @@ -288,7 +288,7 @@ void assertOptimizedCompletedBuckets(TaskQuartzImpl task) { .filter(b -> b.getState() == WorkBucketStateType.COMPLETE) .count(); if (completed > OPTIMIZED_BUCKETS_THRESHOLD) { - display("Task with more than one completed bucket", task); + displayValue("Task with more than one completed bucket", task); fail("More than one completed bucket found in task: " + completed + " in " + task); } } @@ -338,11 +338,11 @@ private Set getCachingProfiles(Task task) { return env != null ? new HashSet<>(env.getCachingProfile()) : Collections.emptySet(); } - protected void display(String title, DebugDumpable value) { + protected void displayValue(String title, DebugDumpable value) { PrismTestUtil.display(title, value); } - protected void display(String title, Object value) { + public void displayValue(String title, Object value) { PrismTestUtil.display(title, value); } diff --git a/repo/task-quartz-impl/src/test/java/com/evolveum/midpoint/task/quartzimpl/CleanupTest.java b/repo/task-quartz-impl/src/test/java/com/evolveum/midpoint/task/quartzimpl/CleanupTest.java index 92d958308c2..ec1721c4b82 100644 --- a/repo/task-quartz-impl/src/test/java/com/evolveum/midpoint/task/quartzimpl/CleanupTest.java +++ b/repo/task-quartz-impl/src/test/java/com/evolveum/midpoint/task/quartzimpl/CleanupTest.java @@ -73,7 +73,7 @@ public void testTasksCleanup() throws Exception { // THEN List> tasks = repositoryService.searchObjects(TaskType.class, null, null, result); AssertJUnit.assertNotNull(tasks); - display("tasks", tasks); + displayValue("tasks", tasks); AssertJUnit.assertEquals(1, tasks.size()); PrismObject task = tasks.get(0); diff --git a/repo/task-quartz-impl/src/test/java/com/evolveum/midpoint/task/quartzimpl/TestMiscellaneous.java b/repo/task-quartz-impl/src/test/java/com/evolveum/midpoint/task/quartzimpl/TestMiscellaneous.java index 454990e5a28..72b3fd2fe4a 100644 --- a/repo/task-quartz-impl/src/test/java/com/evolveum/midpoint/task/quartzimpl/TestMiscellaneous.java +++ b/repo/task-quartz-impl/src/test/java/com/evolveum/midpoint/task/quartzimpl/TestMiscellaneous.java @@ -117,13 +117,13 @@ public void testComputingLimitations() throws TaskManagerConfigurationException, private void assertLimitationsParsed(String value, List expected) throws TaskManagerConfigurationException, SchemaException { TaskExecutionLimitationsType parsed = TaskManagerConfiguration.parseExecutionLimitations(value); - display("parsed value of '" + value + "'", serialize(parsed)); + displayValue("parsed value of '" + value + "'", serialize(parsed)); assertEquals("Wrong parsed value for '" + value + "'", expected, parsed.getGroupLimitation()); } private void assertLimitationsComputed(String value, List expected) throws TaskManagerConfigurationException, SchemaException { TaskExecutionLimitationsType parsed = TaskManagerConfiguration.parseExecutionLimitations(value); - display("parsed value of '" + value + "'", serialize(parsed)); + displayValue("parsed value of '" + value + "'", serialize(parsed)); TaskExecutionLimitationsType computed = NodeRegistrar.computeTaskExecutionLimitations(parsed, "NODE"); assertEquals("Wrong computed value for '" + value + "'", expected, computed.getGroupLimitation()); } diff --git a/repo/task-quartz-impl/src/test/java/com/evolveum/midpoint/task/quartzimpl/TestPartitioning.java b/repo/task-quartz-impl/src/test/java/com/evolveum/midpoint/task/quartzimpl/TestPartitioning.java index 473b2b3275d..d2f836937c7 100644 --- a/repo/task-quartz-impl/src/test/java/com/evolveum/midpoint/task/quartzimpl/TestPartitioning.java +++ b/repo/task-quartz-impl/src/test/java/com/evolveum/midpoint/task/quartzimpl/TestPartitioning.java @@ -75,8 +75,8 @@ public void test100DurableRecurring() throws Exception { TaskQuartzImpl masterTask = taskManager.getTaskPlain(masterTaskOid, result); List partitions = masterTask.listSubtasks(result); - display("master task", masterTask); - display("partition tasks", partitions); + displayValue("master task", masterTask); + displayValue("partition tasks", partitions); assertEquals("Wrong # of partitions", 3, partitions.size()); @@ -93,8 +93,8 @@ public void test100DurableRecurring() throws Exception { masterTask = taskManager.getTaskPlain(masterTaskOid, result); partitions = masterTask.listSubtasks(result); - display("master task (after 2nd run)", masterTask); - display("partition tasks (after 2nd run)", partitions); + displayValue("master task (after 2nd run)", masterTask); + displayValue("partition tasks (after 2nd run)", partitions); assertEquals("Wrong # of handler executions", 6, singleHandler1.getExecutions()); } finally { diff --git a/repo/task-quartz-impl/src/test/java/com/evolveum/midpoint/task/quartzimpl/TestTaskManagerContract.java b/repo/task-quartz-impl/src/test/java/com/evolveum/midpoint/task/quartzimpl/TestTaskManagerContract.java index dae92dc9872..74204144ee2 100644 --- a/repo/task-quartz-impl/src/test/java/com/evolveum/midpoint/task/quartzimpl/TestTaskManagerContract.java +++ b/repo/task-quartz-impl/src/test/java/com/evolveum/midpoint/task/quartzimpl/TestTaskManagerContract.java @@ -822,7 +822,7 @@ public void test017WaitForSubtasksEmpty() throws Exception { try { Task rootTask = createTaskFromFile(taskFilename(), result); - display("root task", rootTask); + displayValue("root task", rootTask); waitForTaskClose(taskOid(), result, 40000, 3000); } finally { taskManager.getClusterManager().stopClusterManagerThread(10000L, result); diff --git a/repo/task-quartz-impl/src/test/java/com/evolveum/midpoint/task/quartzimpl/TestWorkBucketStrategies.java b/repo/task-quartz-impl/src/test/java/com/evolveum/midpoint/task/quartzimpl/TestWorkBucketStrategies.java index 6ef6b921854..68293aee34c 100644 --- a/repo/task-quartz-impl/src/test/java/com/evolveum/midpoint/task/quartzimpl/TestWorkBucketStrategies.java +++ b/repo/task-quartz-impl/src/test/java/com/evolveum/midpoint/task/quartzimpl/TestWorkBucketStrategies.java @@ -114,10 +114,10 @@ public void test100NumericExplicitBuckets() throws Exception { .narrowQueryForWorkBucket(task, null, UserType.class, null, bucket, result); // THEN - display("allocated bucket", bucket); + displayValue("allocated bucket", bucket); TaskQuartzImpl taskAfter = taskManager.getTaskPlain(task.getOid(), result); - display("task after", taskAfter); - display("narrowed query", narrowedQuery); + displayValue("task after", taskAfter); + displayValue("narrowed query", narrowedQuery); assertNumericBucket(bucket, null, 1, null, 123); assertOptimizedCompletedBuckets(taskAfter); @@ -132,10 +132,10 @@ public void test100NumericExplicitBuckets() throws Exception { narrowedQuery = workStateManager .narrowQueryForWorkBucket(task, null, UserType.class, null, bucket, result); // THEN - display("allocated bucket (2)", bucket); + displayValue("allocated bucket (2)", bucket); taskAfter = taskManager.getTaskPlain(task.getOid(), result); - display("task after (2)", taskAfter); - display("narrowed query (2)", narrowedQuery); + displayValue("task after (2)", taskAfter); + displayValue("narrowed query (2)", narrowedQuery); assertNumericBucket(bucket, null, 2, 123, 200); assertOptimizedCompletedBuckets(taskAfter); @@ -152,10 +152,10 @@ public void test100NumericExplicitBuckets() throws Exception { .narrowQueryForWorkBucket(task, null, UserType.class, null, bucket, result); // THEN - display("allocated bucket (3)", bucket); + displayValue("allocated bucket (3)", bucket); taskAfter = taskManager.getTaskPlain(task.getOid(), result); - display("task after (3)", taskAfter); - display("narrowed query (3)", narrowedQuery); + displayValue("task after (3)", taskAfter); + displayValue("narrowed query (3)", narrowedQuery); assertNumericBucket(bucket, null, 3, 200, null); assertOptimizedCompletedBuckets(taskAfter); @@ -169,9 +169,9 @@ public void test100NumericExplicitBuckets() throws Exception { bucket = workStateManager.getWorkBucket(task.getOid(), 0, null, null, result); // THEN - display("allocated bucket (4)", String.valueOf(bucket)); + displayValue("allocated bucket (4)", String.valueOf(bucket)); taskAfter = taskManager.getTaskPlain(task.getOid(), result); - display("task after (4)", taskAfter); + displayValue("task after (4)", taskAfter); //noinspection SimplifiedTestNGAssertion assertEquals("Expected null bucket", null, bucket); @@ -196,10 +196,10 @@ public void test110FilterExplicitBuckets() throws Exception { Integer numberOfBuckets = segmentationStrategy.estimateNumberOfBuckets(null); // THEN - display("allocated bucket", bucket); + displayValue("allocated bucket", bucket); TaskQuartzImpl taskAfter = taskManager.getTaskPlain(task.getOid(), result); - display("task after", taskAfter); - display("narrowed query", narrowedQuery); + displayValue("task after", taskAfter); + displayValue("narrowed query", narrowedQuery); assertEquals("Wrong # of estimated buckets (API)", Integer.valueOf(3), numberOfBuckets); assertEquals("Wrong # of estimated buckets (task)", Integer.valueOf(3), taskAfter.getWorkState().getNumberOfBuckets()); @@ -218,10 +218,10 @@ public void test110FilterExplicitBuckets() throws Exception { .narrowQueryForWorkBucket(task, null, ShadowType.class, null, bucket, result); // THEN - display("allocated bucket (2)", bucket); + displayValue("allocated bucket (2)", bucket); taskAfter = taskManager.getTaskPlain(task.getOid(), result); - display("task after (2)", taskAfter); - display("narrowed query (2)", narrowedQuery); + displayValue("task after (2)", taskAfter); + displayValue("narrowed query (2)", narrowedQuery); assertBucket(bucket, null, 2); assertOptimizedCompletedBuckets(taskAfter); @@ -239,10 +239,10 @@ public void test110FilterExplicitBuckets() throws Exception { .narrowQueryForWorkBucket(task, null, ShadowType.class, null, bucket, result); // THEN - display("allocated bucket (3)", bucket); + displayValue("allocated bucket (3)", bucket); taskAfter = taskManager.getTaskPlain(task.getOid(), result); - display("task after (3)", taskAfter); - display("narrowed query (3)", narrowedQuery); + displayValue("task after (3)", taskAfter); + displayValue("narrowed query (3)", narrowedQuery); assertBucket(bucket, null, 3); assertOptimizedCompletedBuckets(taskAfter); @@ -256,9 +256,9 @@ public void test110FilterExplicitBuckets() throws Exception { bucket = workStateManager.getWorkBucket(task.getOid(), 0, null, null, result); // THEN - display("allocated bucket (4)", String.valueOf(bucket)); + displayValue("allocated bucket (4)", String.valueOf(bucket)); taskAfter = taskManager.getTaskPlain(task.getOid(), result); - display("task after (4)", taskAfter); + displayValue("task after (4)", taskAfter); //noinspection SimplifiedTestNGAssertion assertEquals("Expected null bucket", null, bucket); @@ -288,7 +288,7 @@ public void test120StringPrefixBuckets() throws Exception { WorkBucketType bucket = assumeNextPrefix(segmentationStrategy, workState, "a00", 1); ObjectQuery narrowedQuery = workStateManager .narrowQueryForWorkBucket(task, null, UserType.class, null, bucket, result); - display("narrowed query (1)", narrowedQuery); + displayValue("narrowed query (1)", narrowedQuery); ObjectQuery expectedQuery = prismContext.queryFor(UserType.class) .item(UserType.F_NAME).startsWith("a00").matchingNorm() .build(); @@ -343,7 +343,7 @@ public void test125StringExactValueBuckets() throws Exception { WorkBucketType bucket = assumeNextValue(segmentationStrategy, workState, "a00", 1); ObjectQuery narrowedQuery = workStateManager .narrowQueryForWorkBucket(task, null, UserType.class, null, bucket, result); - display("narrowed query (1)", narrowedQuery); + displayValue("narrowed query (1)", narrowedQuery); ObjectQuery expectedQuery = prismContext.queryFor(UserType.class) .item(UserType.F_NAME).eq("a00").matchingNorm() .build(); @@ -395,7 +395,7 @@ public void test130StringIntervalBuckets() throws Exception { WorkBucketType bucket = assumeNextInterval(segmentationStrategy, workState, null, "00", 1); ObjectQuery narrowedQuery = workStateManager .narrowQueryForWorkBucket(task, null, UserType.class, null, bucket, result); - display("narrowed query (1)", narrowedQuery); + displayValue("narrowed query (1)", narrowedQuery); ObjectQuery expectedQuery = prismContext.queryFor(UserType.class) .item(UserType.F_NAME).lt("00").matchingNorm() .build(); @@ -404,7 +404,7 @@ public void test130StringIntervalBuckets() throws Exception { bucket = assumeNextInterval(segmentationStrategy, workState, "00", "0a", 2); narrowedQuery = workStateManager .narrowQueryForWorkBucket(task, null, UserType.class, null, bucket, result); - display("narrowed query (2)", narrowedQuery); + displayValue("narrowed query (2)", narrowedQuery); expectedQuery = prismContext.queryFor(UserType.class) .item(UserType.F_NAME).ge("00").matchingNorm() .and().item(UserType.F_NAME).lt("0a").matchingNorm() @@ -507,10 +507,10 @@ private WorkBucketType assumeNextInterval(WorkSegmentationStrategy segmentationS private WorkBucketType getNextBucket(WorkSegmentationStrategy segmentationStrategy, TaskWorkStateType workState, int expectedSequentialNumber) throws SchemaException { WorkSegmentationStrategy.GetBucketResult gbr = segmentationStrategy.getBucket(workState); - display("get bucket result", gbr); + displayValue("get bucket result", gbr); assertTrue("Wrong answer", gbr instanceof WorkSegmentationStrategy.GetBucketResult.NewBuckets); WorkSegmentationStrategy.GetBucketResult.NewBuckets nbr = (WorkSegmentationStrategy.GetBucketResult.NewBuckets) gbr; - display("new buckets obtained", nbr.newBuckets); + displayValue("new buckets obtained", nbr.newBuckets); assertEquals("Wrong new buckets count", 1, nbr.newBuckets.size()); WorkBucketType newBucket = nbr.newBuckets.get(0); assertEquals("Wrong sequential number", expectedSequentialNumber, newBucket.getSequentialNumber()); @@ -519,7 +519,7 @@ private WorkBucketType getNextBucket(WorkSegmentationStrategy segmentationStrate private void assumeNoNextBucket(WorkSegmentationStrategy segmentationStrategy, TaskWorkStateType workState) throws SchemaException { WorkSegmentationStrategy.GetBucketResult gbr = segmentationStrategy.getBucket(workState); - display("get bucket result", gbr); + displayValue("get bucket result", gbr); assertTrue("Wrong answer", gbr instanceof WorkSegmentationStrategy.GetBucketResult.NothingFound); WorkSegmentationStrategy.GetBucketResult.NothingFound nothingFound = (WorkSegmentationStrategy.GetBucketResult.NothingFound) gbr; //noinspection SimplifiedTestNGAssertion diff --git a/repo/task-quartz-impl/src/test/java/com/evolveum/midpoint/task/quartzimpl/TestWorkDistribution.java b/repo/task-quartz-impl/src/test/java/com/evolveum/midpoint/task/quartzimpl/TestWorkDistribution.java index 6783737433d..f0e51823889 100644 --- a/repo/task-quartz-impl/src/test/java/com/evolveum/midpoint/task/quartzimpl/TestWorkDistribution.java +++ b/repo/task-quartz-impl/src/test/java/com/evolveum/midpoint/task/quartzimpl/TestWorkDistribution.java @@ -121,11 +121,11 @@ public void test100AllocateBucket() throws Exception { WorkBucketType bucket = workStateManager.getWorkBucket(worker.getOid(), 0, null, null, result); // THEN - display("allocated bucket", bucket); + displayValue("allocated bucket", bucket); TaskQuartzImpl coordinatorAfter = taskManager.getTaskPlain(coordinatorTaskOid(), result); TaskQuartzImpl workerAfter = taskManager.getTaskPlain(worker.getOid(), result); - display("coordinator task after", coordinatorAfter); - display("worker task after", workerAfter); + displayValue("coordinator task after", coordinatorAfter); + displayValue("worker task after", workerAfter); assertNumericBucket(bucket, null, 1, 0, 1000); List wBuckets = workerAfter.getWorkState().getBucket(); @@ -152,9 +152,9 @@ public void test105AllocateBucketStandalone() throws Exception { WorkBucketType bucket = workStateManager.getWorkBucket(standalone.getOid(), 0, null, null, result); // THEN - display("allocated bucket", bucket); + displayValue("allocated bucket", bucket); TaskQuartzImpl standaloneAfter = taskManager.getTaskPlain(standalone.getOid(), result); - display("task after", standaloneAfter); + displayValue("task after", standaloneAfter); List wBuckets = standaloneAfter.getWorkState().getBucket(); assertEquals("Wrong # of buckets", 1, wBuckets.size()); @@ -178,9 +178,9 @@ public void test107AllocateBucketStandaloneBatched() throws Exception { WorkBucketType bucket = workStateManager.getWorkBucket(standalone.getOid(), 0, null, null, result); // THEN - display("allocated bucket", bucket); + displayValue("allocated bucket", bucket); TaskQuartzImpl standaloneAfter = taskManager.getTaskPlain(standalone.getOid(), result); - display("task after", standaloneAfter); + displayValue("task after", standaloneAfter); List wBuckets = standaloneAfter.getWorkState().getBucket(); assertEquals("Wrong # of buckets", 7, wBuckets.size()); @@ -204,10 +204,10 @@ public void test110AllocateTwoBucketsStandalone() throws Exception { WorkBucketType bucket2 = workStateManager.getWorkBucket(standalone.getOid(), 0, null, null, result); // THEN - display("1st obtained bucket", bucket1); - display("2nd obtained bucket", bucket2); + displayValue("1st obtained bucket", bucket1); + displayValue("2nd obtained bucket", bucket2); standalone = taskManager.getTaskPlain(standalone.getOid(), result); - display("task after 2xget", standalone); + displayValue("task after 2xget", standalone); assertNumericBucket(bucket1, WorkBucketStateType.READY, 1, 0, 100); assertNumericBucket(bucket2, WorkBucketStateType.READY, 1, 0, 100); // should be the same @@ -222,9 +222,9 @@ public void test110AllocateTwoBucketsStandalone() throws Exception { WorkBucketType bucket3 = workStateManager.getWorkBucket(standalone.getOid(), 0, null, null, result); // THEN - display("bucket obtained after complete", bucket3); + displayValue("bucket obtained after complete", bucket3); standalone = taskManager.getTaskPlain(standalone.getOid(), result); - display("task after complete+get", standalone); + displayValue("task after complete+get", standalone); assertOptimizedCompletedBuckets(standalone); assertNumericBucket(bucket3, WorkBucketStateType.READY, 2, 100, 200); @@ -240,9 +240,9 @@ public void test110AllocateTwoBucketsStandalone() throws Exception { WorkBucketType bucket4 = workStateManager.getWorkBucket(standalone.getOid(), 0, null, null, result); // THEN - display("bucket obtained after 2nd complete", bucket4); + displayValue("bucket obtained after 2nd complete", bucket4); standalone = taskManager.getTaskPlain(standalone.getOid(), result); - display("task after complete+get+complete+get", standalone); + displayValue("task after complete+get+complete+get", standalone); assertNumericBucket(bucket4, WorkBucketStateType.READY, 3, 200, 300); @@ -299,21 +299,21 @@ public void test130AllocateReleaseCompleteSequence() throws Exception { .getWorkBucket(worker4.getOid(), 0, null, null, result); // should be the same as bucket4 // THEN - display("1st allocated bucket", bucket1); - display("2nd allocated bucket", bucket2); - display("3rd allocated bucket", bucket3); - display("4th allocated bucket", bucket4); - display("4+th allocated bucket", bucket4a); + displayValue("1st allocated bucket", bucket1); + displayValue("2nd allocated bucket", bucket2); + displayValue("3rd allocated bucket", bucket3); + displayValue("4th allocated bucket", bucket4); + displayValue("4+th allocated bucket", bucket4a); worker1 = taskManager.getTaskPlain(worker1.getOid(), result); worker2 = taskManager.getTaskPlain(worker2.getOid(), result); worker3 = taskManager.getTaskPlain(worker3.getOid(), result); worker4 = taskManager.getTaskPlain(worker4.getOid(), result); Task coordinator = taskManager.getTaskPlain(coordinatorTaskOid(), result); - display("coordinator task after 4+1x allocation", coordinator); - display("worker1 task after 4+1x allocation", worker1); - display("worker2 task after 4+1x allocation", worker2); - display("worker3 task after 4+1x allocation", worker3); - display("worker4 task after 4+1x allocation", worker4); + displayValue("coordinator task after 4+1x allocation", coordinator); + displayValue("worker1 task after 4+1x allocation", worker1); + displayValue("worker2 task after 4+1x allocation", worker2); + displayValue("worker3 task after 4+1x allocation", worker3); + displayValue("worker4 task after 4+1x allocation", worker4); assertNumericBucket(bucket1, null, 1, 0, 1); assertNumericBucket(bucket2, null, 2, 1, 2); @@ -347,9 +347,9 @@ public void test130AllocateReleaseCompleteSequence() throws Exception { // THEN worker2 = taskManager.getTaskPlain(worker2.getOid(), result); - display("worker2 after completion of 2nd bucket", worker2); + displayValue("worker2 after completion of 2nd bucket", worker2); coordinator = taskManager.getTaskPlain(coordinator.getOid(), result); - display("coordinator after completion of 2nd bucket", coordinator); + displayValue("coordinator after completion of 2nd bucket", coordinator); buckets = new ArrayList<>(coordinator.getWorkState().getBucket()); sortBucketsBySequentialNumber(buckets); @@ -369,9 +369,9 @@ public void test130AllocateReleaseCompleteSequence() throws Exception { // THEN worker1 = taskManager.getTaskPlain(worker1.getOid(), result); - display("worker1 after completion of 1st bucket and fetching next one", worker1); + displayValue("worker1 after completion of 1st bucket and fetching next one", worker1); coordinator = taskManager.getTaskPlain(coordinator.getOid(), result); - display("coordinator after completion of 1st bucket and fetching next one", coordinator); + displayValue("coordinator after completion of 1st bucket and fetching next one", coordinator); assertNumericBucket(bucket, null, 5, 4, 5); @@ -400,9 +400,9 @@ public void test130AllocateReleaseCompleteSequence() throws Exception { // THEN worker4 = taskManager.getTaskPlain(worker4.getOid(), result); - display("worker4 after releasing of 4th bucket", worker4); + displayValue("worker4 after releasing of 4th bucket", worker4); coordinator = taskManager.getTaskPlain(coordinator.getOid(), result); - display("coordinator after releasing of 4th bucket", coordinator); + displayValue("coordinator after releasing of 4th bucket", coordinator); buckets = new ArrayList<>(coordinator.getWorkState().getBucket()); sortBucketsBySequentialNumber(buckets); @@ -421,11 +421,11 @@ public void test130AllocateReleaseCompleteSequence() throws Exception { // THEN worker3 = taskManager.getTaskPlain(worker3.getOid(), result); - display("worker3 after completion of 3rd bucket and getting next one", worker3); + displayValue("worker3 after completion of 3rd bucket and getting next one", worker3); worker5 = taskManager.getTaskPlain(worker5.getOid(), result); - display("worker5 after completion of 3rd bucket and getting next one", worker5); + displayValue("worker5 after completion of 3rd bucket and getting next one", worker5); coordinator = taskManager.getTaskPlain(coordinator.getOid(), result); - display("coordinator after completion of 3rd bucket and getting next one", coordinator); + displayValue("coordinator after completion of 3rd bucket and getting next one", coordinator); assertNumericBucket(bucket, null, 4, 3, 4); @@ -448,11 +448,11 @@ public void test130AllocateReleaseCompleteSequence() throws Exception { // THEN worker1 = taskManager.getTaskPlain(worker1.getOid(), result); - display("worker1 after completion of 5th bucket and closing worker5", worker1); + displayValue("worker1 after completion of 5th bucket and closing worker5", worker1); worker5 = taskManager.getTaskPlain(worker5.getOid(), result); - display("worker5 after completion of 5th bucket and closing worker5", worker5); + displayValue("worker5 after completion of 5th bucket and closing worker5", worker5); coordinator = taskManager.getTaskPlain(coordinator.getOid(), result); - display("coordinator after completion of 5th bucket and closing worker5", coordinator); + displayValue("coordinator after completion of 5th bucket and closing worker5", coordinator); buckets = new ArrayList<>(coordinator.getWorkState().getBucket()); assertEquals(2, buckets.size()); @@ -466,9 +466,9 @@ public void test130AllocateReleaseCompleteSequence() throws Exception { // THEN worker1 = taskManager.getTaskPlain(worker1.getOid(), result); - display("worker1 after reclaiming mis-allocated bucket", worker1); + displayValue("worker1 after reclaiming mis-allocated bucket", worker1); coordinator = taskManager.getTaskPlain(coordinator.getOid(), result); - display("coordinator after reclaiming mis-allocated bucket", coordinator); + displayValue("coordinator after reclaiming mis-allocated bucket", coordinator); assertNumericBucket(bucket, null, 4, 3, 4); @@ -486,9 +486,9 @@ public void test130AllocateReleaseCompleteSequence() throws Exception { // THEN worker1 = taskManager.getTaskPlain(worker1.getOid(), result); - display("worker1 after completion of 4th bucket", worker1); + displayValue("worker1 after completion of 4th bucket", worker1); coordinator = taskManager.getTaskPlain(coordinator.getOid(), result); - display("coordinator after completion of 4th bucket", coordinator); + displayValue("coordinator after completion of 4th bucket", coordinator); buckets = new ArrayList<>(coordinator.getWorkState().getBucket()); assertEquals(1, buckets.size()); @@ -518,8 +518,8 @@ public void test200OneWorkerTask() throws Exception { TaskQuartzImpl coordinatorAfter = taskManager.getTaskPlain(coordinatorTaskOid, result); TaskQuartzImpl workerAfter = taskManager.getTaskPlain(worker.getOid(), result); - display("coordinator task after", coordinatorAfter); - display("worker task after", workerAfter); + displayValue("coordinator task after", coordinatorAfter); + displayValue("worker task after", workerAfter); assertTotalSuccessCount(30, singleton(workerAfter)); } finally { @@ -555,13 +555,13 @@ public void test210ThreeWorkersTask() throws Exception { worker1 = taskManager.getTaskPlain(worker1.getOid(), result); worker2 = taskManager.getTaskPlain(worker2.getOid(), result); worker3 = taskManager.getTaskPlain(worker3.getOid(), result); - display("coordinator task after", coordinatorAfter); - display("worker1 task after", worker1); - display("worker2 task after", worker2); - display("worker3 task after", worker3); - display("worker1 op stats task after", PrismTestUtil.serializeAnyDataWrapped(worker1.getStoredOperationStats())); - display("worker2 op stats task after", PrismTestUtil.serializeAnyDataWrapped(worker2.getStoredOperationStats())); - display("worker3 op stats task after", PrismTestUtil.serializeAnyDataWrapped(worker3.getStoredOperationStats())); + displayValue("coordinator task after", coordinatorAfter); + displayValue("worker1 task after", worker1); + displayValue("worker2 task after", worker2); + displayValue("worker3 task after", worker3); + displayValue("worker1 op stats task after", PrismTestUtil.serializeAnyDataWrapped(worker1.getStoredOperationStats())); + displayValue("worker2 op stats task after", PrismTestUtil.serializeAnyDataWrapped(worker2.getStoredOperationStats())); + displayValue("worker3 op stats task after", PrismTestUtil.serializeAnyDataWrapped(worker3.getStoredOperationStats())); assertNumberOfBuckets(coordinatorAfter, 11); @@ -622,15 +622,15 @@ public void test220WorkerSuspend() throws Exception { worker1 = taskManager.getTaskPlain(worker1.getOid(), result); worker2 = taskManager.getTaskPlain(worker2.getOid(), result); worker3 = taskManager.getTaskPlain(worker3.getOid(), result); - display("coordinator task after unfinished run", coordinatorAfter); - display("worker1 task after unfinished run", worker1); - display("worker2 task after unfinished run", worker2); - display("worker3 task after unfinished run", worker3); - display("worker1 op stats task after unfinished run", + displayValue("coordinator task after unfinished run", coordinatorAfter); + displayValue("worker1 task after unfinished run", worker1); + displayValue("worker2 task after unfinished run", worker2); + displayValue("worker3 task after unfinished run", worker3); + displayValue("worker1 op stats task after unfinished run", PrismTestUtil.serializeAnyDataWrapped(worker1.getStoredOperationStats())); - display("worker2 op stats task after unfinished run", + displayValue("worker2 op stats task after unfinished run", PrismTestUtil.serializeAnyDataWrapped(worker2.getStoredOperationStats())); - display("worker3 op stats task after unfinished run", + displayValue("worker3 op stats task after unfinished run", PrismTestUtil.serializeAnyDataWrapped(worker3.getStoredOperationStats())); assertTotalSuccessCount(107 - 6, Arrays.asList(worker1, worker2, worker3)); @@ -654,7 +654,7 @@ public void test220WorkerSuspend() throws Exception { waitForTaskClose(coordinatorTaskOid, result, DEFAULT_TIMEOUT, 200); coordinatorAfter = taskManager.getTaskPlain(coordinatorTaskOid, result); - display("coordinator task after finished run", coordinatorAfter); + displayValue("coordinator task after finished run", coordinatorAfter); assertOptimizedCompletedBuckets(coordinatorAfter); @@ -706,15 +706,15 @@ public void test230WorkerException() throws Exception { worker1 = taskManager.getTaskPlain(worker1.getOid(), result); worker2 = taskManager.getTaskPlain(worker2.getOid(), result); worker3 = taskManager.getTaskPlain(worker3.getOid(), result); - display("coordinator task after unfinished run", coordinatorAfter); - display("worker1 task after unfinished run", worker1); - display("worker2 task after unfinished run", worker2); - display("worker3 task after unfinished run", worker3); - display("worker1 op stats task after unfinished run", + displayValue("coordinator task after unfinished run", coordinatorAfter); + displayValue("worker1 task after unfinished run", worker1); + displayValue("worker2 task after unfinished run", worker2); + displayValue("worker3 task after unfinished run", worker3); + displayValue("worker1 op stats task after unfinished run", PrismTestUtil.serializeAnyDataWrapped(worker1.getStoredOperationStats())); - display("worker2 op stats task after unfinished run", + displayValue("worker2 op stats task after unfinished run", PrismTestUtil.serializeAnyDataWrapped(worker2.getStoredOperationStats())); - display("worker3 op stats task after unfinished run", + displayValue("worker3 op stats task after unfinished run", PrismTestUtil.serializeAnyDataWrapped(worker3.getStoredOperationStats())); assertTotalSuccessCount(107 - 6, Arrays.asList(worker1, worker2, worker3)); @@ -741,13 +741,13 @@ public void test230WorkerException() throws Exception { worker1 = taskManager.getTaskPlain(worker1.getOid(), result); worker2 = taskManager.getTaskPlain(worker2.getOid(), result); worker3 = taskManager.getTaskPlain(worker3.getOid(), result); - display("coordinator task after", coordinatorAfter); - display("worker1 task after", worker1); - display("worker2 task after", worker2); - display("worker3 task after", worker3); - display("worker1 op stats task after", PrismTestUtil.serializeAnyDataWrapped(worker1.getStoredOperationStats())); - display("worker2 op stats task after", PrismTestUtil.serializeAnyDataWrapped(worker2.getStoredOperationStats())); - display("worker3 op stats task after", PrismTestUtil.serializeAnyDataWrapped(worker3.getStoredOperationStats())); + displayValue("coordinator task after", coordinatorAfter); + displayValue("worker1 task after", worker1); + displayValue("worker2 task after", worker2); + displayValue("worker3 task after", worker3); + displayValue("worker1 op stats task after", PrismTestUtil.serializeAnyDataWrapped(worker1.getStoredOperationStats())); + displayValue("worker2 op stats task after", PrismTestUtil.serializeAnyDataWrapped(worker2.getStoredOperationStats())); + displayValue("worker3 op stats task after", PrismTestUtil.serializeAnyDataWrapped(worker3.getStoredOperationStats())); // TODO change after correct resuming assertTotalSuccessCount(107 - 6 + 10, coordinatorAfter.listSubtasks(result)); @@ -780,13 +780,13 @@ public void test300NarrowQueryOneWorkerTask() throws Exception { TaskQuartzImpl coordinatorAfter = taskManager.getTaskPlain(coordinatorTaskOid, result); TaskQuartzImpl workerAfter = taskManager.getTaskPlain(worker.getOid(), result); - display("coordinator task after", coordinatorAfter); - display("worker task after", workerAfter); + displayValue("coordinator task after", coordinatorAfter); + displayValue("worker task after", workerAfter); assertTotalSuccessCount(30, singleton(workerAfter)); List qe = workBucketsTaskHandler.getQueriesExecuted(); - display("Queries executed", qe); + displayValue("Queries executed", qe); assertEquals("Wrong # of queries", 3, qe.size()); ObjectQuery q1 = prismContext.queryFor(UserType.class) .item(UserType.F_ITERATION).ge(BigInteger.valueOf(0)) diff --git a/repo/task-quartz-impl/src/test/java/com/evolveum/midpoint/task/quartzimpl/TestWorkersManagement.java b/repo/task-quartz-impl/src/test/java/com/evolveum/midpoint/task/quartzimpl/TestWorkersManagement.java index f3602c616d5..35e96afedf3 100644 --- a/repo/task-quartz-impl/src/test/java/com/evolveum/midpoint/task/quartzimpl/TestWorkersManagement.java +++ b/repo/task-quartz-impl/src/test/java/com/evolveum/midpoint/task/quartzimpl/TestWorkersManagement.java @@ -121,8 +121,8 @@ public void test100CreateWorkersSingle() throws Exception { List workers = coordinatorTask.listSubtasks(result); assertEquals("Wrong # of workers", 1, workers.size()); - display("coordinator task", coordinatorTask); - display("worker task", workers.get(0)); + displayValue("coordinator task", coordinatorTask); + displayValue("worker task", workers.get(0)); displayBucketOpStatistics("coordinator", coordinatorTask); displayBucketOpStatistics("worker", workers.get(0)); assertCachingProfiles(coordinatorTask, "profile1"); @@ -145,8 +145,8 @@ public void test100CreateWorkersSingle() throws Exception { workers = coordinatorTask.listSubtasks(result); assertEquals("Wrong # of workers", 1, workers.size()); - display("coordinator task after re-run", coordinatorTask); - display("worker task after re-run", workers.get(0)); + displayValue("coordinator task after re-run", coordinatorTask); + displayValue("worker task after re-run", workers.get(0)); Thread.sleep(1000); // if workers would be started again, we would get some more processing here assertEquals("Wrong # of items processed", 8, workBucketsTaskHandler.getItemsProcessed()); @@ -159,7 +159,7 @@ private void displayBucketOpStatistics(String label, Task task) throws SchemaExc OperationStatsType stats = task.getStoredOperationStats(); WorkBucketManagementPerformanceInformationType bucketStats = stats != null ? stats.getWorkBucketManagementPerformanceInformation() : null; String text = bucketStats != null ? prismContext.yamlSerializer().root(new QName("stats")).serializeRealValue(bucketStats) : "(null)"; - display("Bucket op stats for " + label, text); + displayValue("Bucket op stats for " + label, text); } @Test @@ -183,8 +183,8 @@ public void test110CreateWorkersRecurring() throws Exception { List workers = coordinatorTask.listSubtasks(result); assertEquals("Wrong # of workers", 1, workers.size()); - display("coordinator task", coordinatorTask); - display("worker task", workers.get(0)); + displayValue("coordinator task", coordinatorTask); + displayValue("worker task", workers.get(0)); waitForTaskClose(workers.get(0).getOid(), result, DEFAULT_TIMEOUT, DEFAULT_SLEEP_INTERVAL); @@ -204,8 +204,8 @@ public void test110CreateWorkersRecurring() throws Exception { workers = coordinatorTask.listSubtasks(result); assertEquals("Wrong # of workers", 1, workers.size()); - display("coordinator task after re-run", coordinatorTask); - display("worker task after re-run", workers.get(0)); + displayValue("coordinator task after re-run", coordinatorTask); + displayValue("worker task after re-run", workers.get(0)); waitForTaskClose(workers.get(0).getOid(), result, DEFAULT_TIMEOUT, DEFAULT_SLEEP_INTERVAL); @@ -224,8 +224,8 @@ public void test110CreateWorkersRecurring() throws Exception { assertTrue("tasks were not stopped", stopped); - display("coordinator task after suspend-when-waiting", coordinatorTask); - display("worker task after suspend-when-waiting", worker); + displayValue("coordinator task after suspend-when-waiting", coordinatorTask); + displayValue("worker task after suspend-when-waiting", worker); assertEquals("Wrong execution status of coordinator", TaskExecutionStatus.SUSPENDED, coordinatorTask.getExecutionStatus()); @@ -247,8 +247,8 @@ public void test110CreateWorkersRecurring() throws Exception { assertEquals("Wrong # of workers", 1, workers.size()); worker = workers.get(0); - display("coordinator task after resume-from-suspend-when-waiting", coordinatorTask); - display("worker task after resume-from-suspend-when-waiting", worker); + displayValue("coordinator task after resume-from-suspend-when-waiting", coordinatorTask); + displayValue("worker task after resume-from-suspend-when-waiting", worker); assertEquals("Wrong execution status of coordinator", TaskExecutionStatus.RUNNABLE, coordinatorTask.getExecutionStatus()); @@ -269,8 +269,8 @@ public void test110CreateWorkersRecurring() throws Exception { assertEquals("Wrong # of workers", 1, workers.size()); worker = workers.get(0); - display("coordinator task after suspend-when-running", coordinatorTask); - display("worker task after suspend-when-running", worker); + displayValue("coordinator task after suspend-when-running", coordinatorTask); + displayValue("worker task after suspend-when-running", worker); assertEquals("Wrong execution status of coordinator", TaskExecutionStatus.SUSPENDED, coordinatorTask.getExecutionStatus()); @@ -294,8 +294,8 @@ public void test110CreateWorkersRecurring() throws Exception { assertEquals("Wrong # of workers", 1, workers.size()); worker = workers.get(0); - display("coordinator task after resume-after-2nd-suspend", coordinatorTask); - display("worker task after resume-after-2nd-suspend", worker); + displayValue("coordinator task after resume-after-2nd-suspend", coordinatorTask); + displayValue("worker task after resume-after-2nd-suspend", worker); displayBucketOpStatistics("coordinator", coordinatorTask); displayBucketOpStatistics("worker", worker); @@ -330,8 +330,8 @@ public void test200SimplePartitioning() throws Exception { TaskQuartzImpl masterTask = taskManager.getTaskPlain(masterTaskOid, result); List subtasks = masterTask.listSubtasks(result); - display("master task", masterTask); - display("subtasks", subtasks); + displayValue("master task", masterTask); + displayValue("subtasks", subtasks); assertEquals("Wrong task kind", TaskKindType.PARTITIONED_MASTER, masterTask.getWorkManagement().getTaskKind()); assertEquals("Wrong # of partitions", 3, subtasks.size()); @@ -379,8 +379,8 @@ public void test210PartitioningToWorkersSingleBucket() throws Exception { TaskQuartzImpl masterTask = taskManager.getTaskPlain(masterTaskOid, result); List subtasks = masterTask.listSubtasks(result); - display("master task", masterTask); - display("subtasks", subtasks); + displayValue("master task", masterTask); + displayValue("subtasks", subtasks); assertEquals("Wrong task kind", TaskKindType.PARTITIONED_MASTER, masterTask.getWorkManagement().getTaskKind()); assertEquals("Wrong # of partitions", 3, subtasks.size()); @@ -393,9 +393,9 @@ public void test210PartitioningToWorkersSingleBucket() throws Exception { waitForTaskCloseCheckingSubtasks(second.getOid(), result, DEFAULT_TIMEOUT, DEFAULT_SLEEP_INTERVAL); second = taskManager.getTaskPlain(second.getOid(), result); - display("Second task after completion", second); + displayValue("Second task after completion", second); List secondSubtasks = second.listSubtasks(result); - display("Subtasks of second task after completion", secondSubtasks); + displayValue("Subtasks of second task after completion", secondSubtasks); assertEquals("Wrong # of second task's subtasks", 3, secondSubtasks.size()); assertCachingProfiles(masterTask, "profile1"); @@ -406,9 +406,9 @@ public void test210PartitioningToWorkersSingleBucket() throws Exception { waitForTaskCloseCheckingSubtasks(third.getOid(), result, DEFAULT_TIMEOUT, DEFAULT_SLEEP_INTERVAL); third = taskManager.getTaskPlain(third.getOid(), result); - display("Third task after completion", third); + displayValue("Third task after completion", third); List thirdSubtasks = third.listSubtasks(result); - display("Subtasks of third task after completion", thirdSubtasks); + displayValue("Subtasks of third task after completion", thirdSubtasks); assertEquals("Wrong # of third task's subtasks", 2, thirdSubtasks.size()); waitForTaskCloseCheckingSubtasks(masterTaskOid, result, DEFAULT_TIMEOUT, DEFAULT_SLEEP_INTERVAL); @@ -442,8 +442,8 @@ public void test220PartitioningToWorkersMoreBuckets() throws Exception { TaskQuartzImpl masterTask = taskManager.getTaskPlain(masterTaskOid, result); List subtasks = masterTask.listSubtasks(result); - display("master task", masterTask); - display("subtasks", subtasks); + displayValue("master task", masterTask); + displayValue("subtasks", subtasks); assertEquals("Wrong task kind", TaskKindType.PARTITIONED_MASTER, masterTask.getWorkManagement().getTaskKind()); assertEquals("Wrong # of partitions", 3, subtasks.size()); @@ -456,16 +456,16 @@ public void test220PartitioningToWorkersMoreBuckets() throws Exception { waitForTaskCloseCheckingSubtasks(second.getOid(), result, 30000L, DEFAULT_SLEEP_INTERVAL); second = taskManager.getTaskPlain(second.getOid(), result); - display("Second task after completion", second); + displayValue("Second task after completion", second); List secondSubtasks = second.listSubtasks(result); - display("Subtasks of second task after completion", secondSubtasks); + displayValue("Subtasks of second task after completion", secondSubtasks); assertEquals("Wrong # of second task's subtasks", 3, secondSubtasks.size()); waitForTaskCloseCheckingSubtasks(third.getOid(), result, 20000L, DEFAULT_SLEEP_INTERVAL); third = taskManager.getTaskPlain(third.getOid(), result); - display("Third task after completion", third); + displayValue("Third task after completion", third); List thirdSubtasks = third.listSubtasks(result); - display("Subtasks of third task after completion", thirdSubtasks); + displayValue("Subtasks of third task after completion", thirdSubtasks); assertEquals("Wrong # of third task's subtasks", 2, thirdSubtasks.size()); assertCachingProfiles(masterTask, "profile1"); diff --git a/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/AbstractEDirTest.java b/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/AbstractEDirTest.java index f8a5f33bb80..088e4f36048 100644 --- a/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/AbstractEDirTest.java +++ b/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/AbstractEDirTest.java @@ -598,7 +598,7 @@ public void test250AssignGuybrushPirates() throws Exception { TestUtil.assertSuccess(result); Entry entry = assertLdapAccount(USER_GUYBRUSH_USERNAME, USER_GUYBRUSH_FULL_NAME); - display("Entry", entry); + displayValue("Entry", entry); assertAttribute(entry, "loginDisabled", "TRUE"); assertEDirGroupMember(entry, GROUP_PIRATES_NAME); @@ -656,11 +656,11 @@ public void test300AssignBarbossaPirates() throws Exception { TestUtil.assertSuccess(result); Entry entry = assertLdapAccount(USER_BARBOSSA_USERNAME, USER_BARBOSSA_FULL_NAME); - display("Entry", entry); + displayValue("Entry", entry); assertAttribute(entry, "title", "Captain"); Entry groupEntry = assertEDirGroupMember(entry, GROUP_PIRATES_NAME); - display("Group entry", groupEntry); + displayValue("Group entry", groupEntry); PrismObject user = getUser(USER_BARBOSSA_OID); String shadowOid = getSingleLinkOid(user); @@ -924,7 +924,7 @@ public void test890UnAssignBarbossaPirates() throws Exception { TestUtil.assertSuccess(result); Entry entry = assertLdapAccount(USER_CPTBARBOSSA_USERNAME, USER_BARBOSSA_FULL_NAME); - display("Entry", entry); + displayValue("Entry", entry); assertAttribute(entry, "title", "Captain"); assertEDirNoGroupMember(entry, GROUP_PIRATES_NAME); diff --git a/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/AbstractLdapConnTest.java b/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/AbstractLdapConnTest.java index 856ab66fb89..a4898e7dab7 100644 --- a/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/AbstractLdapConnTest.java +++ b/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/AbstractLdapConnTest.java @@ -881,7 +881,7 @@ public void test290ModifyUserBarbossaRename() throws Exception { TestUtil.assertSuccess(result); Entry entry = assertLdapAccount(USER_CPTBARBOSSA_USERNAME, USER_BARBOSSA_FULL_NAME); - display("LDAP entry after", entry); + displayValue("LDAP entry after", entry); assertEquals("Wrong DN", toAccountDn(USER_CPTBARBOSSA_USERNAME), entry.getDn().toString()); assertAttribute(entry, "title", "Captain"); @@ -925,7 +925,7 @@ public void test292ModifyUserBarbossaRenameCapitalized() throws Exception { TestUtil.assertSuccess(result); Entry entry = assertLdapAccount(USER_CPTBARBOSSA_USERNAME, USER_BARBOSSA_FULL_NAME); - display("LDAP entry after", entry); + displayValue("LDAP entry after", entry); assertAttribute(entry, "title", "Captain"); assertEquals("Wrong DN", toAccountDn(USER_CPTBARBOSSA_USERNAME), entry.getDn().toString()); @@ -1004,9 +1004,9 @@ public void test300AssignRoleEvilToLechuck() throws Exception { assertLdapNoGroupMember(entry, GROUP_UNDEAD_CN); Entry ldapEntryEvil = getLdapEntry(toGroupDn(GROUP_EVIL_CN)); - display("Evil group", ldapEntryEvil); + displayValue("Evil group", ldapEntryEvil); Entry ldapEntryUndead = getLdapEntry(toGroupDn(GROUP_UNDEAD_CN)); - display("Undead group", ldapEntryUndead); + displayValue("Undead group", ldapEntryUndead); assertLdapConnectorInstances(1, 2); } @@ -1040,9 +1040,9 @@ public void test302AssignRoleUndeadToLechuck() throws Exception { assertLdapGroupMember(entry, GROUP_UNDEAD_CN); Entry ldapEntryEvil = getLdapEntry(toGroupDn(GROUP_EVIL_CN)); - display("Evil group", ldapEntryEvil); + displayValue("Evil group", ldapEntryEvil); Entry ldapEntryUndead = getLdapEntry(toGroupDn(GROUP_UNDEAD_CN)); - display("Undead group", ldapEntryUndead); + displayValue("Undead group", ldapEntryUndead); assertLdapConnectorInstances(1, 2); } @@ -1076,9 +1076,9 @@ public void test306UnassignRoleEvilFromLechuck() throws Exception { assertLdapGroupMember(entry, GROUP_UNDEAD_CN); Entry ldapEntryEvil = getLdapEntry(toGroupDn(GROUP_EVIL_CN)); - display("Evil group", ldapEntryEvil); + displayValue("Evil group", ldapEntryEvil); Entry ldapEntryUndead = getLdapEntry(toGroupDn(GROUP_UNDEAD_CN)); - display("Undead group", ldapEntryUndead); + displayValue("Undead group", ldapEntryUndead); assertLdapConnectorInstances(1, 2); } @@ -1112,9 +1112,9 @@ public void test309UnassignRoleUndeadFromLechuck() throws Exception { assertLdapNoGroupMember(accountLechuckDn, GROUP_UNDEAD_CN); Entry ldapEntryEvil = getLdapEntry(toGroupDn(GROUP_EVIL_CN)); - display("Evil group", ldapEntryEvil); + displayValue("Evil group", ldapEntryEvil); Entry ldapEntryUndead = getLdapEntry(toGroupDn(GROUP_UNDEAD_CN)); - display("Undead group", ldapEntryUndead); + displayValue("Undead group", ldapEntryUndead); assertLdapConnectorInstances(1, 2); } @@ -1171,7 +1171,7 @@ public void test312AssignRoleEvilToBarbossa() throws Exception { TestUtil.assertSuccess(result); Entry entry = assertLdapAccount(USER_CPTBARBOSSA_USERNAME, USER_BARBOSSA_FULL_NAME); - display("Account LDAP entry", entry); + displayValue("Account LDAP entry", entry); PrismObject user = getUser(USER_BARBOSSA_OID); String shadowOid = getSingleLinkOid(user); @@ -1186,9 +1186,9 @@ public void test312AssignRoleEvilToBarbossa() throws Exception { assertNotNull("No identifier in " + shadow, accountBarbossaEntryId); Entry ldapEntryEvil = getLdapEntry(toGroupDn(GROUP_EVIL_CN)); - display("Evil group", ldapEntryEvil); + displayValue("Evil group", ldapEntryEvil); Entry ldapEntryUndead = getLdapEntry(toGroupDn(GROUP_UNDEAD_CN)); - display("Undead group", ldapEntryUndead); + displayValue("Undead group", ldapEntryUndead); assertLdapGroupMember(entry, GROUP_EVIL_CN); assertLdapNoGroupMember(entry, GROUP_UNDEAD_CN); @@ -1221,7 +1221,7 @@ public void test314ModifyUserBarbossaRenameBack() throws Exception { TestUtil.assertSuccess(result); Entry entry = assertLdapAccount(USER_BARBOSSA_USERNAME, USER_BARBOSSA_FULL_NAME); - display("LDAP entry after", entry); + displayValue("LDAP entry after", entry); assertEquals("Wrong DN", toAccountDn(USER_BARBOSSA_USERNAME), entry.getDn().toString()); PrismObject user = getUser(USER_BARBOSSA_OID); @@ -1239,9 +1239,9 @@ public void test314ModifyUserBarbossaRenameBack() throws Exception { } Entry ldapEntryEvil = getLdapEntry(toGroupDn(GROUP_EVIL_CN)); - display("Evil group", ldapEntryEvil); + displayValue("Evil group", ldapEntryEvil); Entry ldapEntryUndead = getLdapEntry(toGroupDn(GROUP_UNDEAD_CN)); - display("Undead group", ldapEntryUndead); + displayValue("Undead group", ldapEntryUndead); assertLdapGroupMember(entry, GROUP_EVIL_CN); assertLdapNoGroupMember(accountBarbossaDn, GROUP_EVIL_CN); @@ -1284,15 +1284,15 @@ public void test320AddEvilUserLargo() throws Exception { display("Shadow (model)", shadow); Entry entry = assertLdapAccount(USER_LARGO_NAME, userAfter.asObjectable().getFullName().getOrig()); - display("account after", entry); + displayValue("account after", entry); assertLdapGroupMember(entry, GROUP_EVIL_CN); assertLdapNoGroupMember(entry, GROUP_UNDEAD_CN); Entry ldapEntryEvil = getLdapEntry(toGroupDn(GROUP_EVIL_CN)); - display("Evil group", ldapEntryEvil); + displayValue("Evil group", ldapEntryEvil); Entry ldapEntryUndead = getLdapEntry(toGroupDn(GROUP_UNDEAD_CN)); - display("Undead group", ldapEntryUndead); + displayValue("Undead group", ldapEntryUndead); assertAssociation(shadow, ASSOCIATION_GROUP_NAME, groupEvilShadowOid); diff --git a/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/TestOpenLdap.java b/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/TestOpenLdap.java index 98bd09fae8e..0f5b7f7240a 100644 --- a/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/TestOpenLdap.java +++ b/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/TestOpenLdap.java @@ -130,7 +130,7 @@ protected void assertActivationCapability(ActivationCapabilityType activationCap ActivationLockoutStatusCapabilityType lockoutCapability = CapabilityUtil.getEffectiveActivationLockoutStatus(activationCapabilityType); assertNotNull("No lockout capability", lockoutCapability); - display("Lockout capability", lockoutCapability); + displayValue("Lockout capability", lockoutCapability); } @Override @@ -145,7 +145,7 @@ protected void assertStepSyncToken(String syncTaskOid, int step, long tsStart, l assertNotNull("No sync token in " + task, syncTokenProperty); String syncToken = syncTokenProperty.getRealValue(); assertNotNull("No sync token in " + task, syncToken); - display("Sync token", syncToken); + displayValue("Sync token", syncToken); GeneralizedTime syncTokenGt; try { @@ -180,7 +180,7 @@ public void test700CheckBarbossaLockoutStatus() throws Exception { @Test public void test702LockOutBarbossa() throws Exception { Entry entry = getLdapAccountByUid(USER_BARBOSSA_USERNAME); - display("LDAP Entry before", entry); + displayValue("LDAP Entry before", entry); // WHEN when(); @@ -198,7 +198,7 @@ public void test702LockOutBarbossa() throws Exception { then(); entry = assertLdapAccount(USER_BARBOSSA_USERNAME, USER_BARBOSSA_FULL_NAME); - display("LDAP Entry after", entry); + displayValue("LDAP Entry after", entry); PrismObject shadow = getShadowModel(accountBarbossaOid); display("Shadow (model)", shadow); @@ -238,7 +238,7 @@ public void test705UnlockBarbossaAccount() throws Exception { } Entry entry = assertLdapAccount(USER_BARBOSSA_USERNAME, USER_BARBOSSA_FULL_NAME); - display("LDAP Entry", entry); + displayValue("LDAP Entry", entry); assertNoAttribute(entry, "pwdAccountLockedTime"); assertLdapPassword(USER_BARBOSSA_USERNAME, USER_BARBOSSA_PASSWORD_2); diff --git a/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/ad/AbstractAdLdapMultidomainTest.java b/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/ad/AbstractAdLdapMultidomainTest.java index f90504dfa25..50157dfda60 100644 --- a/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/ad/AbstractAdLdapMultidomainTest.java +++ b/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/ad/AbstractAdLdapMultidomainTest.java @@ -1262,7 +1262,7 @@ private void assertBarbossaDisabled(String password) throws Exception { assertAdministrativeStatus(user, ActivationStatusType.DISABLED); Entry entry = assertLdapAccount(USER_BARBOSSA_USERNAME, USER_BARBOSSA_FULL_NAME); - display("disabled Barbossa entry", entry); + displayValue("disabled Barbossa entry", entry); assertAttribute(entry, ATTRIBUTE_USER_ACCOUNT_CONTROL_NAME, "514"); assertAttribute(entry, ATTRIBUTE_MS_EXCH_HIDE_FROM_ADDRESS_LISTS_NAME, "TRUE"); @@ -1306,7 +1306,7 @@ public void test250AssignGuybrushPirates() throws Exception { assertSuccess(result); Entry entry = assertLdapAccount(USER_GUYBRUSH_USERNAME, USER_GUYBRUSH_FULL_NAME); - display("Entry", entry); + displayValue("Entry", entry); assertAttribute(entry, ATTRIBUTE_USER_ACCOUNT_CONTROL_NAME, "514"); assertLdapGroupMember(entry, GROUP_PIRATES_NAME); @@ -1347,7 +1347,7 @@ public void test255ModifyUserGuybrushPassword() throws Exception { assertSuccess(result); Entry entry = assertLdapAccount(USER_GUYBRUSH_USERNAME, USER_GUYBRUSH_FULL_NAME); - display("Guybrush entry after", entry); + displayValue("Guybrush entry after", entry); assertAttribute(entry, ATTRIBUTE_USER_ACCOUNT_CONTROL_NAME, "514"); try { @@ -1459,7 +1459,7 @@ public void test300AssignBarbossaPirates() throws Exception { TestUtil.assertSuccess(result); Entry entry = assertLdapAccount(USER_BARBOSSA_USERNAME, USER_BARBOSSA_FULL_NAME); - display("Entry", entry); + displayValue("Entry", entry); assertAttribute(entry, "title", "Captain"); assertLdapGroupMember(entry, GROUP_PIRATES_NAME); @@ -1532,7 +1532,7 @@ public void test395UnAssignBarbossaPirates() throws Exception { TestUtil.assertSuccess(result); Entry entry = assertLdapAccount(USER_CPTBARBOSSA_USERNAME, USER_CPTBARBOSSA_FULL_NAME); - display("Entry", entry); + displayValue("Entry", entry); assertAttribute(entry, "title", "Captain"); assertLdapNoGroupMember(entry, GROUP_PIRATES_NAME); @@ -1799,7 +1799,7 @@ public void test524GetMeleeIslandPirates() throws Exception { assertLdapOrg(GROUP_MELEE_ISLAND_ALT_NAME); assertNoLdapOrg(GROUP_MELEE_ISLAND_NAME); Entry entryOrgGroup = assertLdapOrgGroup(GROUP_MELEE_ISLAND_PIRATES_NAME, GROUP_MELEE_ISLAND_ALT_NAME); - display("Melee org", entryOrgGroup); + displayValue("Melee org", entryOrgGroup); assertNoLdapOrgGroup(GROUP_MELEE_ISLAND_PIRATES_NAME, GROUP_MELEE_ISLAND_NAME); } @@ -1864,7 +1864,7 @@ protected void createUnderMeleeEntry() throws LdapException, IOException { Entry entry = new DefaultEntry("ou=underMelee," + toOrgDn(GROUP_MELEE_ISLAND_ALT_NAME), "objectclass", "organizationalUnit", "ou", "underMelee"); - display("underMelee org", entry); + displayValue("underMelee org", entry); addLdapEntry(entry); } @@ -1888,7 +1888,7 @@ public void test600AssignAccountSubman() throws Exception { long tsEnd = System.currentTimeMillis(); Entry entry = assertLdapSubAccount(USER_SUBMAN_USERNAME, USER_SUBMAN_FULL_NAME); - display("Sub entry", entry); + displayValue("Sub entry", entry); assertAttribute(entry, "title", null); PrismObject userAfter = getUser(USER_SUBMAN_OID); @@ -1935,7 +1935,7 @@ public void test610ModifyUserSubmanTitle() throws Exception { assertSuccess(result); Entry entry = assertLdapSubAccount(USER_SUBMAN_USERNAME, USER_SUBMAN_FULL_NAME); - display("Sub entry", entry); + displayValue("Sub entry", entry); assertAttribute(entry, "title", "Underdog"); assertAttribute(entry, ATTRIBUTE_USER_ACCOUNT_CONTROL_NAME, "512"); @@ -2125,7 +2125,7 @@ public void test700AssignAccountSubmarineAndModify() throws Exception { assertSuccess(result); Entry entry = assertLdapSubAccount(USER_SUBMARINE_USERNAME, USER_SUBMARINE_FULL_NAME); - display("Sub entry", entry); + displayValue("Sub entry", entry); assertAttribute(entry, "title", "Underseadog"); PrismObject userAfter = getUser(USER_SUBMARINE_OID); diff --git a/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/ad/AbstractAdLdapTest.java b/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/ad/AbstractAdLdapTest.java index bffdea986aa..f713404bf63 100644 --- a/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/ad/AbstractAdLdapTest.java +++ b/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/ad/AbstractAdLdapTest.java @@ -857,7 +857,7 @@ public void test250AssignGuybrushPirates() throws Exception { assertSuccess(result); Entry entry = assertLdapAccount(USER_GUYBRUSH_USERNAME, USER_GUYBRUSH_FULL_NAME); - display("Entry", entry); + displayValue("Entry", entry); assertAttribute(entry, ATTRIBUTE_USER_ACCOUNT_CONTROL_NAME, "514"); assertLdapGroupMember(entry, GROUP_PIRATES_NAME); @@ -950,7 +950,7 @@ public void test300AssignBarbossaPirates() throws Exception { TestUtil.assertSuccess(result); Entry entry = assertLdapAccount(USER_BARBOSSA_USERNAME, USER_BARBOSSA_FULL_NAME); - display("Entry", entry); + displayValue("Entry", entry); assertAttribute(entry, "title", "Captain"); assertLdapGroupMember(entry, GROUP_PIRATES_NAME); @@ -1023,7 +1023,7 @@ public void test395UnAssignBarbossaPirates() throws Exception { TestUtil.assertSuccess(result); Entry entry = assertLdapAccount(USER_CPTBARBOSSA_USERNAME, USER_CPTBARBOSSA_FULL_NAME); - display("Entry", entry); + displayValue("Entry", entry); assertAttribute(entry, "title", "Captain"); assertLdapNoGroupMember(entry, GROUP_PIRATES_NAME); diff --git a/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/ad/AdTestMixin.java b/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/ad/AdTestMixin.java index e787b5dd63c..fcf48f4e6ce 100644 --- a/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/ad/AdTestMixin.java +++ b/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/ad/AdTestMixin.java @@ -247,7 +247,7 @@ default void display(String title, DebugDumpable value) { PrismTestUtil.display(title, value); } - default void display(String title, Object value) { + default void displayValue(String title, Object value) { PrismTestUtil.display(title, value); } } diff --git a/testing/longtest/src/test/java/com/evolveum/midpoint/testing/longtest/TestGenericSynchronization.java b/testing/longtest/src/test/java/com/evolveum/midpoint/testing/longtest/TestGenericSynchronization.java index e0f6e3ae8bf..308b5dc9d0e 100644 --- a/testing/longtest/src/test/java/com/evolveum/midpoint/testing/longtest/TestGenericSynchronization.java +++ b/testing/longtest/src/test/java/com/evolveum/midpoint/testing/longtest/TestGenericSynchronization.java @@ -218,7 +218,7 @@ public void test100TreeImport() throws Exception { then(); int userCount = modelService.countObjects(UserType.class, null, null, task, result); - display("Users", userCount); + displayValue("Users", userCount); AssertJUnit.assertEquals("Unexpected number of users", ldapdUserCount, userCount); } diff --git a/testing/longtest/src/test/java/com/evolveum/midpoint/testing/longtest/TestLdap.java b/testing/longtest/src/test/java/com/evolveum/midpoint/testing/longtest/TestLdap.java index 10d7400057f..3f07caa1177 100644 --- a/testing/longtest/src/test/java/com/evolveum/midpoint/testing/longtest/TestLdap.java +++ b/testing/longtest/src/test/java/com/evolveum/midpoint/testing/longtest/TestLdap.java @@ -144,7 +144,7 @@ public void initSystem(Task initTask, OperationResult initResult) throws Excepti profilingManager.appendProfilingToTest(); //initProfiling - end - display("initial LDAP content", openDJController.dumpEntries()); + displayValue("initial LDAP content", openDJController.dumpEntries()); } @Test @@ -188,7 +188,7 @@ public void test202AssignLdapAccountToGuybrush() throws Exception { OperationResult result = task.getResult(); byte[] photoIn = Files.readAllBytes(Paths.get(DOT_JPG_FILENAME)); - display("Photo in", MiscUtil.binaryToHex(photoIn)); + displayValue("Photo in", MiscUtil.binaryToHex(photoIn)); modifyUserReplace(USER_GUYBRUSH_OID, UserType.F_JPEG_PHOTO, task, result, photoIn); Collection> options = getOperationOptionsBuilder() @@ -224,7 +224,7 @@ public void test202AssignLdapAccountToGuybrush() throws Exception { PrismProperty jpegPhotoAttr = attributesContainer.findProperty(jpegPhotoQName); byte[] photoBytesOut = jpegPhotoAttr.getValues().get(0).getValue(); - display("Photo bytes out", MiscUtil.binaryToHex(photoBytesOut)); + displayValue("Photo bytes out", MiscUtil.binaryToHex(photoBytesOut)); assertEquals("Photo byte length changed (shadow)", photoIn.length, photoBytesOut.length); assertTrue("Photo bytes do not match (shadow)", Arrays.equals(photoIn, photoBytesOut)); @@ -367,7 +367,7 @@ public void test810BigImport() throws Exception { then(); int userCount = modelService.countObjects(UserType.class, null, null, task, result); - display("Users", userCount); + displayValue("Users", userCount); assertEquals("Unexpected number of users", 2*NUM_LDAP_ENTRIES + 8, userCount); } @@ -402,7 +402,7 @@ public void test820BigReconciliation() throws Exception { then(); int userCount = modelService.countObjects(UserType.class, null, null, task, result); - display("Users", userCount); + displayValue("Users", userCount); assertEquals("Unexpected number of users", 2*NUM_LDAP_ENTRIES + 8, userCount); } diff --git a/testing/longtest/src/test/java/com/evolveum/midpoint/testing/longtest/TestLdapComplex.java b/testing/longtest/src/test/java/com/evolveum/midpoint/testing/longtest/TestLdapComplex.java index 33cfb69591d..f777df15976 100644 --- a/testing/longtest/src/test/java/com/evolveum/midpoint/testing/longtest/TestLdapComplex.java +++ b/testing/longtest/src/test/java/com/evolveum/midpoint/testing/longtest/TestLdapComplex.java @@ -121,7 +121,7 @@ public void initSystem(Task initTask, OperationResult initResult) throws Excepti openDJController.addEntriesFromLdifFile(ROLES_LDIF_FILE.getPath()); - display("initial LDAP content", openDJController.dumpEntries()); + displayValue("initial LDAP content", openDJController.dumpEntries()); } @Test @@ -149,7 +149,7 @@ public void test100BigImport() throws Exception { then(); int userCount = modelService.countObjects(UserType.class, null, null, task, result); - display("Users", userCount); + displayValue("Users", userCount); assertEquals("Unexpected number of users", NUM_LDAP_ENTRIES + 4, userCount); assertUser("u1", task, result); @@ -187,7 +187,7 @@ public void test120BigReconciliation() throws Exception { then(); int userCount = modelService.countObjects(UserType.class, null, null, task, result); - display("Users", userCount); + displayValue("Users", userCount); assertEquals("Unexpected number of users", NUM_LDAP_ENTRIES + 4, userCount); assertUser("u1", task, result); diff --git a/testing/longtest/src/test/java/com/evolveum/midpoint/testing/longtest/TestLdapUniversity.java b/testing/longtest/src/test/java/com/evolveum/midpoint/testing/longtest/TestLdapUniversity.java index fc70ebf65f6..567ccd49fe5 100644 --- a/testing/longtest/src/test/java/com/evolveum/midpoint/testing/longtest/TestLdapUniversity.java +++ b/testing/longtest/src/test/java/com/evolveum/midpoint/testing/longtest/TestLdapUniversity.java @@ -111,7 +111,7 @@ public void initSystem(Task initTask, OperationResult initResult) throws Excepti assumeAssignmentPolicy(AssignmentPolicyEnforcementType.RELATIVE); - display("initial LDAP content", openDJController.dumpEntries()); + displayValue("initial LDAP content", openDJController.dumpEntries()); } @Test @@ -141,7 +141,7 @@ public void test100BigImportWithLinking() throws Exception { then(); int userCount = modelService.countObjects(UserType.class, null, null, task, result); - display("Users", userCount); + displayValue("Users", userCount); assertEquals("Unexpected number of users", NUM_LDAP_ENTRIES + 1, userCount); display("e0(u0)", findUserByUsername("e0(u0)")); @@ -192,7 +192,7 @@ public void test120BigReconciliation() throws Exception { then(); waitForTaskFinish(task, true, 20000 + NUM_LDAP_ENTRIES * 2000, 10000L); int userCount = modelService.countObjects(UserType.class, null, null, task, result); - display("Users", userCount); + displayValue("Users", userCount); assertEquals("Unexpected number of users", NUM_LDAP_ENTRIES + 1, userCount); display("e0(u0)", findUserByUsername("e0(u0)")); diff --git a/testing/longtest/src/test/java/com/evolveum/midpoint/testing/longtest/TestRunAs.java b/testing/longtest/src/test/java/com/evolveum/midpoint/testing/longtest/TestRunAs.java index 64cee8228d2..f696fb2ef3d 100644 --- a/testing/longtest/src/test/java/com/evolveum/midpoint/testing/longtest/TestRunAs.java +++ b/testing/longtest/src/test/java/com/evolveum/midpoint/testing/longtest/TestRunAs.java @@ -276,7 +276,7 @@ public void test310BarbossaSetOrganizationRunAs() throws Exception { display("Run time " + runTimeMillis + "ms, repo read count increment " + readCountIncrement); long percentRuntimeIncrease = (runTimeMillis - baselineRunTime) * 100 / baselineRunTime; long readCountIncrease = readCountIncrement - baselineRepoReadCountIncrement; - display("Increase over baseline", + displayValue("Increase over baseline", " run time: " + (runTimeMillis - baselineRunTime) + " (" + percentRuntimeIncrease + "%) \n" + " repo read: " + readCountIncrease); diff --git a/testing/rest/src/test/java/com/evolveum/midpoint/testing/rest/TestAbstractRestService.java b/testing/rest/src/test/java/com/evolveum/midpoint/testing/rest/TestAbstractRestService.java index 176a02ba03b..fca7d5fc625 100644 --- a/testing/rest/src/test/java/com/evolveum/midpoint/testing/rest/TestAbstractRestService.java +++ b/testing/rest/src/test/java/com/evolveum/midpoint/testing/rest/TestAbstractRestService.java @@ -768,7 +768,7 @@ public void test412GetFunctionLibraryHello() { List> expressionEvaluators = libType.getFunction().get(0).getExpressionEvaluator(); ScriptExpressionEvaluatorType scriptExpressionEvaluator = (ScriptExpressionEvaluatorType) expressionEvaluators.get(0).getValue(); String code = scriptExpressionEvaluator.getCode(); - display("Code", code); + displayValue("Code", code); assertEquals("Wrong hello code", HELLO_CODE, code); display("Audit", getDummyAuditService()); @@ -1168,7 +1168,7 @@ public void test520GeneratePasswordsUsingScripting() throws Exception { assertEquals("Expected 200 but got " + response.getStatus(), 200, response.getStatus()); ExecuteScriptResponseType responseData = response.readEntity(ExecuteScriptResponseType.class); - display("Response", getPrismContext().xmlSerializer().serializeRealValue(responseData)); + displayValue("Response", getPrismContext().xmlSerializer().serializeRealValue(responseData)); logger.info("Response: {}", getPrismContext().xmlSerializer().serializeRealValue(responseData)); List items = responseData.getOutput().getDataOutput().getItem(); @@ -1224,7 +1224,7 @@ public void test530ModifyValidToUsingScripting() throws Exception { getDummyAuditService().assertLoginLogout(SchemaConstants.CHANNEL_REST_URI); ExecuteScriptResponseType responseData = response.readEntity(ExecuteScriptResponseType.class); - display("Response", getPrismContext().xmlSerializer().serializeRealValue(responseData)); + displayValue("Response", getPrismContext().xmlSerializer().serializeRealValue(responseData)); List items = responseData.getOutput().getDataOutput().getItem(); assertEquals("Wrong # of processed items", 2, items.size()); diff --git a/testing/sanity/src/test/java/com/evolveum/midpoint/testing/sanity/TestSanity.java b/testing/sanity/src/test/java/com/evolveum/midpoint/testing/sanity/TestSanity.java index ebbbc76f8a4..ec994cb9666 100644 --- a/testing/sanity/src/test/java/com/evolveum/midpoint/testing/sanity/TestSanity.java +++ b/testing/sanity/src/test/java/com/evolveum/midpoint/testing/sanity/TestSanity.java @@ -442,7 +442,7 @@ public void test001TestConnectionOpenDJ() throws Exception { checkOpenDjResource(resourceTypeOpenDjrepo, "repository"); System.out.println("------------------------------------------------------------------"); - display("OpenDJ resource schema (repo XML)", DOMUtil.serializeDOMToString(ResourceTypeUtil.getResourceXsdSchema(resourceOpenDjRepo))); + displayValue("OpenDJ resource schema (repo XML)", DOMUtil.serializeDOMToString(ResourceTypeUtil.getResourceXsdSchema(resourceOpenDjRepo))); System.out.println("------------------------------------------------------------------"); checkOpenDjResource(openDjResourceProvisioninig.asObjectable(), "provisioning"); @@ -539,7 +539,7 @@ private void checkOpenResourceConfiguration(PrismObject resource, PrismProperty credentialsProp = configPropsContainer.findProperty(new ItemName(connectorNamespace, credentialsPropertyName)); if (credentialsProp == null) { // The is the heisenbug we are looking for. Just dump the entire damn thing. - display("Configuration with the heisenbug", configurationContainer.debugDump()); + displayValue("Configuration with the heisenbug", configurationContainer.debugDump()); } assertNotNull("No " + credentialsPropertyName + " property in " + resource + " from " + source, credentialsProp); assertEquals("Wrong number of " + credentialsPropertyName + " property value in " + resource + " from " + source, 1, credentialsProp.getValues().size()); @@ -1221,7 +1221,7 @@ public boolean handle(PrismObject prismObject, OperationResult paren // THEN - display("Count", objects.size()); + displayValue("Count", objects.size()); } /** @@ -1415,7 +1415,7 @@ private void assertUserPasswordChange(String expectedUserPassword, OperationResu String ldapPasswordAfter = OpenDJController.getAttributeValue(entry, "userPassword"); assertNotNull(ldapPasswordAfter); - display("LDAP password after change", ldapPasswordAfter); + displayValue("LDAP password after change", ldapPasswordAfter); assertFalse("No change in password (original)", ldapPasswordAfter.equals(originalJacksLdapPassword)); if (lastJacksLdapPassword != null) { @@ -1524,7 +1524,7 @@ public void test030DisableUser() throws Exception { assertOpenDJAccountJack(entry, "jack"); String pwpAccountDisabled = OpenDJController.getAttributeValue(entry, "ds-pwp-account-disabled"); - display("ds-pwp-account-disabled before change", pwpAccountDisabled); + displayValue("ds-pwp-account-disabled before change", pwpAccountDisabled); assertTrue("LDAP account is not enabled (precondition)", openDJController.isAccountEnabled(entry)); assertNoRepoCache(); @@ -1580,7 +1580,7 @@ public void test030DisableUser() throws Exception { assertOpenDJAccountJack(entry, "jack"); pwpAccountDisabled = OpenDJController.getAttributeValue(entry, "ds-pwp-account-disabled"); - display("ds-pwp-account-disabled after change", pwpAccountDisabled); + displayValue("ds-pwp-account-disabled after change", pwpAccountDisabled); assertFalse("LDAP account was not disabled", openDJController.isAccountEnabled(entry)); // Use getObject to test fetch of complete shadow @@ -2669,7 +2669,7 @@ public void timeout() { assertTrue("Task result is not a success, it is " + taskResult, taskResult.isSuccess()); final Object tokenAfter = findSyncToken(task); - display("Sync token after", tokenAfter.toString()); + displayValue("Sync token after", tokenAfter.toString()); lastSyncToken = (Integer) tokenAfter; checkAllShadows(); @@ -2696,7 +2696,7 @@ public void test301LiveSyncCreate() throws Exception { AssertJUnit.assertNotNull(syncCycle); final Object tokenBefore = findSyncToken(syncCycle); - display("Sync token before", tokenBefore.toString()); + displayValue("Sync token before", tokenBefore.toString()); // WHEN when(); @@ -2730,14 +2730,14 @@ public void test302LiveSyncModify() throws Exception { AssertJUnit.assertNotNull(syncCycle); int tokenBefore = findSyncToken(syncCycle); - display("Sync token before", tokenBefore); + displayValue("Sync token before", tokenBefore); // WHEN display("Modifying LDAP entry"); ChangeRecordEntry entry = openDJController.executeLdifChange(LDIF_WILL_MODIFY_FILE); // THEN - display("Entry from LDIF", entry); + displayValue("Entry from LDIF", entry); // Wait a bit to give the sync cycle time to detect the change basicWaitForSyncChangeDetection(syncCycle, tokenBefore, 1, result); @@ -2782,7 +2782,7 @@ public void test303LiveSyncLink() throws Exception { AssertJUnit.assertNotNull(syncCycle); int tokenBefore = findSyncToken(syncCycle); - display("Sync token before", tokenBefore); + displayValue("Sync token before", tokenBefore); Entry entry = openDJController.addEntryFromLdifFile(LDIF_E_FILENAME_LINK); display("Entry from LDIF", entry); @@ -2824,7 +2824,7 @@ public void test304LiveSyncCreateNoLocation() throws Exception { AssertJUnit.assertNotNull(syncCycle); int tokenBefore = findSyncToken(syncCycle); - display("Sync token before", tokenBefore); + displayValue("Sync token before", tokenBefore); // WHEN Entry entry = openDJController.addEntryFromLdifFile(LDIF_WILL_WITHOUT_LOCATION_FILENAME); @@ -2857,7 +2857,7 @@ public void test304LiveSyncCreateNoLocation() throws Exception { private void assertAndStoreSyncTokenIncrement(Task syncCycle, int increment) { final Object tokenAfter = findSyncToken(syncCycle); - display("Sync token after", tokenAfter.toString()); + displayValue("Sync token after", tokenAfter.toString()); int tokenAfterInt = (Integer) tokenAfter; int expectedToken = lastSyncToken + increment; lastSyncToken = tokenAfterInt; @@ -2904,7 +2904,7 @@ public void test400ImportFromResource() throws Exception { // Make sure Mr. Gibbs has "l" attribute set to the same value as an outbound expression is setting ChangeRecordEntry entry = openDJController.executeLdifChange(LDIF_GIBBS_MODIFY_FILE); - display("Entry from LDIF", entry); + displayValue("Entry from LDIF", entry); // Let's add an entry with multiple uids. Entry addEntry = openDJController.addEntryFromLdifFile(LDIF_HERMAN_FILENAME); @@ -3475,7 +3475,7 @@ public void test480ListResources() throws Exception { // THEN - display("Resources", objectListHolder.value); + displayValue("Resources", objectListHolder.value); assertEquals("Unexpected number of resources", 4, objectListHolder.value.getObject().size()); // TODO @@ -3545,7 +3545,7 @@ public void test500NotifyChangeCreateAccount() throws Exception { prop.setRealValue(entryUuid); anglicaAccount.setResourceRef(ObjectTypeUtil.createObjectRef(RESOURCE_OPENDJ_OID, ObjectTypes.RESOURCE)); - display("Angelica shadow: ", anglicaAccount.asPrismObject().debugDump()); + displayValue("Angelica shadow: ", anglicaAccount.asPrismObject().debugDump()); ResourceObjectShadowChangeDescriptionType changeDescription = new ResourceObjectShadowChangeDescriptionType(); ObjectDeltaType delta = new ObjectDeltaType(); diff --git a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/AbstractStoryTest.java b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/AbstractStoryTest.java index 7fdfcd23ba6..02b1a0db24b 100644 --- a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/AbstractStoryTest.java +++ b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/AbstractStoryTest.java @@ -223,10 +223,10 @@ protected PerformanceInformation dumpThreadLocalPerformanceData(String testName) } protected void dumpRepoPerformanceData(String label, PerformanceInformation performanceInformation) { - display(label, RepositoryPerformanceInformationUtil.format(performanceInformation.toRepositoryPerformanceInformationType())); + displayValue(label, RepositoryPerformanceInformationUtil.format(performanceInformation.toRepositoryPerformanceInformationType())); } protected void dumpCachePerformanceData(String label, Map performanceMap) { - display(label, CachePerformanceInformationUtil.format(performanceMap)); + displayValue(label, CachePerformanceInformationUtil.format(performanceMap)); } } diff --git a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestConsistencyMechanism.java b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestConsistencyMechanism.java index 4db1b1c81b0..4360780566c 100644 --- a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestConsistencyMechanism.java +++ b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestConsistencyMechanism.java @@ -367,7 +367,7 @@ public void test001TestConnectionOpenDJ() throws Exception { checkOpenDjResource(resourceTypeOpenDjrepo, "repository"); System.out.println("------------------------------------------------------------------"); - display("OpenDJ resource schema (repo XML)", + displayValue("OpenDJ resource schema (repo XML)", DOMUtil.serializeDOMToString(ResourceTypeUtil.getResourceXsdSchema(resourceOpenDjRepo))); System.out.println("------------------------------------------------------------------"); @@ -2758,7 +2758,7 @@ private void checkOpenResourceConfiguration(PrismObject resource, if (credentialsProp == null) { // The is the heisenbug we are looking for. Just dump the entire // damn thing. - display("Configuration with the heisenbug", configurationContainer.debugDump()); + displayValue("Configuration with the heisenbug", configurationContainer.debugDump()); } assertNotNull("No credentials property in " + resource + " from " + source, credentialsProp); assertEquals("Wrong number of credentials property value in " + resource + " from " + source, 1, diff --git a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestOperationPerf.java b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestOperationPerf.java index d9787cf755d..0ad3b3af926 100644 --- a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestOperationPerf.java +++ b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestOperationPerf.java @@ -90,8 +90,8 @@ public void initSystem(Task initTask, OperationResult initResult) throws Excepti public void test000Sanity() throws Exception { assertObjects(RoleType.class, NUMBER_OF_GENERATED_EMPTY_ROLES + NUMBER_OF_ORDINARY_ROLES); - display("Repo reads", InternalMonitor.getCount(InternalCounters.REPOSITORY_READ_COUNT)); - display("Object compares", InternalMonitor.getCount(InternalCounters.PRISM_OBJECT_COMPARE_COUNT)); + displayValue("Repo reads", InternalMonitor.getCount(InternalCounters.REPOSITORY_READ_COUNT)); + displayValue("Object compares", InternalMonitor.getCount(InternalCounters.PRISM_OBJECT_COMPARE_COUNT)); } @Test @@ -136,14 +136,14 @@ public void testAddUser(File userFile, String userOid, int roles) throws Excepti display("Model diagnostics", profilingModelInspectorManager); display("Internal inspector", internalInspector); - display("Internal counters", InternalMonitor.debugDumpStatic(1)); + displayValue("Internal counters", InternalMonitor.debugDumpStatic(1)); PrismObject userAfter = getUser(userOid); display("User after", userAfter); assertAssignments(userAfter, 1); - display("Repo reads", InternalMonitor.getCount(InternalCounters.REPOSITORY_READ_COUNT)); - display("Object compares", InternalMonitor.getCount(InternalCounters.PRISM_OBJECT_COMPARE_COUNT)); + displayValue("Repo reads", InternalMonitor.getCount(InternalCounters.REPOSITORY_READ_COUNT)); + displayValue("Object compares", InternalMonitor.getCount(InternalCounters.PRISM_OBJECT_COMPARE_COUNT)); assertCounterIncrement(InternalCounters.PRISM_OBJECT_COMPARE_COUNT, 0); } diff --git a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestPlentyOfAssignments.java b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestPlentyOfAssignments.java index 6f7a0b3574e..d561e70891a 100644 --- a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestPlentyOfAssignments.java +++ b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestPlentyOfAssignments.java @@ -148,8 +148,8 @@ private String formatGroupName(int num) { public void test000Sanity() throws Exception { assertObjects(RoleType.class, NUMBER_OF_GENERATED_EMPTY_ROLES + NUMBER_OF_GENERATED_DUMMY_ROLES + NUMBER_OF_ORDINARY_ROLES); - display("Repo reads", InternalMonitor.getCount(InternalCounters.REPOSITORY_READ_COUNT)); - display("Object compares", InternalMonitor.getCount(InternalCounters.PRISM_OBJECT_COMPARE_COUNT)); + displayValue("Repo reads", InternalMonitor.getCount(InternalCounters.REPOSITORY_READ_COUNT)); + displayValue("Object compares", InternalMonitor.getCount(InternalCounters.PRISM_OBJECT_COMPARE_COUNT)); } @Test @@ -158,7 +158,7 @@ public void test100AddCheese() throws Exception { OperationResult result = task.getResult(); PrismObject cheeseBefore = prepareCheese(); - display("Cheese before", assignmentSummary(cheeseBefore)); + displayValue("Cheese before", assignmentSummary(cheeseBefore)); inspector.reset(); rememberCounter(InternalCounters.PRISM_OBJECT_COMPARE_COUNT); @@ -178,11 +178,11 @@ public void test100AddCheese() throws Exception { display("Added cheese in " + (endMillis - startMillis) + "ms (" + ((endMillis - startMillis) / NUMBER_OF_CHEESE_ASSIGNMENTS) + "ms per assignment)"); PrismObject cheeseAfter = getUser(USER_CHEESE_OID); - display("Cheese after", assignmentSummary(cheeseAfter)); + displayValue("Cheese after", assignmentSummary(cheeseAfter)); assertCheeseRoleMembershipRef(cheeseAfter); - display("Repo reads", InternalMonitor.getCount(InternalCounters.REPOSITORY_READ_COUNT)); - display("Object compares", InternalMonitor.getCount(InternalCounters.PRISM_OBJECT_COMPARE_COUNT)); + displayValue("Repo reads", InternalMonitor.getCount(InternalCounters.REPOSITORY_READ_COUNT)); + displayValue("Object compares", InternalMonitor.getCount(InternalCounters.PRISM_OBJECT_COMPARE_COUNT)); display("Inspector", inspector); @@ -198,7 +198,7 @@ public void test110RecomputeCheese() throws Exception { OperationResult result = task.getResult(); PrismObject cheeseBefore = prepareCheese(); - display("Cheese before", assignmentSummary(cheeseBefore)); + displayValue("Cheese before", assignmentSummary(cheeseBefore)); inspector.reset(); rememberCounter(InternalCounters.PRISM_OBJECT_COMPARE_COUNT); @@ -218,11 +218,11 @@ public void test110RecomputeCheese() throws Exception { display("Recomputed cheese in " + (endMillis - startMillis) + "ms (" + ((endMillis - startMillis) / NUMBER_OF_CHEESE_ASSIGNMENTS) + "ms per assignment)"); PrismObject cheeseAfter = getUser(USER_CHEESE_OID); - display("Cheese after", assignmentSummary(cheeseAfter)); + displayValue("Cheese after", assignmentSummary(cheeseAfter)); assertCheeseRoleMembershipRef(cheeseAfter); - display("Repo reads", InternalMonitor.getCount(InternalCounters.REPOSITORY_READ_COUNT)); - display("Object compares", InternalMonitor.getCount(InternalCounters.PRISM_OBJECT_COMPARE_COUNT)); + displayValue("Repo reads", InternalMonitor.getCount(InternalCounters.REPOSITORY_READ_COUNT)); + displayValue("Object compares", InternalMonitor.getCount(InternalCounters.PRISM_OBJECT_COMPARE_COUNT)); display("Inspector", inspector); @@ -237,7 +237,7 @@ public void test120CheesePreviewChanges() throws Exception { OperationResult result = task.getResult(); PrismObject cheeseBefore = prepareCheese(); - display("Cheese before", assignmentSummary(cheeseBefore)); + displayValue("Cheese before", assignmentSummary(cheeseBefore)); ObjectDelta delta = cheeseBefore.createModifyDelta(); delta.addModificationReplaceProperty(UserType.F_EMPLOYEE_NUMBER, "123"); @@ -260,11 +260,11 @@ public void test120CheesePreviewChanges() throws Exception { display("Preview cheese in " + (endMillis - startMillis) + "ms (" + ((endMillis - startMillis) / NUMBER_OF_CHEESE_ASSIGNMENTS) + "ms per assignment)"); PrismObject cheeseAfter = getUser(USER_CHEESE_OID); - display("Cheese after", assignmentSummary(cheeseAfter)); + displayValue("Cheese after", assignmentSummary(cheeseAfter)); assertCheeseRoleMembershipRef(cheeseAfter); - display("Repo reads", InternalMonitor.getCount(InternalCounters.REPOSITORY_READ_COUNT)); - display("Object compares", InternalMonitor.getCount(InternalCounters.PRISM_OBJECT_COMPARE_COUNT)); + displayValue("Repo reads", InternalMonitor.getCount(InternalCounters.REPOSITORY_READ_COUNT)); + displayValue("Object compares", InternalMonitor.getCount(InternalCounters.PRISM_OBJECT_COMPARE_COUNT)); display("Inspector", inspector); @@ -375,7 +375,7 @@ public void test210AddBob() throws Exception { PrismObject userBefore = PrismTestUtil.parseObject(USER_BOB_FILE); addAssignments(userBefore, GENERATED_DUMMY_ROLE_OID_FORMAT, null, 0, NUMBER_OF_BOB_DUMMY_ROLE_ASSIGNMENTS); - display("User before", assignmentSummary(userBefore)); + displayValue("User before", assignmentSummary(userBefore)); inspector.reset(); rememberCounter(InternalCounters.PRISM_OBJECT_COMPARE_COUNT); @@ -395,11 +395,11 @@ public void test210AddBob() throws Exception { display("Added bob in " + (endMillis - startMillis) + "ms (" + ((endMillis - startMillis) / NUMBER_OF_BOB_DUMMY_ROLE_ASSIGNMENTS) + "ms per assignment)"); PrismObject userAfter = getUser(USER_BOB_OID); - display("User after", assignmentSummary(userAfter)); + displayValue("User after", assignmentSummary(userAfter)); assertBobRoleMembershipRef(userAfter); - display("Repo reads", InternalMonitor.getCount(InternalCounters.REPOSITORY_READ_COUNT)); - display("Object compares", InternalMonitor.getCount(InternalCounters.PRISM_OBJECT_COMPARE_COUNT)); + displayValue("Repo reads", InternalMonitor.getCount(InternalCounters.REPOSITORY_READ_COUNT)); + displayValue("Object compares", InternalMonitor.getCount(InternalCounters.PRISM_OBJECT_COMPARE_COUNT)); display("Inspector", inspector); @@ -437,11 +437,11 @@ public void test212RecomputeBob() throws Exception { display("Recomputed bob in " + (endMillis - startMillis) + "ms (" + ((endMillis - startMillis) / NUMBER_OF_BOB_DUMMY_ROLE_ASSIGNMENTS) + "ms per assignment)"); PrismObject userAfter = getUser(USER_BOB_OID); - display("User after", assignmentSummary(userAfter)); + displayValue("User after", assignmentSummary(userAfter)); assertBobRoleMembershipRef(userAfter); - display("Repo reads", InternalMonitor.getCount(InternalCounters.REPOSITORY_READ_COUNT)); - display("Object compares", InternalMonitor.getCount(InternalCounters.PRISM_OBJECT_COMPARE_COUNT)); + displayValue("Repo reads", InternalMonitor.getCount(InternalCounters.REPOSITORY_READ_COUNT)); + displayValue("Object compares", InternalMonitor.getCount(InternalCounters.PRISM_OBJECT_COMPARE_COUNT)); display("Inspector", inspector); @@ -479,11 +479,11 @@ public void test2124ReconcileBob() throws Exception { display("Reconciled bob in " + (endMillis - startMillis) + "ms (" + ((endMillis - startMillis) / NUMBER_OF_BOB_DUMMY_ROLE_ASSIGNMENTS) + "ms per assignment)"); PrismObject userAfter = getUser(USER_BOB_OID); - display("User after", assignmentSummary(userAfter)); + displayValue("User after", assignmentSummary(userAfter)); assertBobRoleMembershipRef(userAfter); - display("Repo reads", InternalMonitor.getCount(InternalCounters.REPOSITORY_READ_COUNT)); - display("Object compares", InternalMonitor.getCount(InternalCounters.PRISM_OBJECT_COMPARE_COUNT)); + displayValue("Repo reads", InternalMonitor.getCount(InternalCounters.REPOSITORY_READ_COUNT)); + displayValue("Object compares", InternalMonitor.getCount(InternalCounters.PRISM_OBJECT_COMPARE_COUNT)); display("Inspector", inspector); @@ -523,7 +523,7 @@ public void test220AddAlice() throws Exception { PrismObject userBefore = PrismTestUtil.parseObject(USER_ALICE_FILE); addAssignments(userBefore, GENERATED_DUMMY_GROUP_ROLE_OID_FORMAT, null, 0, NUMBER_OF_GENERATED_DUMMY_GROUPS); - display("User before", assignmentSummary(userBefore)); + displayValue("User before", assignmentSummary(userBefore)); inspector.reset(); rememberCounter(InternalCounters.PRISM_OBJECT_CLONE_COUNT); @@ -544,12 +544,12 @@ public void test220AddAlice() throws Exception { display("Added alice in " + (endMillis - startMillis) + "ms (" + ((endMillis - startMillis) / NUMBER_OF_GENERATED_DUMMY_GROUPS) + "ms per assignment)"); PrismObject userAfter = getUser(USER_ALICE_OID); - display("User after", assignmentSummary(userAfter)); + displayValue("User after", assignmentSummary(userAfter)); assertAliceRoleMembershipRef(userAfter); - display("Repo reads", InternalMonitor.getCount(InternalCounters.REPOSITORY_READ_COUNT)); - display("Object compares", InternalMonitor.getCount(InternalCounters.PRISM_OBJECT_COMPARE_COUNT)); - display("Prism clones", InternalMonitor.getCount(InternalCounters.PRISM_OBJECT_CLONE_COUNT)); + displayValue("Repo reads", InternalMonitor.getCount(InternalCounters.REPOSITORY_READ_COUNT)); + displayValue("Object compares", InternalMonitor.getCount(InternalCounters.PRISM_OBJECT_COMPARE_COUNT)); + displayValue("Prism clones", InternalMonitor.getCount(InternalCounters.PRISM_OBJECT_CLONE_COUNT)); display("Inspector", inspector); @@ -587,11 +587,11 @@ public void test222RecomputeAlice() throws Exception { display("Recomputed alice in " + (endMillis - startMillis) + "ms (" + ((endMillis - startMillis) / NUMBER_OF_GENERATED_DUMMY_GROUPS) + "ms per assignment)"); PrismObject userAfter = getUser(USER_ALICE_OID); - display("User after", assignmentSummary(userAfter)); + displayValue("User after", assignmentSummary(userAfter)); assertAliceRoleMembershipRef(userAfter); - display("Repo reads", InternalMonitor.getCount(InternalCounters.REPOSITORY_READ_COUNT)); - display("Object compares", InternalMonitor.getCount(InternalCounters.PRISM_OBJECT_COMPARE_COUNT)); + displayValue("Repo reads", InternalMonitor.getCount(InternalCounters.REPOSITORY_READ_COUNT)); + displayValue("Object compares", InternalMonitor.getCount(InternalCounters.PRISM_OBJECT_COMPARE_COUNT)); display("Inspector", inspector); @@ -629,11 +629,11 @@ public void test224ReconcileAlice() throws Exception { display("Reconciled alice in " + (endMillis - startMillis) + "ms (" + ((endMillis - startMillis) / NUMBER_OF_GENERATED_DUMMY_GROUPS) + "ms per assignment)"); PrismObject userAfter = getUser(USER_ALICE_OID); - display("User after", assignmentSummary(userAfter)); + displayValue("User after", assignmentSummary(userAfter)); assertAliceRoleMembershipRef(userAfter); - display("Repo reads", InternalMonitor.getCount(InternalCounters.REPOSITORY_READ_COUNT)); - display("Object compares", InternalMonitor.getCount(InternalCounters.PRISM_OBJECT_COMPARE_COUNT)); + displayValue("Repo reads", InternalMonitor.getCount(InternalCounters.REPOSITORY_READ_COUNT)); + displayValue("Object compares", InternalMonitor.getCount(InternalCounters.PRISM_OBJECT_COMPARE_COUNT)); display("Inspector", inspector); diff --git a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestReconNullValue.java b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestReconNullValue.java index acec70abe03..726a019f60f 100644 --- a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestReconNullValue.java +++ b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestReconNullValue.java @@ -399,8 +399,8 @@ public void test170ReplaceGivenNameEmpty() throws Exception { } private void dumpLdap() throws DirectoryException { - display("LDAP server tree", openDJController.dumpTree()); - display("LDAP server content", openDJController.dumpEntries()); + displayValue("LDAP server tree", openDJController.dumpTree()); + displayValue("LDAP server content", openDJController.dumpEntries()); } protected PrismObject getObjectByName(Class clazz, String name) @@ -418,7 +418,7 @@ private void assertShadowAttribute(PrismObject focus, ShadowKindType kind, throws SchemaException, ObjectNotFoundException, SecurityViolationException, CommunicationException, ConfigurationException, ExpressionEvaluationException { String focusName = focus.getName().toString(); - display("assert focus " + focus.getCompileTimeClass(), focusName); + displayValue("assert focus " + focus.getCompileTimeClass(), focusName); String objOid = getLinkRefOid(focus, RESOURCE_OPENDJ_OID, kind, intent); PrismObject objShadow = getShadowModel(objOid); diff --git a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestRetirement.java b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestRetirement.java index 57c8bacaac8..e1e07f11d9f 100644 --- a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestRetirement.java +++ b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestRetirement.java @@ -162,7 +162,7 @@ public void test050AddOrgRetired() throws Exception { Entry ouEntry = openDJController.fetchEntry(ouShadow.getName().getOrig()); assertNotNull("No ou LDAP entry for retirement (" + ouShadow.getName().getOrig() + ")", ouEntry); - display("OU retirement entry", openDJController.toHumanReadableLdifoid(ouEntry)); + displayValue("OU retirement entry", openDJController.toHumanReadableLdifoid(ouEntry)); OpenDJController.assertObjectClass(ouEntry, "organizationalUnit"); assertSubOrgs(org, 0); @@ -452,7 +452,7 @@ private PrismObject getAndAssertUser(String username) Entry accountEntry = openDJController.searchSingle("uid=" + username); assertNotNull("No account LDAP entry for " + username, accountEntry); - display("account entry", openDJController.toHumanReadableLdifoid(accountEntry)); + displayValue("account entry", openDJController.toHumanReadableLdifoid(accountEntry)); OpenDJController.assertObjectClass(accountEntry, "inetOrgPerson"); return user; @@ -470,7 +470,7 @@ private PrismObject getAndAssertRetiredUser(String username) throws Co String dn = "uid=RRR-" + username + ",ou=RETIRED,dc=example,dc=com"; Entry accountEntry = openDJController.fetchEntry(dn); assertNotNull("No account LDAP entry for " + username + " (" + dn + ")", accountEntry); - display("account entry", openDJController.toHumanReadableLdifoid(accountEntry)); + displayValue("account entry", openDJController.toHumanReadableLdifoid(accountEntry)); OpenDJController.assertObjectClass(accountEntry, "inetOrgPerson"); return user; @@ -489,7 +489,7 @@ private PrismObject getAndAssertFunctionalOrg(String orgName, String di Entry groupEntry = openDJController.searchSingle("cn=" + orgName); assertNotNull("No group LDAP entry for " + orgName, groupEntry); - display("OU GROUP entry", openDJController.toHumanReadableLdifoid(groupEntry)); + displayValue("OU GROUP entry", openDJController.toHumanReadableLdifoid(groupEntry)); OpenDJController.assertObjectClass(groupEntry, "groupOfUniqueNames"); assertHasOrg(org, directParentOrgOid); @@ -499,7 +499,7 @@ private PrismObject getAndAssertFunctionalOrg(String orgName, String di } private void dumpLdap() throws DirectoryException { - display("LDAP server tree", openDJController.dumpTree()); - display("LDAP server content", openDJController.dumpEntries()); + displayValue("LDAP server tree", openDJController.dumpTree()); + displayValue("LDAP server content", openDJController.dumpEntries()); } } diff --git a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestShadowsPerformance.java b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestShadowsPerformance.java index a105b9b609b..ce04229369a 100644 --- a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestShadowsPerformance.java +++ b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestShadowsPerformance.java @@ -130,7 +130,7 @@ public void test100ImportAccounts() throws Exception { then(); Task taskAfter = waitForTaskFinish(TASK_IMPORT_OID, true, SYNC_TASK_WAIT_TIMEOUT); - display("task after", prismContext.xmlSerializer().serialize(taskAfter.getUpdatedTaskObject())); + displayValue("task after", prismContext.xmlSerializer().serialize(taskAfter.getUpdatedTaskObject())); OperationStatsType statistics = getTaskTreeOperationStatistics(TASK_IMPORT_OID); displayOperationStatistics(statistics); @@ -158,7 +158,7 @@ public void test200DeleteAccountsAndReconcile() throws Exception { then(); Task taskAfter = waitForTaskFinish(TASK_RECONCILIATION_OID, true, 0L, SYNC_TASK_WAIT_TIMEOUT, false, 100, null); - display("task after", prismContext.xmlSerializer().serialize(taskAfter.getUpdatedTaskObject())); + displayValue("task after", prismContext.xmlSerializer().serialize(taskAfter.getUpdatedTaskObject())); OperationStatsType statistics = getTaskTreeOperationStatistics(TASK_RECONCILIATION_OID); displayOperationStatistics(statistics); @@ -186,7 +186,7 @@ public void test210DeleteShadows() throws Exception { then(); Task taskAfter = waitForTaskFinish(TASK_BULK_DELETE_OID, true, 0L, SYNC_TASK_WAIT_TIMEOUT, false, 100, null); - display("task after", prismContext.xmlSerializer().serialize(taskAfter.getUpdatedTaskObject())); + displayValue("task after", prismContext.xmlSerializer().serialize(taskAfter.getUpdatedTaskObject())); OperationStatsType statistics = getTaskTreeOperationStatistics(TASK_BULK_DELETE_OID); displayOperationStatistics(statistics); @@ -202,7 +202,7 @@ public void test900Summarize() { for (Map.Entry entry : durations.entrySet()) { sb.append(summary(entry.getKey(), entry.getValue())); } - display("Summary (" + NUMBER_OF_GENERATED_USERS + " users)", sb.toString()); + displayValue("Summary (" + NUMBER_OF_GENERATED_USERS + " users)", sb.toString()); // THEN then(); diff --git a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestThresholds.java b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestThresholds.java index 03101573ab4..e961628e564 100644 --- a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestThresholds.java +++ b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestThresholds.java @@ -257,6 +257,6 @@ public void test520ImportDisabledAccounts() throws Exception { } void dumpSynchronizationInformation(SynchronizationInformationType synchronizationInformation) { - display("Synchronization information", SynchronizationInformation.format(synchronizationInformation)); + displayValue("Synchronization information", SynchronizationInformation.format(synchronizationInformation)); } } diff --git a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestThresholdsReconFull.java b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestThresholdsReconFull.java index 5861da8a0cc..1f101eebf00 100644 --- a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestThresholdsReconFull.java +++ b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestThresholdsReconFull.java @@ -13,8 +13,6 @@ import com.evolveum.midpoint.schema.statistics.IterativeTaskInformation; -import com.evolveum.midpoint.schema.statistics.SynchronizationInformation; - import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.annotation.DirtiesContext.ClassMode; import org.springframework.test.context.ContextConfiguration; @@ -189,7 +187,7 @@ protected void assertSynchronizationStatisticsAfterSecondImport(Task taskAfter) protected void assertSynchronizationStatisticsActivation(Task taskAfter) { IterativeTaskInformationType infoType = taskAfter.getStoredOperationStats().getIterativeTaskInformation(); assertEquals(infoType.getTotalFailureCount(), 1); - display("Iterative task information", IterativeTaskInformation.format(infoType)); + displayValue("Iterative task information", IterativeTaskInformation.format(infoType)); SynchronizationInformationType synchronizationInformation = taskAfter.getStoredOperationStats().getSynchronizationInformation(); dumpSynchronizationInformation(synchronizationInformation); diff --git a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestVillage.java b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestVillage.java index fe0979033bb..579ec80608d 100644 --- a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestVillage.java +++ b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestVillage.java @@ -351,7 +351,7 @@ public void test022ResourceOpenDjRefinedSchema() throws Exception { RefinedResourceSchema refinedSchemaAfter = RefinedResourceSchema.getRefinedSchema(resourceAfter); long t4 = System.currentTimeMillis(); - display("Times", "getObject(RESOURCE_OPENDJ_OID): " + (t1 - t0) + "ms\ngetResourceSchema: " + (t3 - t2) + displayValue("Times", "getObject(RESOURCE_OPENDJ_OID): " + (t1 - t0) + "ms\ngetResourceSchema: " + (t3 - t2) + "ms\ngetRefinedSchema: " + (t4 - t3) + "ms"); // variable number of clones: 1 or 2 because of trigger scanner task @@ -775,7 +775,7 @@ public void test310ProjectJollyRogerNestedGroup() throws Exception { "cn: jollyrogers\n" + GROUP_MEMBER_ATTRIBUTE_NAME + ": " + GROUP_PROJECT_JOLLY_ROGER_ADMIN_DN + "\n"); - display("LDAP entries", openDJController.dumpEntries()); + displayValue("LDAP entries", openDJController.dumpEntries()); ObjectQuery query = ObjectQueryUtil.createResourceAndObjectClassFilterPrefix(RESOURCE_OPENDJ_OID, GROUP_OF_UNIQUE_NAMES_OBJECTCLASS_QNAME, prismContext) .and().itemWithDef( diff --git a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/ldap/AbstractLdapTest.java b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/ldap/AbstractLdapTest.java index c4d85e914ed..a8163c05866 100644 --- a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/ldap/AbstractLdapTest.java +++ b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/ldap/AbstractLdapTest.java @@ -70,8 +70,8 @@ public abstract class AbstractLdapTest extends AbstractStoryTest { protected abstract String getLdapResourceOid(); protected void dumpLdap() throws DirectoryException { - display("LDAP server tree", openDJController.dumpTree()); - display("LDAP server content", openDJController.dumpEntries()); + displayValue("LDAP server tree", openDJController.dumpTree()); + displayValue("LDAP server content", openDJController.dumpEntries()); } //// should be in AbstractModelIntegrationTest diff --git a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/ldap/TestLdapAssociationPerformance.java b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/ldap/TestLdapAssociationPerformance.java index 1a17d449963..b2699991550 100644 --- a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/ldap/TestLdapAssociationPerformance.java +++ b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/ldap/TestLdapAssociationPerformance.java @@ -297,7 +297,7 @@ private void dumpRepoSnapshot( String.format("%" + (max + 2) + "s: " + REPO_LINE_FORMAT, kind, counters.get(kind).getInvocationCount(), (double) counters.get(kind).getInvocationCount() / unitCount, unit))); - display(label + " (" + NUMBER_OF_GENERATED_USERS + " users, " + NUMBER_OF_GENERATED_ROLES + " roles) - per " + unit, sb.toString()); + displayValue(label + " (" + NUMBER_OF_GENERATED_USERS + " users, " + NUMBER_OF_GENERATED_ROLES + " roles) - per " + unit, sb.toString()); } @Test @@ -515,7 +515,7 @@ public void test900Summarize() { for (Map.Entry entry : durations.entrySet()) { sb.append(summary(entry.getKey(), entry.getValue())); } - display("Summary (" + NUMBER_OF_GENERATED_USERS + " users, " + NUMBER_OF_GENERATED_ROLES + " roles)", sb.toString()); + displayValue("Summary (" + NUMBER_OF_GENERATED_USERS + " users, " + NUMBER_OF_GENERATED_ROLES + " roles)", sb.toString()); // THEN then(); diff --git a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/ldap/TestLdapDependency.java b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/ldap/TestLdapDependency.java index 49ddbedd183..78074bb9371 100644 --- a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/ldap/TestLdapDependency.java +++ b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/ldap/TestLdapDependency.java @@ -399,7 +399,7 @@ private void assertLdapObject(PrismObject org, ShadowKindType kind, Str throws SchemaException, ObjectNotFoundException, SecurityViolationException, CommunicationException, ConfigurationException, DirectoryException, ExpressionEvaluationException { String orgName = org.getName().toString(); - display("assert org", orgName); + displayValue("assert org", orgName); String objOid = getLinkRefOid(org, RESOURCE_OPENDJ_OID, kind, intent); PrismObject objShadow = getShadowModel(objOid); diff --git a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/ldap/TestLdapReconPerformance.java b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/ldap/TestLdapReconPerformance.java index a7ce8f95ce0..7e79949139e 100644 --- a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/ldap/TestLdapReconPerformance.java +++ b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/ldap/TestLdapReconPerformance.java @@ -281,7 +281,7 @@ public void test900Summarize() { for (Map.Entry entry : durations.entrySet()) { sb.append(summary(entry.getKey(), entry.getValue())); } - display("Summary (" + NUMBER_OF_GENERATED_USERS + " users)", sb.toString()); + displayValue("Summary (" + NUMBER_OF_GENERATED_USERS + " users)", sb.toString()); // THEN then(); diff --git a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/ldap/TestLdapSyncMassive.java b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/ldap/TestLdapSyncMassive.java index 5a1b9c73299..c10af97b87e 100644 --- a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/ldap/TestLdapSyncMassive.java +++ b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/ldap/TestLdapSyncMassive.java @@ -137,13 +137,13 @@ public void test080ImportSyncTask() throws Exception { PrismObject syncTask = getTask(TASK_LIVE_SYNC_OID); lastSyncToken = ObjectTypeUtil.getExtensionItemRealValue(syncTask, SchemaConstants.SYNC_TOKEN); - display("Initial sync token", lastSyncToken); + displayValue("Initial sync token", lastSyncToken); assertNotNull("Null sync token", lastSyncToken); assertLdapConnectorInstances(1); threadCountBaseline = Thread.activeCount(); - display("Thread count baseline", threadCountBaseline); + displayValue("Thread count baseline", threadCountBaseline); dumpLdap(); } @@ -493,6 +493,6 @@ private void assertSyncTokenIncrement(int expectedIncrement) throws ObjectNotFou @Override protected void dumpLdap() throws DirectoryException { - display("LDAP server tree", openDJController.dumpTree()); + displayValue("LDAP server tree", openDJController.dumpTree()); } } diff --git a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/ldap/TestLdapVirtualGroup.java b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/ldap/TestLdapVirtualGroup.java index 2072c9309f7..4a0f6a2075b 100644 --- a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/ldap/TestLdapVirtualGroup.java +++ b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/ldap/TestLdapVirtualGroup.java @@ -448,7 +448,7 @@ private void assertLdapUserObject(PrismObject user, ShadowKindType kin throws SchemaException, ObjectNotFoundException, SecurityViolationException, CommunicationException, ConfigurationException, DirectoryException, ExpressionEvaluationException { String userName = user.getName().toString(); - display("assert user", userName); + displayValue("assert user", userName); String objOid = getLinkRefOid(user, RESOURCE_OPENDJ_OID, kind, intent); PrismObject objShadow = getShadowModel(objOid); @@ -468,7 +468,7 @@ private void assertLdapObject(PrismObject role, ShadowKindType kind, S throws SchemaException, ObjectNotFoundException, SecurityViolationException, CommunicationException, ConfigurationException, DirectoryException, ExpressionEvaluationException { String roleName = role.getName().toString(); - display("assert role", roleName); + displayValue("assert role", roleName); String objOid = getLinkRefOid(role, RESOURCE_OPENDJ_OID, kind, intent); PrismObject objShadow = getShadowModel(objOid); @@ -492,7 +492,7 @@ private void assertShadowAttribute(PrismObject focus, throws SchemaException, ObjectNotFoundException, SecurityViolationException, CommunicationException, ConfigurationException, ExpressionEvaluationException { String focusName = focus.getName().toString(); - display("assert focus " + focus.getCompileTimeClass(), focusName); + displayValue("assert focus " + focus.getCompileTimeClass(), focusName); String objOid = getLinkRefOid(focus, RESOURCE_OPENDJ_OID, kind, intent); PrismObject objShadow = getShadowModel(objOid); diff --git a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/ldap/hierarchy/AbstractLdapHierarchyTest.java b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/ldap/hierarchy/AbstractLdapHierarchyTest.java index 299492babae..2049c72c73c 100644 --- a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/ldap/hierarchy/AbstractLdapHierarchyTest.java +++ b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/ldap/hierarchy/AbstractLdapHierarchyTest.java @@ -498,7 +498,7 @@ protected PrismObject getAndAssertUser( Entry accountEntry = openDJController.searchSingle("uid=" + username); assertNotNull("No account LDAP entry for " + username, accountEntry); - display("account entry", openDJController.toHumanReadableLdifoid(accountEntry)); + displayValue("account entry", openDJController.toHumanReadableLdifoid(accountEntry)); openDJController.assertObjectClass(accountEntry, "inetOrgPerson"); return user; @@ -517,7 +517,7 @@ protected PrismObject getAndAssertFunctionalOrg(String orgName, String Entry groupEntry = openDJController.searchSingle("cn=" + orgName); assertNotNull("No group LDAP entry for " + orgName, groupEntry); - display("OU GROUP entry", openDJController.toHumanReadableLdifoid(groupEntry)); + displayValue("OU GROUP entry", openDJController.toHumanReadableLdifoid(groupEntry)); openDJController.assertObjectClass(groupEntry, "groupOfUniqueNames"); assertHasOrg(org, directParentOrgOid); @@ -535,12 +535,12 @@ protected PrismObject getOrg(String orgName) throws SchemaException, Ob } protected void dumpOrgTree() throws SchemaException, ObjectNotFoundException, SecurityViolationException, CommunicationException, ConfigurationException, ExpressionEvaluationException { - display("Org tree", dumpOrgTree(ORG_TOP_OID)); + displayValue("Org tree", dumpOrgTree(ORG_TOP_OID)); } protected void dumpLdap() throws DirectoryException { - display("LDAP server tree", openDJController.dumpTree()); - display("LDAP server content", openDJController.dumpEntries()); + displayValue("LDAP server tree", openDJController.dumpTree()); + displayValue("LDAP server content", openDJController.dumpEntries()); } protected void assertGroupMembers(PrismObject org, String... members) throws Exception { diff --git a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/ldap/hierarchy/TestLdapDeeplyHierarchical.java b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/ldap/hierarchy/TestLdapDeeplyHierarchical.java index c7d9a844ccc..dd032e9f31f 100644 --- a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/ldap/hierarchy/TestLdapDeeplyHierarchical.java +++ b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/ldap/hierarchy/TestLdapDeeplyHierarchical.java @@ -87,7 +87,7 @@ protected PrismObject getAndAssertFunctionalOrg(String orgName, String PrismObject parentOrg = getObject(OrgType.class, directParentOrgOid); Entry parentGroupEntry = openDJController.searchSingle("cn="+parentOrg.getName()); assertNotNull("No group LDAP entry for "+parentOrg.getName(), parentGroupEntry); - display("parent group entry", openDJController.toHumanReadableLdifoid(parentGroupEntry)); + displayValue("parent group entry", openDJController.toHumanReadableLdifoid(parentGroupEntry)); openDJController.assertUniqueMember(parentGroupEntry, groupEntry.getDN().toString()); } @@ -97,7 +97,7 @@ protected PrismObject getAndAssertFunctionalOrg(String orgName, String Entry groupEntry = openDJController.searchSingle("ou="+orgName); assertNotNull("No UO LDAP entry for "+orgName, groupEntry); - display("OU entry", openDJController.toHumanReadableLdifoid(groupEntry)); + displayValue("OU entry", openDJController.toHumanReadableLdifoid(groupEntry)); openDJController.assertObjectClass(groupEntry, "organizationalUnit"); String expectedDn = getOuDn(org); diff --git a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/ldap/hierarchy/TestLdapHierarchical.java b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/ldap/hierarchy/TestLdapHierarchical.java index a38844eb6be..4aa54e88a7a 100644 --- a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/ldap/hierarchy/TestLdapHierarchical.java +++ b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/ldap/hierarchy/TestLdapHierarchical.java @@ -82,7 +82,7 @@ protected PrismObject getAndAssertFunctionalOrg(String orgName, String PrismObject parentOrg = getObject(OrgType.class, directParentOrgOid); Entry parentGroupEntry = openDJController.searchSingle("cn="+parentOrg.getName()); assertNotNull("No group LDAP entry for "+parentOrg.getName(), parentGroupEntry); - display("parent group entry", openDJController.toHumanReadableLdifoid(parentGroupEntry)); + displayValue("parent group entry", openDJController.toHumanReadableLdifoid(parentGroupEntry)); openDJController.assertUniqueMember(parentGroupEntry, groupEntry.getDN().toString()); } @@ -92,7 +92,7 @@ protected PrismObject getAndAssertFunctionalOrg(String orgName, String Entry groupEntry = openDJController.searchSingle("ou="+orgName); assertNotNull("No UO LDAP entry for "+orgName, groupEntry); - display("OU entry", openDJController.toHumanReadableLdifoid(groupEntry)); + displayValue("OU entry", openDJController.toHumanReadableLdifoid(groupEntry)); openDJController.assertObjectClass(groupEntry, "organizationalUnit"); String expectedDn = getOuDn(org); diff --git a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/notorious/AbstractNotoriousTest.java b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/notorious/AbstractNotoriousTest.java index 3f317c01727..f44b105df42 100644 --- a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/notorious/AbstractNotoriousTest.java +++ b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/notorious/AbstractNotoriousTest.java @@ -160,8 +160,8 @@ public void test000Sanity() throws Exception { assertObjects(RoleType.class, NUMBER_OF_LEVEL_A_ROLES + NUMBER_OF_LEVEL_B_ROLES + NUMBER_OF_ORDINARY_ROLES + getNumberOfExtraRoles()); assertObjects(OrgType.class, getNumberOfExtraOrgs()); - display("Repo reads", InternalMonitor.getCount(InternalCounters.REPOSITORY_READ_COUNT)); - display("Object compares", InternalMonitor.getCount(InternalCounters.PRISM_OBJECT_COMPARE_COUNT)); + displayValue("Repo reads", InternalMonitor.getCount(InternalCounters.REPOSITORY_READ_COUNT)); + displayValue("Object compares", InternalMonitor.getCount(InternalCounters.PRISM_OBJECT_COMPARE_COUNT)); } @Test @@ -185,7 +185,7 @@ public void test100AssignRa0ToJack() throws Exception { display("Ra0 assign in "+(endMillis - startMillis)+"ms ("+((endMillis - startMillis)/(NUMBER_OF_LEVEL_B_ROLES + 2))+"ms per assigned role)"); PrismObject userAfter = getUser(USER_JACK_OID); - display("User after", assignmentSummary(userAfter)); + displayValue("User after", assignmentSummary(userAfter)); assertJackRoleAMembershipRef(userAfter, 1); assertNotoriousParentOrgRef(userAfter); @@ -218,7 +218,7 @@ public void test102RecomputeJack() throws Exception { display("Ra0 recompute in "+(endMillis - startMillis)+"ms ("+((endMillis - startMillis)/(NUMBER_OF_LEVEL_B_ROLES + 2))+"ms per assigned role)"); PrismObject userAfter = getUser(USER_JACK_OID); - display("User after", assignmentSummary(userAfter)); + displayValue("User after", assignmentSummary(userAfter)); assertJackRoleAMembershipRef(userAfter, 1); assertNotoriousParentOrgRef(userAfter); @@ -234,7 +234,7 @@ public void test104PreviewChangesJack() throws Exception { OperationResult result = task.getResult(); PrismObject userBefore = getUser(USER_JACK_OID); - display("User before", assignmentSummary(userBefore)); + displayValue("User before", assignmentSummary(userBefore)); ObjectDelta delta = userBefore.createModifyDelta(); delta.addModificationReplaceProperty(UserType.F_EMPLOYEE_NUMBER, "123"); @@ -254,7 +254,7 @@ public void test104PreviewChangesJack() throws Exception { display("Ra0 preview changes in "+(endMillis - startMillis)+"ms ("+((endMillis - startMillis)/(NUMBER_OF_LEVEL_B_ROLES + 2))+"ms per assigned role)"); PrismObject userAfter = getUser(USER_JACK_OID); - display("User after", assignmentSummary(userAfter)); + displayValue("User after", assignmentSummary(userAfter)); assertJackRoleAMembershipRef(userAfter, 1); assertNotoriousParentOrgRef(userAfter); @@ -285,7 +285,7 @@ public void test109UnassignRa0FromJack() throws Exception { display("Ra0 unassign in "+(endMillis - startMillis)+"ms ("+((endMillis - startMillis)/(NUMBER_OF_LEVEL_B_ROLES + 2))+"ms per assigned role)"); PrismObject userAfter = getUser(USER_JACK_OID); - display("User after", assignmentSummary(userAfter)); + displayValue("User after", assignmentSummary(userAfter)); assertNoAssignments(userAfter); assertRoleMembershipRefs(userAfter, 0); assertNoNotoriousParentOrgRef(userAfter); @@ -316,7 +316,7 @@ public void test110Assign5ARolesToJack() throws Exception { display("Assign 5 A roles in "+(endMillis - startMillis)+"ms ("+((endMillis - startMillis)/(NUMBER_OF_LEVEL_B_ROLES + 1 + 5))+"ms per assigned role)"); PrismObject userAfter = getUser(USER_JACK_OID); - display("User after", assignmentSummary(userAfter)); + displayValue("User after", assignmentSummary(userAfter)); assertJackRoleAMembershipRef(userAfter, 5); assertNotoriousParentOrgRef(userAfter); @@ -346,7 +346,7 @@ public void test112RecomputeJack() throws Exception { display("Recompute 5 A roles in "+(endMillis - startMillis)+"ms ("+((endMillis - startMillis)/(NUMBER_OF_LEVEL_B_ROLES + 1 + 5))+"ms per assigned role)"); PrismObject userAfter = getUser(USER_JACK_OID); - display("User after", assignmentSummary(userAfter)); + displayValue("User after", assignmentSummary(userAfter)); assertJackRoleAMembershipRef(userAfter, 5); assertNotoriousParentOrgRef(userAfter); @@ -376,7 +376,7 @@ public void test119Unassign5ARolesFromJack() throws Exception { display("Ra0 unassign in "+(endMillis - startMillis)+"ms ("+((endMillis - startMillis)/(NUMBER_OF_LEVEL_B_ROLES + 1 + 5))+"ms per assigned role)"); PrismObject userAfter = getUser(USER_JACK_OID); - display("User after", assignmentSummary(userAfter)); + displayValue("User after", assignmentSummary(userAfter)); assertNoAssignments(userAfter); assertRoleMembershipRefs(userAfter, 0); assertNoNotoriousParentOrgRef(userAfter); @@ -407,7 +407,7 @@ public void test120AssignAllARolesToJack() throws Exception { display("Assign all A roles in "+(endMillis - startMillis)+"ms ("+((endMillis - startMillis)/(NUMBER_OF_LEVEL_B_ROLES + 1 + NUMBER_OF_LEVEL_A_ROLES))+"ms per assigned role)"); PrismObject userAfter = getUser(USER_JACK_OID); - display("User after", assignmentSummary(userAfter)); + displayValue("User after", assignmentSummary(userAfter)); assertJackRoleAMembershipRef(userAfter, NUMBER_OF_LEVEL_A_ROLES); assertNotoriousParentOrgRef(userAfter); @@ -437,7 +437,7 @@ public void test122RecomputeJack() throws Exception { display("Recompute all A roles in "+(endMillis - startMillis)+"ms ("+((endMillis - startMillis)/(NUMBER_OF_LEVEL_B_ROLES + 1 + NUMBER_OF_LEVEL_A_ROLES))+"ms per assigned role)"); PrismObject userAfter = getUser(USER_JACK_OID); - display("User after", assignmentSummary(userAfter)); + displayValue("User after", assignmentSummary(userAfter)); assertJackRoleAMembershipRef(userAfter, NUMBER_OF_LEVEL_A_ROLES); assertNotoriousParentOrgRef(userAfter); @@ -453,7 +453,7 @@ public void test124PreviewChangesJack() throws Exception { OperationResult result = task.getResult(); PrismObject userBefore = getUser(USER_JACK_OID); - display("User before", assignmentSummary(userBefore)); + displayValue("User before", assignmentSummary(userBefore)); ObjectDelta delta = userBefore.createModifyDelta(); delta.addModificationReplaceProperty(UserType.F_EMPLOYEE_NUMBER, "123"); @@ -473,7 +473,7 @@ public void test124PreviewChangesJack() throws Exception { display("Preview changes (all A roles) in "+(endMillis - startMillis)+"ms ("+((endMillis - startMillis)/(NUMBER_OF_LEVEL_B_ROLES + 1 + NUMBER_OF_LEVEL_A_ROLES))+"ms per assigned role)"); PrismObject userAfter = getUser(USER_JACK_OID); - display("User after", assignmentSummary(userAfter)); + displayValue("User after", assignmentSummary(userAfter)); assertJackRoleAMembershipRef(userAfter, NUMBER_OF_LEVEL_A_ROLES); assertNotoriousParentOrgRef(userAfter); @@ -504,7 +504,7 @@ public void test129UnassignAllARolesFromJack() throws Exception { display("Unassign all A roles in "+(endMillis - startMillis)+"ms ("+((endMillis - startMillis)/(NUMBER_OF_LEVEL_B_ROLES + 1 + NUMBER_OF_LEVEL_A_ROLES))+"ms per assigned role)"); PrismObject userAfter = getUser(USER_JACK_OID); - display("User after", assignmentSummary(userAfter)); + displayValue("User after", assignmentSummary(userAfter)); assertNoAssignments(userAfter); assertRoleMembershipRefs(userAfter, 0); assertNoNotoriousParentOrgRef(userAfter); @@ -536,7 +536,7 @@ public void test130AssignRb0ToJack() throws Exception { display("Rb0 assign in "+(endMillis - startMillis)+"ms ("+((endMillis - startMillis)/(NUMBER_OF_LEVEL_B_ROLES + 2))+"ms per assigned role)"); PrismObject userAfter = getUser(USER_JACK_OID); - display("User after", assignmentSummary(userAfter)); + displayValue("User after", assignmentSummary(userAfter)); assertRoleMembershipRef(userAfter, generateRoleBOid(0)); assertNoNotoriousParentOrgRef(userAfter); @@ -576,7 +576,7 @@ public void test132AssignRa0ToJack() throws Exception { display("Ra0 assign in "+(endMillis - startMillis)+"ms ("+((endMillis - startMillis)/(NUMBER_OF_LEVEL_B_ROLES + 2))+"ms per assigned role)"); PrismObject userAfter = getUser(USER_JACK_OID); - display("User after", assignmentSummary(userAfter)); + displayValue("User after", assignmentSummary(userAfter)); assertJackRoleAMembershipRef(userAfter, 1); assertNotoriousParentOrgRef(userAfter); @@ -609,7 +609,7 @@ public void test134RecomputeJack() throws Exception { display("Ra0+Rb0 recompute in "+(endMillis - startMillis)+"ms ("+((endMillis - startMillis)/(NUMBER_OF_LEVEL_B_ROLES + 2))+"ms per assigned role)"); PrismObject userAfter = getUser(USER_JACK_OID); - display("User after", assignmentSummary(userAfter)); + displayValue("User after", assignmentSummary(userAfter)); assertJackRoleAMembershipRef(userAfter, 1); assertNotoriousParentOrgRef(userAfter); @@ -642,7 +642,7 @@ public void test136UnassignRb0FromJack() throws Exception { display("Rb0 unassign in "+(endMillis - startMillis)+"ms ("+((endMillis - startMillis)/(NUMBER_OF_LEVEL_B_ROLES + 2))+"ms per assigned role)"); PrismObject userAfter = getUser(USER_JACK_OID); - display("User after", assignmentSummary(userAfter)); + displayValue("User after", assignmentSummary(userAfter)); assertJackRoleAMembershipRef(userAfter, 1); assertNotoriousParentOrgRef(userAfter); @@ -676,7 +676,7 @@ public void test138AssignRb0ToJackAgain() throws Exception { display("Rb0 assign in "+(endMillis - startMillis)+"ms ("+((endMillis - startMillis)/(NUMBER_OF_LEVEL_B_ROLES + 2))+"ms per assigned role)"); PrismObject userAfter = getUser(USER_JACK_OID); - display("User after", assignmentSummary(userAfter)); + displayValue("User after", assignmentSummary(userAfter)); assertJackRoleAMembershipRef(userAfter, 1); assertNotoriousParentOrgRef(userAfter); @@ -709,7 +709,7 @@ public void test140RecomputeJackAgain() throws Exception { display("Ra0+Rb0 recompute again in "+(endMillis - startMillis)+"ms ("+((endMillis - startMillis)/(NUMBER_OF_LEVEL_B_ROLES + 2))+"ms per assigned role)"); PrismObject userAfter = getUser(USER_JACK_OID); - display("User after", assignmentSummary(userAfter)); + displayValue("User after", assignmentSummary(userAfter)); assertJackRoleAMembershipRef(userAfter, 1); assertNotoriousParentOrgRef(userAfter); @@ -742,7 +742,7 @@ public void test142RecomputeJackAlt() throws Exception { display("Ra0+Rb0 recompute again in "+(endMillis - startMillis)+"ms ("+((endMillis - startMillis)/(NUMBER_OF_LEVEL_B_ROLES + 2))+"ms per assigned role)"); PrismObject userAfter = getUser(USER_JACK_OID); - display("User after", assignmentSummary(userAfter)); + displayValue("User after", assignmentSummary(userAfter)); assertJackRoleAMembershipRef(userAfter, 1); assertNotoriousParentOrgRef(userAfter); @@ -775,7 +775,7 @@ public void test144UnassignRa0FromJack() throws Exception { display("Ra0 unassign in "+(endMillis - startMillis)+"ms ("+((endMillis - startMillis)/(NUMBER_OF_LEVEL_B_ROLES + 2))+"ms per assigned role)"); PrismObject userAfter = getUser(USER_JACK_OID); - display("User after", assignmentSummary(userAfter)); + displayValue("User after", assignmentSummary(userAfter)); assertRoleMembershipRef(userAfter, generateRoleBOid(0)); assertNoNotoriousParentOrgRef(userAfter); @@ -809,7 +809,7 @@ public void test149UnassignRb0FromJack() throws Exception { display("Rb0 unassign in "+(endMillis - startMillis)+"ms ("+((endMillis - startMillis)/(NUMBER_OF_LEVEL_B_ROLES + 2))+"ms per assigned role)"); PrismObject userAfter = getUser(USER_JACK_OID); - display("User after", assignmentSummary(userAfter)); + displayValue("User after", assignmentSummary(userAfter)); assertNoAssignments(userAfter); assertRoleMembershipRefs(userAfter, 0); assertNoNotoriousParentOrgRef(userAfter); @@ -849,7 +849,7 @@ public void test150AssignNotoriousDefaultToJack() throws Exception { display("Notorious relation=default assign in "+(endMillis - startMillis)+"ms ("+((endMillis - startMillis)/(NUMBER_OF_LEVEL_B_ROLES + 2))+"ms per assigned role)"); PrismObject userAfter = getUser(USER_JACK_OID); - display("User after", assignmentSummary(userAfter)); + displayValue("User after", assignmentSummary(userAfter)); assertJackRoleAMembershipRef(userAfter, 0); assertNotoriousParentOrgRef(userAfter); @@ -889,7 +889,7 @@ public void test152AssignNotoriousAltRelationToJack() throws Exception { display("Notorious relation="+getAltRelation().getLocalPart()+" assign in "+(endMillis - startMillis)+"ms ("+((endMillis - startMillis)/(NUMBER_OF_LEVEL_B_ROLES + 2))+"ms per assigned role)"); PrismObject userAfter = getUser(USER_JACK_OID); - display("User after", assignmentSummary(userAfter)); + displayValue("User after", assignmentSummary(userAfter)); assertRoleMembershipRefNonExclusive(userAfter, getNotoriousOid(), getNotoriousType(), SchemaConstants.ORG_DEFAULT); assertRoleMembershipRefNonExclusive(userAfter, getNotoriousOid(), getNotoriousType(), getAltRelation()); @@ -929,7 +929,7 @@ public void test154RecomputeJack() throws Exception { display("Notorious relation="+getAltRelation().getLocalPart()+" assign in "+(endMillis - startMillis)+"ms ("+((endMillis - startMillis)/(NUMBER_OF_LEVEL_B_ROLES + 2))+"ms per assigned role)"); PrismObject userAfter = getUser(USER_JACK_OID); - display("User after", assignmentSummary(userAfter)); + displayValue("User after", assignmentSummary(userAfter)); assertRoleMembershipRefNonExclusive(userAfter, getNotoriousOid(), getNotoriousType(), SchemaConstants.ORG_DEFAULT); assertRoleMembershipRefNonExclusive(userAfter, getNotoriousOid(), getNotoriousType(), getAltRelation()); @@ -973,7 +973,7 @@ public void test156RecomputeJackAlt() throws Exception { display("Notorious relation="+getAltRelation().getLocalPart()+" unassign in "+(endMillis - startMillis)+"ms ("+((endMillis - startMillis)/(NUMBER_OF_LEVEL_B_ROLES + 2))+"ms per assigned role)"); PrismObject userAfter = getUser(USER_JACK_OID); - display("User after", assignmentSummary(userAfter)); + displayValue("User after", assignmentSummary(userAfter)); assertRoleMembershipRefNonExclusive(userAfter, getNotoriousOid(), getNotoriousType(), SchemaConstants.ORG_DEFAULT); assertRoleMembershipRefNonExclusive(userAfter, getNotoriousOid(), getNotoriousType(), getAltRelation()); @@ -1014,7 +1014,7 @@ public void test158UnassignNotoriousDefaultFromJack() throws Exception { display("Notorious relation=default unassign in "+(endMillis - startMillis)+"ms ("+((endMillis - startMillis)/(NUMBER_OF_LEVEL_B_ROLES + 2))+"ms per assigned role)"); PrismObject userAfter = getUser(USER_JACK_OID); - display("User after", assignmentSummary(userAfter)); + displayValue("User after", assignmentSummary(userAfter)); assertTest158RoleMembershipRef(userAfter); assertNotoriousParentOrgRefRelations(userAfter, getAltRelation()); @@ -1053,7 +1053,7 @@ public void test159UnassignNotoriousAltRelationFromJack() throws Exception { display("Notorious relation="+getAltRelation().getLocalPart()+" assign in "+(endMillis - startMillis)+"ms ("+((endMillis - startMillis)/(NUMBER_OF_LEVEL_B_ROLES + 2))+"ms per assigned role)"); PrismObject userAfter = getUser(USER_JACK_OID); - display("User after", assignmentSummary(userAfter)); + displayValue("User after", assignmentSummary(userAfter)); assertNoAssignments(userAfter); assertRoleMembershipRefs(userAfter, 0); assertNoNotoriousParentOrgRef(userAfter); diff --git a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/perf/TestImport.java b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/perf/TestImport.java index f9c4fe0d863..fcb6ec0ba62 100644 --- a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/perf/TestImport.java +++ b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/perf/TestImport.java @@ -89,7 +89,7 @@ public void initSystem(Task initTask, OperationResult initResult) throws Excepti repoAddObjectFromFile(ORG_BASIC_FILE, OrgType.class, initResult); usersBefore = repositoryService.countObjects(UserType.class, null, null, initResult); - display("users before", usersBefore); + displayValue("users before", usersBefore); //InternalMonitor.setTrace(InternalOperationClasses.PRISM_OBJECT_CLONES, true); } @@ -162,10 +162,10 @@ public void test100RunImport() throws Exception { PrismObject taskAfter = repositoryService.getObject(TaskType.class, TASK_IMPORT_OID, null, result); String taskXml = prismContext.xmlSerializer().serialize(taskAfter); - display("Task after", taskXml); + displayValue("Task after", taskXml); int usersAfter = repositoryService.countObjects(UserType.class, null, null, result); - display("users after", usersAfter); + displayValue("users after", usersAfter); assertEquals("Wrong # of users", usersBefore + USERS, usersAfter); } diff --git a/tools/test-ng/src/main/java/com/evolveum/midpoint/tools/testng/MidpointTestMixin.java b/tools/test-ng/src/main/java/com/evolveum/midpoint/tools/testng/MidpointTestMixin.java index 2425d4f606c..b597a1f605f 100644 --- a/tools/test-ng/src/main/java/com/evolveum/midpoint/tools/testng/MidpointTestMixin.java +++ b/tools/test-ng/src/main/java/com/evolveum/midpoint/tools/testng/MidpointTestMixin.java @@ -134,7 +134,10 @@ default void display(String text) { logger().debug("*** {}", text); } - default void display(String title, String value) { + /** + * Displays + */ + default void displayValue(String title, Object value) { System.out.println("\n*** " + title + "\n" + value); logger().debug("*** {}\n{}", title, value); } From e1b6fb81c18dec045605cc2a511c6d8e47f9cb33 Mon Sep 17 00:00:00 2001 From: Pavol Mederly Date: Mon, 16 Mar 2020 12:04:43 +0100 Subject: [PATCH 04/21] Mark case.taskRef as deprecated --- .../xml/ns/public/common/common-case-management-3.xsd | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/infra/schema/src/main/resources/xml/ns/public/common/common-case-management-3.xsd b/infra/schema/src/main/resources/xml/ns/public/common/common-case-management-3.xsd index 36f13049dc4..816c92c69d0 100644 --- a/infra/schema/src/main/resources/xml/ns/public/common/common-case-management-3.xsd +++ b/infra/schema/src/main/resources/xml/ns/public/common/common-case-management-3.xsd @@ -168,10 +168,14 @@ Reference to the task holding workflow context for wf-related cases. - EXPERIMENTAL. Probably will be removed. + DEPRECATED. Not used any more. The relation is defined the other way: + task.objectRef points to this case. tns:TaskType + true + 4.1 + 4.0.3 From 1344608673964c782d54a8e984e38da4e8d8b6c9 Mon Sep 17 00:00:00 2001 From: lskublik Date: Mon, 16 Mar 2020 12:17:49 +0100 Subject: [PATCH 05/21] adding checking of condition during adding of trigger for existence (MID-6040) --- .../model/impl/lens/projector/mappings/MappingEvaluator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/mappings/MappingEvaluator.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/mappings/MappingEvaluator.java index 26ebc7822a9..89d532ffc1b 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/mappings/MappingEvaluator.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/mappings/MappingEvaluator.java @@ -494,7 +494,7 @@ public mapping: mappings) { XMLGregorianCalendar mappingNextRecomputeTime = mapping.getNextRecomputeTime(); if (mappingNextRecomputeTime != null) { - if (nextRecomputeTime == null || nextRecomputeTime.compare(mappingNextRecomputeTime) == DatatypeConstants.GREATER) { + if (mapping.isSatisfyCondition() && (nextRecomputeTime == null || nextRecomputeTime.compare(mappingNextRecomputeTime) == DatatypeConstants.GREATER)) { nextRecomputeTime = mappingNextRecomputeTime; // TODO: maybe better description? But consider storage requirements. We do not want to store too much. triggerOriginDescription = mapping.getIdentifier(); From b1aac0a321a3479365d10678d002582af8c44d14 Mon Sep 17 00:00:00 2001 From: lskublik Date: Mon, 16 Mar 2020 14:07:40 +0100 Subject: [PATCH 06/21] fix for NPE in isSatisfyCondition (MID-6040) --- .../evolveum/midpoint/model/common/mapping/MappingImpl.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/mapping/MappingImpl.java b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/mapping/MappingImpl.java index 2ddb9705f83..cede7ba1995 100644 --- a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/mapping/MappingImpl.java +++ b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/mapping/MappingImpl.java @@ -620,6 +620,9 @@ private void addToMinusIfNecessary(V originalValue) { @SuppressWarnings("unused") // todo is this externally used? public boolean isSatisfyCondition() { + if (conditionOutputTriple == null) { + return true; + } boolean conditionOutputOld = computeConditionResult(conditionOutputTriple.getNonPositiveValues()); boolean conditionResultOld = conditionOutputOld && conditionMaskOld; From 50150061e106b1776f3dcf166ce6ab8b1f236b47 Mon Sep 17 00:00:00 2001 From: Radovan Semancik Date: Mon, 16 Mar 2020 16:59:36 +0100 Subject: [PATCH 07/21] Test for AD modifytimestamp sync (MID-5943), switch to LDAP connector 3.0-M3 --- pom.xml | 2 +- .../src/test/resources/connector-ldap.xml | 46 +- .../AbstractLdapSynchronizationTest.java | 26 +- .../testing/conntest/TestOpenDjDumber.java | 161 +- .../conntest/ad/AbstractAdLdapTest.java | 2512 ++++++++--------- .../ad/TestAdLdapMedusaSyncTimestamp.java | 27 + .../resource-medusa-sync-timestamp.xml | 379 +++ .../src/test/resources/logback-test.xml | 3 + .../test/resources/opendj-dumber/resource.xml | 737 ++--- 9 files changed, 2178 insertions(+), 1715 deletions(-) create mode 100644 testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/ad/TestAdLdapMedusaSyncTimestamp.java create mode 100644 testing/conntest/src/test/resources/ad-ldap/resource-medusa-sync-timestamp.xml diff --git a/pom.xml b/pom.xml index cf82b33eb9e..6d6d13febc5 100644 --- a/pom.xml +++ b/pom.xml @@ -893,7 +893,7 @@ com.evolveum.polygon connector-ldap - 3.0-M2 + 3.0-M3 diff --git a/provisioning/ucf-impl-connid/src/test/resources/connector-ldap.xml b/provisioning/ucf-impl-connid/src/test/resources/connector-ldap.xml index eba4396ce7c..02f7359dfe4 100644 --- a/provisioning/ucf-impl-connid/src/test/resources/connector-ldap.xml +++ b/provisioning/ucf-impl-connid/src/test/resources/connector-ldap.xml @@ -1,23 +1,23 @@ - - - - - - ICF com.evolveum.polygon.connector.ldap.LdapConnector - http://midpoint.evolveum.com/xml/ns/public/connector/icf-1 - com.evolveum.polygon.connector.ldap.LdapConnector - 3.0-M2 - com.evolveum.polygon.connector-ldap - http://midpoint.evolveum.com/xml/ns/public/connector/icf-1/bundle/com.evolveum.polygon.connector-ldap/com.evolveum.polygon.connector.ldap.LdapConnector - - - - + + + + + + ICF com.evolveum.polygon.connector.ldap.LdapConnector + http://midpoint.evolveum.com/xml/ns/public/connector/icf-1 + com.evolveum.polygon.connector.ldap.LdapConnector + 3.0-M3 + com.evolveum.polygon.connector-ldap + http://midpoint.evolveum.com/xml/ns/public/connector/icf-1/bundle/com.evolveum.polygon.connector-ldap/com.evolveum.polygon.connector.ldap.LdapConnector + + + + diff --git a/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/AbstractLdapSynchronizationTest.java b/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/AbstractLdapSynchronizationTest.java index d16461a1f95..068d5e9b3a0 100644 --- a/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/AbstractLdapSynchronizationTest.java +++ b/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/AbstractLdapSynchronizationTest.java @@ -12,6 +12,7 @@ import java.util.List; import org.apache.directory.api.ldap.model.entry.DefaultModification; +import org.apache.directory.api.ldap.model.entry.Entry; import org.apache.directory.api.ldap.model.entry.Modification; import org.apache.directory.api.ldap.model.entry.ModificationOperation; import org.apache.directory.api.ldap.model.exception.LdapException; @@ -119,6 +120,9 @@ public void test801SyncAddAccountHt() throws Exception { // WHEN when(); addLdapAccount(ACCOUNT_HT_UID, ACCOUNT_HT_CN, ACCOUNT_HT_GIVENNAME, ACCOUNT_HT_SN); + + syncWait(); + waitForTaskNextRunAssertSuccess(getSyncTaskOid(), true); // THEN @@ -153,8 +157,15 @@ public void test802ModifyAccountHtSn() throws Exception { LdapNetworkConnection connection = ldapConnect(); Modification modSn = new DefaultModification(ModificationOperation.REPLACE_ATTRIBUTE, "sn", ACCOUNT_HT_SN_MODIFIED); connection.modify(toAccountDn(ACCOUNT_HT_UID, ACCOUNT_HT_CN), modSn); + + // reread to show the timestamps. Good for timestamp debugging. + Entry entryBefore = assertLdapAccount(ACCOUNT_HT_UID, ACCOUNT_HT_CN); + display("HT AD entry", entryBefore); + ldapDisconnect(connection); + syncWait(); + waitForTaskNextRunAssertSuccess(getSyncTaskOid(), true); // THEN @@ -171,6 +182,7 @@ public void test802ModifyAccountHtSn() throws Exception { } + @Test public void test810SyncAddGroupMonkeys() throws Exception { // GIVEN @@ -186,6 +198,9 @@ public void test810SyncAddGroupMonkeys() throws Exception { } else { addLdapGroup(GROUP_MONKEYS_CN, GROUP_MONKEYS_DESCRIPTION); } + + syncWait(); + waitForTaskNextRunAssertSuccess(getSyncTaskOid(), true); // THEN @@ -226,6 +241,8 @@ public void test817RenameAccount() throws Exception { ldapDisconnect(connection); + syncWait(); + waitForTaskNextRunAssertSuccess(getSyncTaskOid(), true); // THEN @@ -243,6 +260,10 @@ public void test817RenameAccount() throws Exception { } + protected void syncWait() throws InterruptedException { + // Nothing to do here. It can be overridden in subclasses to give us better chance to "catch" the event (e.g. in timestamp-based sync). + }; + protected String getAccountHtmCnAfterRename() { return ACCOUNT_HT_CN; } @@ -265,6 +286,8 @@ public void test818DeleteAccountHtm() throws Exception { when(); deleteLdapEntry(toAccountDn(ACCOUNT_HTM_UID, ACCOUNT_HTM_CN)); + syncWait(); + waitForTaskNextRunAssertSuccess(getSyncTaskOid(), true); // THEN @@ -299,7 +322,8 @@ public void test819DeleteSyncTask() throws Exception { // THEN then(); - assertSuccess(result); + // There may be warning about deleting a running task +// assertSuccess(result); assertNoObject(TaskType.class, getSyncTaskOid(), task, result); } diff --git a/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/TestOpenDjDumber.java b/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/TestOpenDjDumber.java index 52b732d6870..d7296969d1f 100644 --- a/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/TestOpenDjDumber.java +++ b/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/TestOpenDjDumber.java @@ -1,66 +1,95 @@ -/* - * Copyright (c) 2016-2018 Evolveum and contributors - * - * This work is dual-licensed under the Apache License 2.0 - * and European Union Public License. See LICENSE file for details. - */ -package com.evolveum.midpoint.testing.conntest; - -import static org.testng.AssertJUnit.assertEquals; - -import java.io.File; - -import org.testng.annotations.Listeners; -import org.testng.annotations.Test; - -import com.evolveum.midpoint.prism.PrismObject; -import com.evolveum.midpoint.schema.SearchResultList; -import com.evolveum.midpoint.test.util.MidPointTestConstants; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType; - -/** - * OpenDJ, but without permissive modify, shortcut attributes, with manual matching rules, etc. - * Also has additional search filter. - * - * @author semancik - */ -@Listeners({ com.evolveum.midpoint.tools.testng.AlphabeticalMethodInterceptor.class }) -public class TestOpenDjDumber extends TestOpenDj { - - private static final int INITIAL_SYNC_TOKEN = 21; - - @Override - protected File getBaseDir() { - return new File(MidPointTestConstants.TEST_RESOURCES_DIR, "opendj-dumber"); - } - - @Override - protected boolean hasAssociationShortcut() { - return false; - } - - @Override - protected int getInitialSyncToken() { - return INITIAL_SYNC_TOKEN; - } - - @Override - protected boolean isUsingGroupShortcutAttribute() { - return false; - } - - /** - * Test for additional search filter. - * MID-4925 - */ - @Test - @Override - public void test350SearchInvisibleAccount() throws Exception { - // GIVEN - createBilboEntry(); - - SearchResultList> shadows = searchBilbo(); - - assertEquals("Unexpected search result: " + shadows, 0, shadows.size()); - } -} +/* + * Copyright (c) 2016-2018 Evolveum and contributors + * + * This work is dual-licensed under the Apache License 2.0 + * and European Union Public License. See LICENSE file for details. + */ +package com.evolveum.midpoint.testing.conntest; + +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertNull; + +import java.io.File; + +import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.task.api.Task; +import com.evolveum.midpoint.test.util.TestUtil; +import com.evolveum.midpoint.util.exception.ObjectNotFoundException; +import com.evolveum.midpoint.util.exception.SchemaException; + +import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; + +import org.testng.annotations.Listeners; +import org.testng.annotations.Test; + +import com.evolveum.midpoint.prism.PrismObject; +import com.evolveum.midpoint.schema.SearchResultList; +import com.evolveum.midpoint.test.util.MidPointTestConstants; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType; + +/** + * OpenDJ, but without permissive modify, shortcut attributes, with manual matching rules, etc. + * Also has additional search filter. + * + * @author semancik + */ +@Listeners({ com.evolveum.midpoint.tools.testng.AlphabeticalMethodInterceptor.class }) +public class TestOpenDjDumber extends TestOpenDj { + + private static final int INITIAL_SYNC_TOKEN = 21; + + @Override + protected File getBaseDir() { + return new File(MidPointTestConstants.TEST_RESOURCES_DIR, "opendj-dumber"); + } + + @Override + protected boolean hasAssociationShortcut() { + return false; + } + + @Override + protected int getInitialSyncToken() { + return INITIAL_SYNC_TOKEN; + } + + @Override + protected boolean isUsingGroupShortcutAttribute() { + return false; + } + + @Override + protected void assertStepSyncToken(String syncTaskOid, int step, long tsStart, long tsEnd) throws ObjectNotFoundException, SchemaException { + // TODO: assert timistamp + } + + /** + * Test for additional search filter. + * MID-4925 + */ + @Test + @Override + public void test350SearchInvisibleAccount() throws Exception { + // GIVEN + createBilboEntry(); + + SearchResultList> shadows = searchBilbo(); + + assertEquals("Unexpected search result: " + shadows, 0, shadows.size()); + } + + @Test + public void test818DeleteAccountHtm() throws Exception { + // Nothing to do. This won't work with modifytimestamp sync. + } + + @Test + public void test837RenameAccount() throws Exception { + // Nothing to do. This won't work with modifytimestamp sync. + } + + @Test + public void test838DeleteAccountHtm() throws Exception { + // Nothing to do. This won't work with modifytimestamp sync. + } +} diff --git a/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/ad/AbstractAdLdapTest.java b/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/ad/AbstractAdLdapTest.java index bffdea986aa..8ad2dbefffb 100644 --- a/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/ad/AbstractAdLdapTest.java +++ b/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/ad/AbstractAdLdapTest.java @@ -1,1256 +1,1256 @@ -/* - * Copyright (c) 2015-2019 Evolveum and contributors - *

- * This work is dual-licensed under the Apache License 2.0 - * and European Union Public License. See LICENSE file for details. - */ -package com.evolveum.midpoint.testing.conntest.ad; - -import static org.testng.AssertJUnit.*; - -import static com.evolveum.midpoint.schema.constants.SchemaConstants.PATH_ACTIVATION_ADMINISTRATIVE_STATUS; -import static com.evolveum.midpoint.schema.constants.SchemaConstants.PATH_CREDENTIALS_PASSWORD_VALUE; - -import java.io.File; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.Collection; -import java.util.List; -import javax.xml.datatype.XMLGregorianCalendar; -import javax.xml.namespace.QName; - -import org.apache.commons.lang.StringUtils; -import org.apache.directory.api.ldap.model.cursor.CursorException; -import org.apache.directory.api.ldap.model.entry.*; -import org.apache.directory.api.ldap.model.exception.LdapException; -import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException; -import org.apache.directory.api.ldap.model.name.Ava; -import org.apache.directory.api.ldap.model.name.Rdn; -import org.apache.directory.ldap.client.api.LdapNetworkConnection; -import org.testng.AssertJUnit; -import org.testng.annotations.Listeners; -import org.testng.annotations.Test; - -import com.evolveum.midpoint.prism.PrismObject; -import com.evolveum.midpoint.prism.PrismProperty; -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.prism.query.ObjectPaging; -import com.evolveum.midpoint.prism.query.ObjectQuery; -import com.evolveum.midpoint.prism.query.OrderDirection; -import com.evolveum.midpoint.prism.util.PrismAsserts; -import com.evolveum.midpoint.prism.util.PrismTestUtil; -import com.evolveum.midpoint.prism.xml.XmlTypeConverter; -import com.evolveum.midpoint.schema.SearchResultList; -import com.evolveum.midpoint.schema.SearchResultMetadata; -import com.evolveum.midpoint.schema.constants.MidPointConstants; -import com.evolveum.midpoint.schema.constants.SchemaConstants; -import com.evolveum.midpoint.schema.internals.InternalCounters; -import com.evolveum.midpoint.schema.processor.ResourceAttribute; -import com.evolveum.midpoint.schema.processor.ResourceAttributeDefinition; -import com.evolveum.midpoint.schema.result.OperationResult; -import com.evolveum.midpoint.schema.util.MiscSchemaUtil; -import com.evolveum.midpoint.schema.util.ObjectQueryUtil; -import com.evolveum.midpoint.schema.util.ShadowUtil; -import com.evolveum.midpoint.task.api.Task; -import com.evolveum.midpoint.test.IntegrationTestTools; -import com.evolveum.midpoint.test.util.MidPointTestConstants; -import com.evolveum.midpoint.test.util.TestUtil; -import com.evolveum.midpoint.testing.conntest.AbstractLdapSynchronizationTest; -import com.evolveum.midpoint.util.MiscUtil; -import com.evolveum.midpoint.util.exception.ObjectNotFoundException; -import com.evolveum.midpoint.util.exception.SchemaException; -import com.evolveum.midpoint.xml.ns._public.common.common_3.*; -import com.evolveum.prism.xml.ns._public.types_3.PolyStringType; -import com.evolveum.prism.xml.ns._public.types_3.ProtectedStringType; - -/** - * @author semancik - */ -@Listeners({ com.evolveum.midpoint.tools.testng.AlphabeticalMethodInterceptor.class }) -public abstract class AbstractAdLdapTest extends AbstractLdapSynchronizationTest - implements AdTestMixin { - - protected static final File TEST_DIR = new File(MidPointTestConstants.TEST_RESOURCES_DIR, "ad-ldap"); - - protected static final File ROLE_PIRATES_FILE = new File(TEST_DIR, "role-pirate.xml"); - protected static final String ROLE_PIRATES_OID = "5dd034e8-41d2-11e5-a123-001e8c717e5b"; - - protected static final File ROLE_META_ORG_FILE = new File(TEST_DIR, "role-meta-org.xml"); - protected static final String ROLE_META_ORG_OID = "f2ad0ace-45d7-11e5-af54-001e8c717e5b"; - - protected static final String ACCOUNT_JACK_SAM_ACCOUNT_NAME = "jack"; - protected static final String ACCOUNT_JACK_FULL_NAME = "Jack Sparrow"; - protected static final String ACCOUNT_JACK_PASSWORD = "qwe.123"; - - protected static final String USER_CPTBARBOSSA_FULL_NAME = "Captain Hector Barbossa"; - - private static final String GROUP_PIRATES_NAME = "pirates"; - private static final String GROUP_MELEE_ISLAND_NAME = "Mêlée Island"; - - protected static final int NUMBER_OF_ACCOUNTS = 12; - private static final String ASSOCIATION_GROUP_NAME = "group"; - - private static final String NS_EXTENSION = "http://whatever.com/my"; - private static final QName EXTENSION_SHOW_IN_ADVANCED_VIEW_ONLY_QNAME = new QName(NS_EXTENSION, "showInAdvancedViewOnly"); - - private boolean allowDuplicateSearchResults = false; - - protected String jackAccountOid; - protected String groupPiratesOid; - protected String accountBarbossaOid; - protected String orgMeleeIslandOid; - protected String groupMeleeOid; - - @Override - public String getStartSystemCommand() { - return null; - } - - @Override - public String getStopSystemCommand() { - return null; - } - - @Override - protected File getBaseDir() { - return TEST_DIR; - } - - @Override - protected String getSyncTaskOid() { - return "cd1e0ff2-0099-11e5-9e22-001e8c717e5b"; - } - - @Override - protected boolean useSsl() { - return true; - } - - @Override - protected String getLdapSuffix() { - return "DC=win,DC=evolveum,DC=com"; - } - - @Override - protected String getLdapBindDn() { - return "CN=midpoint admin1,CN=Users,DC=win,DC=evolveum,DC=com"; - } - - @Override - protected String getLdapBindPassword() { - return "mAZadlo911"; - } - - @Override - protected int getSearchSizeLimit() { - return -1; - } - - @Override - public String getPrimaryIdentifierAttributeName() { - return "objectGUID"; - } - - @Override - protected String getPeopleLdapSuffix() { - return "CN=Users," + getLdapSuffix(); - } - - @Override - protected String getGroupsLdapSuffix() { - return "CN=Users," + getLdapSuffix(); - } - - @Override - protected String getLdapAccountObjectClass() { - return "user"; - } - - @Override - protected String getLdapGroupObjectClass() { - return "group"; - } - - @Override - protected String getLdapGroupMemberAttribute() { - return "member"; - } - - private QName getAssociationGroupQName() { - return new QName(MidPointConstants.NS_RI, ASSOCIATION_GROUP_NAME); - } - - @Override - protected boolean allowDuplicateSearchResults() { - return allowDuplicateSearchResults; - } - - @Override - protected File getSyncTaskInetOrgPersonFile() { - return new File(getBaseDir(), "task-sync-user.xml"); - } - - @Override - protected boolean isGroupMemberMandatory() { - return false; - } - - protected String getLdapConnectorClassName() { - return AdTestMixin.AD_CONNECTOR_TYPE; - } - - @Override - public void initSystem(Task initTask, OperationResult initResult) throws Exception { - super.initSystem(initTask, initResult); - - binaryAttributeDetector.addBinaryAttribute(ATTRIBUTE_OBJECT_GUID_NAME); - binaryAttributeDetector.addBinaryAttribute(ATTRIBUTE_UNICODE_PWD_NAME); - - // Users - repoAddObjectFromFile(USER_BARBOSSA_FILE, initResult); - repoAddObjectFromFile(USER_GUYBRUSH_FILE, initResult); - - // Roles - repoAddObjectFromFile(ROLE_PIRATES_FILE, initResult); - repoAddObjectFromFile(ROLE_META_ORG_FILE, initResult); - - } - - @Test - @Override - public void test000Sanity() throws Exception { - super.test000Sanity(); - - assertLdapPasswordByFullName(ACCOUNT_JACK_FULL_NAME, ACCOUNT_JACK_PASSWORD); - cleanupDelete(toAccountDn(USER_BARBOSSA_USERNAME, USER_BARBOSSA_FULL_NAME)); - cleanupDelete(toAccountDn(USER_CPTBARBOSSA_USERNAME, USER_CPTBARBOSSA_FULL_NAME)); - cleanupDelete(toAccountDn(USER_GUYBRUSH_USERNAME, USER_GUYBRUSH_FULL_NAME)); - cleanupDelete(toGroupDn(GROUP_MELEE_ISLAND_NAME)); - cleanupDelete(toGroupDn(GROUP_FOOLS_CN)); - } - - @Test - @Override - public void test020Schema() throws Exception { - accountObjectClassDefinition = assertAdResourceSchema(resource, getAccountObjectClass(), prismContext); - - assertLdapConnectorInstances(1); - } - - // test050 in subclasses - - @Test - public void test100SeachJackBySamAccountName() throws Exception { - // GIVEN - Task task = getTestTask(); - OperationResult result = task.getResult(); - - ObjectQuery query = createSamAccountNameQuery(ACCOUNT_JACK_SAM_ACCOUNT_NAME); - - rememberCounter(InternalCounters.CONNECTOR_OPERATION_COUNT); - rememberCounter(InternalCounters.CONNECTOR_SIMULATED_PAGING_SEARCH_COUNT); - - // WHEN - when(); - SearchResultList> shadows = modelService.searchObjects(ShadowType.class, query, null, task, result); - - // THEN - result.computeStatus(); - TestUtil.assertSuccess(result); - - assertEquals("Unexpected search result: " + shadows, 1, shadows.size()); - - PrismObject shadow = shadows.get(0); - display("Shadow", shadow); - assertAccountShadow(shadow, toAccountDn(ACCOUNT_JACK_SAM_ACCOUNT_NAME, ACCOUNT_JACK_FULL_NAME)); - jackAccountOid = shadow.getOid(); - - assertCounterIncrement(InternalCounters.CONNECTOR_OPERATION_COUNT, 2); - assertCounterIncrement(InternalCounters.CONNECTOR_SIMULATED_PAGING_SEARCH_COUNT, 0); - - SearchResultMetadata metadata = shadows.getMetadata(); - if (metadata != null) { - assertFalse(metadata.isPartialResults()); - } - - assertLdapConnectorInstances(1); - } - - @Test - public void test105SeachPiratesByCn() throws Exception { - // GIVEN - Task task = getTestTask(); - OperationResult result = task.getResult(); - - ObjectQuery query = ObjectQueryUtil.createResourceAndObjectClassQuery(getResourceOid(), getGroupObjectClass(), prismContext); - ObjectQueryUtil.filterAnd(query.getFilter(), createAttributeFilter("cn", GROUP_PIRATES_NAME), prismContext); - - rememberCounter(InternalCounters.CONNECTOR_OPERATION_COUNT); - rememberCounter(InternalCounters.CONNECTOR_SIMULATED_PAGING_SEARCH_COUNT); - - // WHEN - when(); - SearchResultList> shadows = modelService.searchObjects(ShadowType.class, query, null, task, result); - - // THEN - result.computeStatus(); - TestUtil.assertSuccess(result); - - assertEquals("Unexpected search result: " + shadows, 1, shadows.size()); - - PrismObject shadow = shadows.get(0); - display("Shadow", shadow); - groupPiratesOid = shadow.getOid(); - - assertCounterIncrement(InternalCounters.CONNECTOR_OPERATION_COUNT, 1); - assertCounterIncrement(InternalCounters.CONNECTOR_SIMULATED_PAGING_SEARCH_COUNT, 0); - - SearchResultMetadata metadata = shadows.getMetadata(); - if (metadata != null) { - assertFalse(metadata.isPartialResults()); - } - - assertLdapConnectorInstances(1); - } - - @Test - public void test110GetJack() throws Exception { - // GIVEN - Task task = getTestTask(); - OperationResult result = task.getResult(); - - rememberCounter(InternalCounters.CONNECTOR_OPERATION_COUNT); - rememberCounter(InternalCounters.CONNECTOR_SIMULATED_PAGING_SEARCH_COUNT); - - // WHEN - when(); - PrismObject shadow = modelService.getObject(ShadowType.class, jackAccountOid, null, task, result); - - // THEN - result.computeStatus(); - TestUtil.assertSuccess(result); - display("Shadow", shadow); - assertAccountShadow(shadow, toAccountDn(ACCOUNT_JACK_SAM_ACCOUNT_NAME, ACCOUNT_JACK_FULL_NAME)); - jackAccountOid = shadow.getOid(); - - IntegrationTestTools.assertAssociation(shadow, getAssociationGroupQName(), groupPiratesOid); - - assertAttribute(shadow, "dn", "CN=Jack Sparrow,CN=Users,DC=win,DC=evolveum,DC=com"); - assertAttribute(shadow, "cn", ACCOUNT_JACK_FULL_NAME); - assertAttribute(shadow, "sn", "Sparrow"); - assertAttribute(shadow, "info", "The best pirate the world has ever seen"); - assertAttribute(shadow, "sAMAccountName", ACCOUNT_JACK_SAM_ACCOUNT_NAME); - assertAttribute(shadow, "lastLogon", 0L); - - assertCounterIncrement(InternalCounters.CONNECTOR_OPERATION_COUNT, 1); - assertCounterIncrement(InternalCounters.CONNECTOR_SIMULATED_PAGING_SEARCH_COUNT, 0); - - assertLdapConnectorInstances(1); - } - - /** - * No paging. It should return all accounts. - */ - @Test - public void test150SeachAllAccounts() throws Exception { - // GIVEN - Task task = getTestTask(); - OperationResult result = task.getResult(); - - ObjectQuery query = ObjectQueryUtil.createResourceAndObjectClassQuery(getResourceOid(), getAccountObjectClass(), prismContext); - - rememberCounter(InternalCounters.CONNECTOR_OPERATION_COUNT); - rememberCounter(InternalCounters.CONNECTOR_SIMULATED_PAGING_SEARCH_COUNT); - - // WHEN - SearchResultList> searchResultList = doSearch(query, - NUMBER_OF_ACCOUNTS, task, result); - - // TODO: why 11? should be 1 - assertCounterIncrement(InternalCounters.CONNECTOR_OPERATION_COUNT, 9); - assertCounterIncrement(InternalCounters.CONNECTOR_SIMULATED_PAGING_SEARCH_COUNT, 0); - - SearchResultMetadata metadata = searchResultList.getMetadata(); - if (metadata != null) { - assertFalse(metadata.isPartialResults()); - } - - assertLdapConnectorInstances(2); - } - - /** - * Blocksize is 5, so this is in one block. - */ - @Test - public void test152SeachFirst2Accounts() throws Exception { - // GIVEN - Task task = getTestTask(); - OperationResult result = task.getResult(); - - ObjectQuery query = ObjectQueryUtil.createResourceAndObjectClassQuery(getResourceOid(), getAccountObjectClass(), prismContext); - - ObjectPaging paging = prismContext.queryFactory().createPaging(); - paging.setMaxSize(2); - query.setPaging(paging); - - SearchResultList> searchResultList = doSearch(query, 2, task, result); - - assertCounterIncrement(InternalCounters.CONNECTOR_OPERATION_COUNT, 1); - assertCounterIncrement(InternalCounters.CONNECTOR_SIMULATED_PAGING_SEARCH_COUNT, 0); - - SearchResultMetadata metadata = searchResultList.getMetadata(); - if (metadata != null) { - assertFalse(metadata.isPartialResults()); - } - - assertLdapConnectorInstances(2); - } - - /** - * Blocksize is 5, so this gets more than two blocks. - */ - @Test - public void test154SeachFirst11Accounts() throws Exception { - // GIVEN - Task task = getTestTask(); - OperationResult result = task.getResult(); - - ObjectQuery query = ObjectQueryUtil.createResourceAndObjectClassQuery(getResourceOid(), getAccountObjectClass(), prismContext); - - ObjectPaging paging = prismContext.queryFactory().createPaging(); - paging.setMaxSize(11); - query.setPaging(paging); - - SearchResultList> searchResultList = doSearch(query, 11, task, result); - - assertCounterIncrement(InternalCounters.CONNECTOR_OPERATION_COUNT, 1); - assertCounterIncrement(InternalCounters.CONNECTOR_SIMULATED_PAGING_SEARCH_COUNT, 0); - - SearchResultMetadata metadata = searchResultList.getMetadata(); - if (metadata != null) { - assertFalse(metadata.isPartialResults()); - } - - assertLdapConnectorInstances(2); - } - - @Test - public void test162SeachFirst2AccountsOffset0() throws Exception { - // GIVEN - Task task = getTestTask(); - OperationResult result = task.getResult(); - - ObjectQuery query = ObjectQueryUtil.createResourceAndObjectClassQuery(getResourceOid(), getAccountObjectClass(), prismContext); - - ObjectPaging paging = prismContext.queryFactory().createPaging(); - paging.setOffset(0); - paging.setMaxSize(2); - query.setPaging(paging); - - SearchResultList> searchResultList = doSearch(query, 2, task, result); - - assertCounterIncrement(InternalCounters.CONNECTOR_OPERATION_COUNT, 1); - assertCounterIncrement(InternalCounters.CONNECTOR_SIMULATED_PAGING_SEARCH_COUNT, 0); - - SearchResultMetadata metadata = searchResultList.getMetadata(); - if (metadata != null) { - assertFalse(metadata.isPartialResults()); - } - - assertLdapConnectorInstances(2); - } - - /** - * Blocksize is 5, so this is in one block. - * There is offset, so VLV should be used. - * No explicit sorting. - */ - @Test - public void test172Search2AccountsOffset1() throws Exception { - // GIVEN - Task task = getTestTask(); - OperationResult result = task.getResult(); - - ObjectQuery query = ObjectQueryUtil.createResourceAndObjectClassQuery(getResourceOid(), getAccountObjectClass(), prismContext); - - ObjectPaging paging = prismContext.queryFactory().createPaging(1, 2); - query.setPaging(paging); - - SearchResultList> searchResultList = doSearch(query, 2, task, result); - - assertCounterIncrement(InternalCounters.CONNECTOR_OPERATION_COUNT, 1); - assertCounterIncrement(InternalCounters.CONNECTOR_SIMULATED_PAGING_SEARCH_COUNT, 0); - - SearchResultMetadata metadata = searchResultList.getMetadata(); - if (metadata != null) { - assertFalse(metadata.isPartialResults()); - } - - assertLdapConnectorInstances(2); - } - - /** - * Blocksize is 5, so this gets more than two blocks. - * There is offset, so VLV should be used. - * No explicit sorting. - */ - @Test - public void test174SeachFirst11AccountsOffset2() throws Exception { - // GIVEN - Task task = getTestTask(); - OperationResult result = task.getResult(); - - ObjectQuery query = ObjectQueryUtil.createResourceAndObjectClassQuery(getResourceOid(), getAccountObjectClass(), prismContext); - - ObjectPaging paging = prismContext.queryFactory().createPaging(2, 11); - query.setPaging(paging); - - allowDuplicateSearchResults = true; - - // WHEN - SearchResultList> searchResultList = doSearch(query, 11, task, result); - - // THEN - allowDuplicateSearchResults = false; - - assertCounterIncrement(InternalCounters.CONNECTOR_OPERATION_COUNT, 1); - assertCounterIncrement(InternalCounters.CONNECTOR_SIMULATED_PAGING_SEARCH_COUNT, 0); - - SearchResultMetadata metadata = searchResultList.getMetadata(); - if (metadata != null) { - assertFalse(metadata.isPartialResults()); - } - - assertLdapConnectorInstances(2); - } - - /** - * Blocksize is 5, so this is in one block. - * There is offset, so VLV should be used. - * Explicit sorting. - */ - @Test - public void test182Search2AccountsOffset1SortCn() throws Exception { - // GIVEN - Task task = getTestTask(); - OperationResult result = task.getResult(); - - ObjectQuery query = ObjectQueryUtil.createResourceAndObjectClassQuery(getResourceOid(), getAccountObjectClass(), prismContext); - - ObjectPaging paging = prismContext.queryFactory().createPaging(1, 2); - paging.setOrdering(getAttributePath(resource, "cn"), OrderDirection.ASCENDING); - query.setPaging(paging); - - SearchResultList> shadows = doSearch(query, 2, task, result); - - assertAccountShadow(shadows.get(0), "CN=Administrator,CN=Users,DC=win,DC=evolveum,DC=com"); - assertAccountShadow(shadows.get(1), "CN=Chuck LeChuck,CN=Users,DC=win,DC=evolveum,DC=com"); - - assertCounterIncrement(InternalCounters.CONNECTOR_OPERATION_COUNT, 1); - assertCounterIncrement(InternalCounters.CONNECTOR_SIMULATED_PAGING_SEARCH_COUNT, 0); - - SearchResultMetadata metadata = shadows.getMetadata(); - if (metadata != null) { - assertFalse(metadata.isPartialResults()); - } - - assertLdapConnectorInstances(2); - } - - @Test - public void test200AssignAccountBarbossa() throws Exception { - // GIVEN - Task task = getTestTask(); - OperationResult result = task.getResult(); - long tsStart = System.currentTimeMillis(); - - // WHEN - when(); - assignAccountToUser(USER_BARBOSSA_OID, getResourceOid(), null, task, result); - - // THEN - then(); - assertSuccess(result); - - long tsEnd = System.currentTimeMillis(); - - Entry entry = assertLdapAccount(USER_BARBOSSA_USERNAME, USER_BARBOSSA_FULL_NAME); - assertAttribute(entry, "title", null); - - PrismObject user = getUser(USER_BARBOSSA_OID); - String shadowOid = getSingleLinkOid(user); - PrismObject shadow = getShadowModel(shadowOid); - display("Shadow (model)", shadow); - accountBarbossaOid = shadow.getOid(); - Collection> identifiers = ShadowUtil.getPrimaryIdentifiers(shadow); - String accountBarbossaIcfUid = (String) identifiers.iterator().next().getRealValue(); - assertNotNull("No identifier in " + shadow, accountBarbossaIcfUid); - - assertEquals("Wrong ICFS UID", - formatGuidToDashedNotation(MiscUtil.binaryToHex(entry.get(getPrimaryIdentifierAttributeName()).getBytes())), - accountBarbossaIcfUid); - - assertLdapPasswordByFullName(USER_BARBOSSA_FULL_NAME, USER_BARBOSSA_PASSWORD); - - assertAttribute(entry, ATTRIBUTE_USER_ACCOUNT_CONTROL_NAME, "512"); - - ResourceAttribute createTimestampAttribute = ShadowUtil.getAttribute(shadow, new QName(MidPointConstants.NS_RI, "createTimeStamp")); - assertNotNull("No createTimestamp in " + shadow, createTimestampAttribute); - XMLGregorianCalendar createTimestamp = createTimestampAttribute.getRealValue(); - // LDAP server may be on a different host. Allow for some clock offset. - TestUtil.assertBetween("Wrong createTimestamp in " + shadow, roundTsDown(tsStart) - 120000, roundTsUp(tsEnd) + 120000, XmlTypeConverter.toMillis(createTimestamp)); - - assertLdapConnectorInstances(2); - } - - @Test - public void test210ModifyAccountBarbossaTitle() throws Exception { - // GIVEN - Task task = getTestTask(); - OperationResult result = task.getResult(); - - ObjectDelta delta = prismContext.deltaFactory().object() - .createEmptyModifyDelta(ShadowType.class, accountBarbossaOid); - QName attrQName = new QName(MidPointConstants.NS_RI, "title"); - ResourceAttributeDefinition attrDef = accountObjectClassDefinition.findAttributeDefinition(attrQName); - PropertyDelta attrDelta = prismContext.deltaFactory().property().createModificationReplaceProperty( - ItemPath.create(ShadowType.F_ATTRIBUTES, attrQName), attrDef, "Captain"); - delta.addModification(attrDelta); - - // WHEN - when(); - modelService.executeChanges(MiscSchemaUtil.createCollection(delta), null, task, result); - - // THEN - then(); - result.computeStatus(); - TestUtil.assertSuccess(result); - - Entry entry = assertLdapAccount(USER_BARBOSSA_USERNAME, USER_BARBOSSA_FULL_NAME); - assertAttribute(entry, "title", "Captain"); - assertAttribute(entry, ATTRIBUTE_USER_ACCOUNT_CONTROL_NAME, "512"); - - PrismObject user = getUser(USER_BARBOSSA_OID); - String shadowOid = getSingleLinkOid(user); - assertEquals("Shadows have moved", accountBarbossaOid, shadowOid); - - assertLdapConnectorInstances(2); - } - - @Test - public void test212ModifyAccountBarbossaShowInAdvancedViewOnlyTrue() throws Exception { - // GIVEN - Task task = getTestTask(); - OperationResult result = task.getResult(); - - ObjectDelta delta = prismContext.deltaFactory().object() - .createEmptyModifyDelta(ShadowType.class, accountBarbossaOid); - QName attrQName = new QName(MidPointConstants.NS_RI, "showInAdvancedViewOnly"); - ResourceAttributeDefinition attrDef = accountObjectClassDefinition.findAttributeDefinition(attrQName); - PropertyDelta attrDelta = prismContext.deltaFactory().property().createModificationReplaceProperty( - ItemPath.create(ShadowType.F_ATTRIBUTES, attrQName), attrDef, Boolean.TRUE); - delta.addModification(attrDelta); - - // WHEN - when(); - modelService.executeChanges(MiscSchemaUtil.createCollection(delta), null, task, result); - - // THEN - then(); - result.computeStatus(); - TestUtil.assertSuccess(result); - - Entry entry = assertLdapAccount(USER_BARBOSSA_USERNAME, USER_BARBOSSA_FULL_NAME); - assertAttribute(entry, "showInAdvancedViewOnly", "TRUE"); - assertAttribute(entry, ATTRIBUTE_USER_ACCOUNT_CONTROL_NAME, "512"); - - PrismObject user = getUser(USER_BARBOSSA_OID); - String shadowOid = getSingleLinkOid(user); - assertEquals("Shadows have moved", accountBarbossaOid, shadowOid); - - assertLdapConnectorInstances(2); - } - - /** - * Modify USER, test boolean value mapping. - */ - @Test - public void test213ModifyUserBarbossaShowInAdvancedViewOnlyFalse() throws Exception { - // GIVEN - Task task = getTestTask(); - OperationResult result = task.getResult(); - - ObjectDelta delta = prismContext.deltaFactory().object() - .createEmptyModifyDelta(ShadowType.class, accountBarbossaOid); - QName attrQName = new QName(MidPointConstants.NS_RI, "showInAdvancedViewOnly"); - ResourceAttributeDefinition attrDef = accountObjectClassDefinition.findAttributeDefinition(attrQName); - PropertyDelta attrDelta = prismContext.deltaFactory().property().createModificationReplaceProperty( - ItemPath.create(ShadowType.F_ATTRIBUTES, attrQName), attrDef, Boolean.TRUE); - delta.addModification(attrDelta); - - // WHEN - when(); - modifyUserReplace(USER_BARBOSSA_OID, ItemPath.create(UserType.F_EXTENSION, EXTENSION_SHOW_IN_ADVANCED_VIEW_ONLY_QNAME), - task, result, Boolean.FALSE); - - // THEN - then(); - assertSuccess(result); - - Entry entry = assertLdapAccount(USER_BARBOSSA_USERNAME, USER_BARBOSSA_FULL_NAME); - assertAttribute(entry, "showInAdvancedViewOnly", "FALSE"); - assertAttribute(entry, ATTRIBUTE_USER_ACCOUNT_CONTROL_NAME, "512"); - - PrismObject user = getUser(USER_BARBOSSA_OID); - String shadowOid = getSingleLinkOid(user); - assertEquals("Shadows have moved", accountBarbossaOid, shadowOid); - - assertLdapConnectorInstances(2); - } - - @Test - public void test220ModifyUserBarbossaPassword() throws Exception { - // GIVEN - Task task = getTestTask(); - OperationResult result = task.getResult(); - - ProtectedStringType userPasswordPs = new ProtectedStringType(); - userPasswordPs.setClearValue(USER_BARBOSSA_PASSWORD_2); - - // WHEN - when(); - modifyUserReplace(USER_BARBOSSA_OID, PATH_CREDENTIALS_PASSWORD_VALUE, task, result, userPasswordPs); - - // THEN - then(); - assertSuccess(result); - - Entry entry = assertLdapAccount(USER_BARBOSSA_USERNAME, USER_BARBOSSA_FULL_NAME); - assertAttribute(entry, "title", "Captain"); - assertLdapPasswordByFullName(USER_BARBOSSA_FULL_NAME, USER_BARBOSSA_PASSWORD_2); - assertAttribute(entry, ATTRIBUTE_USER_ACCOUNT_CONTROL_NAME, "512"); - - PrismObject user = getUser(USER_BARBOSSA_OID); - String shadowOid = getSingleLinkOid(user); - assertEquals("Shadows have moved", accountBarbossaOid, shadowOid); - - assertLdapConnectorInstances(2); - } - - /** - * MID-5242 - */ - @Test - public void test222ModifyUserBarbossaPasswordNational() throws Exception { - // GIVEN - Task task = getTestTask(); - OperationResult result = task.getResult(); - - ProtectedStringType userPasswordPs = new ProtectedStringType(); - userPasswordPs.setClearValue(USER_BARBOSSA_PASSWORD_AD_1); - - // WHEN - when(); - modifyUserReplace(USER_BARBOSSA_OID, PATH_CREDENTIALS_PASSWORD_VALUE, task, result, userPasswordPs); - - // THEN - then(); - assertSuccess(result); - - Entry entry = assertLdapAccount(USER_BARBOSSA_USERNAME, USER_BARBOSSA_FULL_NAME); - assertAttribute(entry, "title", "Captain"); - assertLdapPasswordByFullName(USER_BARBOSSA_FULL_NAME, USER_BARBOSSA_PASSWORD_AD_1); - assertAttribute(entry, ATTRIBUTE_USER_ACCOUNT_CONTROL_NAME, "512"); - - PrismObject user = getUser(USER_BARBOSSA_OID); - String shadowOid = getSingleLinkOid(user); - assertEquals("Shadows have moved", accountBarbossaOid, shadowOid); - - assertLdapConnectorInstances(2); - } - - @Test - public void test230DisableUserBarbossa() throws Exception { - // GIVEN - Task task = getTestTask(); - OperationResult result = task.getResult(); - - // precondition - assertLdapPasswordByFullName(USER_BARBOSSA_FULL_NAME, USER_BARBOSSA_PASSWORD_AD_1); - - // WHEN - when(); - modifyUserReplace(USER_BARBOSSA_OID, PATH_ACTIVATION_ADMINISTRATIVE_STATUS, task, result, ActivationStatusType.DISABLED); - - // THEN - then(); - assertSuccess(result); - - assertLdapConnectorInstances(2); - - PrismObject user = getUser(USER_BARBOSSA_OID); - assertAdministrativeStatus(user, ActivationStatusType.DISABLED); - - Entry entry = assertLdapAccount(USER_BARBOSSA_USERNAME, USER_BARBOSSA_FULL_NAME); - assertAttribute(entry, ATTRIBUTE_USER_ACCOUNT_CONTROL_NAME, "514"); - - String shadowOid = getSingleLinkOid(user); - PrismObject shadow = getObject(ShadowType.class, shadowOid); - assertAccountDisabled(shadow); - - try { - assertLdapPasswordByFullName(USER_BARBOSSA_FULL_NAME, USER_BARBOSSA_PASSWORD_AD_1); - AssertJUnit.fail("Password authentication works, but it should fail"); - } catch (SecurityException e) { - // this is expected - } - - assertLdapConnectorInstances(2); - } - - @Test - public void test239EnableUserBarbossa() throws Exception { - // GIVEN - Task task = getTestTask(); - OperationResult result = task.getResult(); - - // WHEN - when(); - modifyUserReplace(USER_BARBOSSA_OID, PATH_ACTIVATION_ADMINISTRATIVE_STATUS, task, result, ActivationStatusType.ENABLED); - - // THEN - then(); - assertSuccess(result); - - PrismObject user = getUser(USER_BARBOSSA_OID); - assertAdministrativeStatus(user, ActivationStatusType.ENABLED); - - Entry entry = assertLdapAccount(USER_BARBOSSA_USERNAME, USER_BARBOSSA_FULL_NAME); - assertAttribute(entry, ATTRIBUTE_USER_ACCOUNT_CONTROL_NAME, "512"); - - String shadowOid = getSingleLinkOid(user); - PrismObject shadow = getObject(ShadowType.class, shadowOid); - assertAccountEnabled(shadow); - - assertLdapConnectorInstances(2); - } - - /** - * This should create account with a group. And disabled. - */ - @Test - public void test250AssignGuybrushPirates() throws Exception { - // GIVEN - Task task = getTestTask(); - OperationResult result = task.getResult(); - - modifyUserReplace(USER_GUYBRUSH_OID, PATH_ACTIVATION_ADMINISTRATIVE_STATUS, task, result, ActivationStatusType.DISABLED); - - // WHEN - when(); - assignRole(USER_GUYBRUSH_OID, ROLE_PIRATES_OID, task, result); - - // THEN - then(); - assertSuccess(result); - - Entry entry = assertLdapAccount(USER_GUYBRUSH_USERNAME, USER_GUYBRUSH_FULL_NAME); - display("Entry", entry); - assertAttribute(entry, ATTRIBUTE_USER_ACCOUNT_CONTROL_NAME, "514"); - - assertLdapGroupMember(entry, GROUP_PIRATES_NAME); - - PrismObject user = getUser(USER_GUYBRUSH_OID); - assertAdministrativeStatus(user, ActivationStatusType.DISABLED); - String shadowOid = getSingleLinkOid(user); - - PrismObject shadow = getObject(ShadowType.class, shadowOid); - IntegrationTestTools.assertAssociation(shadow, getAssociationGroupQName(), groupPiratesOid); - assertAccountDisabled(shadow); - - assertLdapConnectorInstances(2); - } - - @Test - public void test255ModifyUserGuybrushPassword() throws Exception { - // GIVEN - Task task = getTestTask(); - OperationResult result = task.getResult(); - - ProtectedStringType userPasswordPs = new ProtectedStringType(); - userPasswordPs.setClearValue("wanna.be.a.123"); - - // WHEN - when(); - modifyUserReplace(USER_GUYBRUSH_OID, PATH_CREDENTIALS_PASSWORD_VALUE, task, result, userPasswordPs); - - // THEN - then(); - result.computeStatus(); - TestUtil.assertSuccess(result); - - Entry entry = assertLdapAccount(USER_GUYBRUSH_USERNAME, USER_GUYBRUSH_FULL_NAME); - assertAttribute(entry, ATTRIBUTE_USER_ACCOUNT_CONTROL_NAME, "514"); - - try { - assertLdapPasswordByFullName(USER_GUYBRUSH_FULL_NAME, "wanna.be.a.123"); - AssertJUnit.fail("Password authentication works, but it should fail"); - } catch (SecurityException e) { - // this is expected, account is disabled - } - - assertLdapConnectorInstances(2); - } - - @Test - public void test260EnableGyubrush() throws Exception { - // GIVEN - Task task = getTestTask(); - OperationResult result = task.getResult(); - - // WHEN - when(); - modifyUserReplace(USER_GUYBRUSH_OID, PATH_ACTIVATION_ADMINISTRATIVE_STATUS, task, result, ActivationStatusType.ENABLED); - - // THEN - then(); - result.computeStatus(); - TestUtil.assertSuccess(result); - - PrismObject user = getUser(USER_GUYBRUSH_OID); - assertAdministrativeStatus(user, ActivationStatusType.ENABLED); - - Entry entry = assertLdapAccount(USER_GUYBRUSH_USERNAME, USER_GUYBRUSH_FULL_NAME); - assertAttribute(entry, ATTRIBUTE_USER_ACCOUNT_CONTROL_NAME, "512"); - - String shadowOid = getSingleLinkOid(user); - PrismObject shadow = getObject(ShadowType.class, shadowOid); - assertAccountEnabled(shadow); - - assertLdapPasswordByFullName(USER_GUYBRUSH_FULL_NAME, "wanna.be.a.123"); - - assertLdapConnectorInstances(2); - } - - @Test - public void test300AssignBarbossaPirates() throws Exception { - // GIVEN - Task task = getTestTask(); - OperationResult result = task.getResult(); - - // WHEN - when(); - assignRole(USER_BARBOSSA_OID, ROLE_PIRATES_OID, task, result); - - // THEN - then(); - result.computeStatus(); - TestUtil.assertSuccess(result); - - Entry entry = assertLdapAccount(USER_BARBOSSA_USERNAME, USER_BARBOSSA_FULL_NAME); - display("Entry", entry); - assertAttribute(entry, "title", "Captain"); - - assertLdapGroupMember(entry, GROUP_PIRATES_NAME); - - PrismObject user = getUser(USER_BARBOSSA_OID); - String shadowOid = getSingleLinkOid(user); - assertEquals("Shadows have moved", accountBarbossaOid, shadowOid); - - PrismObject shadow = getObject(ShadowType.class, shadowOid); - IntegrationTestTools.assertAssociation(shadow, getAssociationGroupQName(), groupPiratesOid); - - assertLdapConnectorInstances(2); - } - - @Test - public void test390ModifyUserBarbossaRename() throws Exception { - // GIVEN - Task task = getTestTask(); - OperationResult result = task.getResult(); - - ObjectDelta objectDelta = createModifyUserReplaceDelta(USER_BARBOSSA_OID, UserType.F_NAME, - PrismTestUtil.createPolyString(USER_CPTBARBOSSA_USERNAME)); - objectDelta.addModificationReplaceProperty(UserType.F_FULL_NAME, - PrismTestUtil.createPolyString(USER_CPTBARBOSSA_FULL_NAME)); - Collection> deltas = MiscSchemaUtil.createCollection(objectDelta); - - // WHEN - when(); - modelService.executeChanges(deltas, null, task, result); - - // THEN - then(); - result.computeStatus(); - TestUtil.assertSuccess(result); - - Entry entry = assertLdapAccount(USER_CPTBARBOSSA_USERNAME, USER_CPTBARBOSSA_FULL_NAME); - assertAttribute(entry, "title", "Captain"); - - PrismObject user = getUser(USER_BARBOSSA_OID); - String shadowOid = getSingleLinkOid(user); - assertEquals("Shadows have moved", accountBarbossaOid, shadowOid); - PrismObject shadow = getObject(ShadowType.class, shadowOid); - display("Shadow after rename (model)", shadow); - - PrismObject repoShadow = repositoryService.getObject(ShadowType.class, shadowOid, null, result); - display("Shadow after rename (repo)", repoShadow); - - assertNoLdapAccount(USER_BARBOSSA_USERNAME, USER_BARBOSSA_FULL_NAME); - - assertLdapConnectorInstances(2); - } - - // TODO: create account with a group membership - - @Test - public void test395UnAssignBarbossaPirates() throws Exception { - // TODO: do this on another account. There is a bad interference with rename. - - // GIVEN - Task task = getTestTask(); - OperationResult result = task.getResult(); - - // WHEN - when(); - unassignRole(USER_BARBOSSA_OID, ROLE_PIRATES_OID, task, result); - - // THEN - then(); - result.computeStatus(); - TestUtil.assertSuccess(result); - - Entry entry = assertLdapAccount(USER_CPTBARBOSSA_USERNAME, USER_CPTBARBOSSA_FULL_NAME); - display("Entry", entry); - assertAttribute(entry, "title", "Captain"); - - assertLdapNoGroupMember(entry, GROUP_PIRATES_NAME); - - PrismObject user = getUser(USER_BARBOSSA_OID); - String shadowOid = getSingleLinkOid(user); - assertEquals("Shadows have moved", accountBarbossaOid, shadowOid); - - PrismObject shadow = getObject(ShadowType.class, shadowOid); - IntegrationTestTools.assertNoAssociation(shadow, getAssociationGroupQName(), groupPiratesOid); - - assertLdapConnectorInstances(2); - } - - @Test - public void test399UnAssignAccountBarbossa() throws Exception { - // GIVEN - Task task = getTestTask(); - OperationResult result = task.getResult(); - - // WHEN - when(); - unassignAccountFromUser(USER_BARBOSSA_OID, getResourceOid(), null, task, result); - - // THEN - then(); - result.computeStatus(); - TestUtil.assertSuccess(result); - - assertNoLdapAccount(USER_BARBOSSA_USERNAME, USER_BARBOSSA_FULL_NAME); - assertNoLdapAccount(USER_CPTBARBOSSA_USERNAME, USER_CPTBARBOSSA_FULL_NAME); - - PrismObject user = getUser(USER_BARBOSSA_OID); - assertNoLinkedAccount(user); - - assertLdapConnectorInstances(2); - } - - @Test - public void test500AddOrgMeleeIsland() throws Exception { - // GIVEN - Task task = getTestTask(); - OperationResult result = task.getResult(); - - PrismObject org = prismContext.getSchemaRegistry().findObjectDefinitionByCompileTimeClass(OrgType.class).instantiate(); - OrgType orgType = org.asObjectable(); - orgType.setName(new PolyStringType(GROUP_MELEE_ISLAND_NAME)); - AssignmentType metaroleAssignment = new AssignmentType(); - ObjectReferenceType metaroleRef = new ObjectReferenceType(); - metaroleRef.setOid(ROLE_META_ORG_OID); - metaroleRef.setType(RoleType.COMPLEX_TYPE); - metaroleAssignment.setTargetRef(metaroleRef); - orgType.getAssignment().add(metaroleAssignment); - - // WHEN - when(); - addObject(org, task, result); - - // THEN - then(); - result.computeStatus(); - TestUtil.assertSuccess(result); - - orgMeleeIslandOid = org.getOid(); - assertLdapGroup(GROUP_MELEE_ISLAND_NAME); - - org = getObject(OrgType.class, orgMeleeIslandOid); - groupMeleeOid = getSingleLinkOid(org); - PrismObject shadow = getShadowModel(groupMeleeOid); - display("Shadow (model)", shadow); - - assertLdapConnectorInstances(2); - } - - @Test - public void test510AssignGuybrushMeleeIsland() throws Exception { - // GIVEN - Task task = getTestTask(); - OperationResult result = task.getResult(); - - // WHEN - when(); - assignOrg(USER_GUYBRUSH_OID, orgMeleeIslandOid, task, result); - - // THEN - then(); - assertSuccess(result); - - Entry entry = assertLdapAccount(USER_GUYBRUSH_USERNAME, USER_GUYBRUSH_FULL_NAME); - - PrismObject user = getUser(USER_GUYBRUSH_OID); - String shadowOid = getSingleLinkOid(user); - PrismObject shadow = getShadowModel(shadowOid); - display("Shadow (model)", shadow); - - assertLdapGroupMember(entry, GROUP_MELEE_ISLAND_NAME); - - IntegrationTestTools.assertAssociation(shadow, getAssociationGroupQName(), groupMeleeOid); - - assertLdapConnectorInstances(2); - } - - @Override - protected void doAdditionalRenameModifications(LdapNetworkConnection connection) throws LdapException { - Modification mod = new DefaultModification(ModificationOperation.REPLACE_ATTRIBUTE, - ATTRIBUTE_SAM_ACCOUNT_NAME_NAME, ACCOUNT_HTM_UID); - connection.modify(toAccountDn(ACCOUNT_HTM_UID, ACCOUNT_HTM_CN), mod); - display("Modified " + toAccountDn(ACCOUNT_HT_UID, ACCOUNT_HT_CN) + " " + ATTRIBUTE_SAM_ACCOUNT_NAME_NAME + - " -> " + ACCOUNT_HTM_UID + ": " + mod); - } - - @Override - protected String getAccountHtmCnAfterRename() { - return ACCOUNT_HTM_CN; - } - - @Override - protected void assertAccountShadow(PrismObject shadow, String dn) throws SchemaException { - super.assertAccountShadow(shadow, dn); - ResourceAttribute primaryIdAttr = ShadowUtil.getAttribute(shadow, getPrimaryIdentifierAttributeQName()); - assertNotNull("No primary identifier (" + getPrimaryIdentifierAttributeQName() + " in " + shadow, primaryIdAttr); - String primaryId = primaryIdAttr.getRealValue(); - assertTrue("Unexpected chars in primary ID: '" + primaryId + "'", primaryId.matches("[a-z0-9\\-]+")); - } - - @Override - protected Entry assertLdapAccount(String samAccountName, String cn) throws LdapException, IOException, CursorException { - Entry entry = searchLdapAccount("(cn=" + cn + ")"); - assertAttribute(entry, "cn", cn); - assertAttribute(entry, ATTRIBUTE_SAM_ACCOUNT_NAME_NAME, samAccountName); - return entry; - } - - @Override - protected void assertNoLdapAccount(String uid) { - throw new UnsupportedOperationException("Boom! Cannot do this here. This is bloody AD! We need full name!"); - } - - protected void assertNoLdapAccount(String uid, String cn) throws LdapException, IOException, CursorException { - LdapNetworkConnection connection = ldapConnect(); - List entriesCn = ldapSearch(connection, "(cn=" + cn + ")"); - List entriesSamAccountName = ldapSearch(connection, "(sAMAccountName=" + uid + ")"); - ldapDisconnect(connection); - - assertEquals("Unexpected number of entries for cn=" + cn + ": " + entriesCn, 0, entriesCn.size()); - assertEquals("Unexpected number of entries for sAMAccountName=" + uid + ": " + entriesSamAccountName, 0, entriesSamAccountName.size()); - } - - @Override - protected String toAccountDn(String username) { - throw new UnsupportedOperationException("Boom! Cannot do this here. This is bloody AD! We need full name!"); - } - - @Override - protected String toAccountDn(String username, String fullName) { - return "CN=" + fullName + "," + getPeopleLdapSuffix(); - } - - @Override - protected Rdn toAccountRdn(String username, String fullName) { - try { - return new Rdn(new Ava("CN", fullName)); - } catch (LdapInvalidDnException e) { - throw new IllegalStateException(e.getMessage(), e); - } - } - - protected void assertLdapPasswordByFullName(String fullName, String password) - throws LdapException, IOException, CursorException { - Entry entry = getLdapAccountByCn(fullName); - assertLdapPassword(entry, password); - } - - protected void assertLdapPassword(String uid, String password) { - throw new UnsupportedOperationException( - "Boom! Cannot do this here. This is bloody AD! We need full name!"); - } - - protected ObjectQuery createSamAccountNameQuery(String samAccountName) throws SchemaException { - ObjectQuery query = ObjectQueryUtil.createResourceAndObjectClassQuery(getResourceOid(), getAccountObjectClass(), prismContext); - ObjectQueryUtil.filterAnd(query.getFilter(), createAttributeFilter(ATTRIBUTE_SAM_ACCOUNT_NAME_NAME, samAccountName), - prismContext); - return query; - } - - @Override - protected Entry createAccountEntry(String uid, String cn, String givenName, String sn) throws LdapException { - byte[] password = encodePassword("Secret.123"); - Entry entry = new DefaultEntry(toAccountDn(uid, cn), - "objectclass", getLdapAccountObjectClass(), - ATTRIBUTE_SAM_ACCOUNT_NAME_NAME, uid, - "cn", cn, - "givenName", givenName, - "sn", sn, - ATTRIBUTE_USER_ACCOUNT_CONTROL_NAME, "512", - ATTRIBUTE_UNICODE_PWD_NAME, password); - return entry; - } - - private byte[] encodePassword(String password) { - String quotedPassword = "\"" + password + "\""; - return quotedPassword.getBytes(StandardCharsets.UTF_16LE); - } - - @Override - protected void assertStepSyncToken(String syncTaskOid, int step, long tsStart, long tsEnd) - throws ObjectNotFoundException, SchemaException { - OperationResult result = createOperationResult("assertStepSyncToken"); - Task task = taskManager.getTaskPlain(syncTaskOid, result); - PrismProperty syncTokenProperty = task.getExtensionPropertyOrClone(SchemaConstants.SYNC_TOKEN); - assertNotNull("No sync token", syncTokenProperty); - assertNotNull("No sync token value", syncTokenProperty.getRealValue()); - assertNotNull("Empty sync token value", StringUtils.isBlank(syncTokenProperty.getRealValue())); - result.computeStatus(); - TestUtil.assertSuccess(result); - } - - public void assertAttribute(PrismObject shadow, String attrName, T... expectedValues) { - assertAttribute(shadow, new QName(getResourceNamespace(), attrName), expectedValues); - } - - public void assertAttribute(PrismObject shadow, QName attrQname, T... expectedValues) { - List actualValues = ShadowUtil.getAttributeValues(shadow, attrQname); - PrismAsserts.assertSets("attribute " + attrQname + " in " + shadow, actualValues, expectedValues); - } - - protected abstract void assertAccountDisabled(PrismObject shadow); - - protected abstract void assertAccountEnabled(PrismObject shadow); -} +/* + * Copyright (c) 2015-2019 Evolveum and contributors + *

+ * This work is dual-licensed under the Apache License 2.0 + * and European Union Public License. See LICENSE file for details. + */ +package com.evolveum.midpoint.testing.conntest.ad; + +import static org.testng.AssertJUnit.*; + +import static com.evolveum.midpoint.schema.constants.SchemaConstants.PATH_ACTIVATION_ADMINISTRATIVE_STATUS; +import static com.evolveum.midpoint.schema.constants.SchemaConstants.PATH_CREDENTIALS_PASSWORD_VALUE; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Collection; +import java.util.List; +import javax.xml.datatype.XMLGregorianCalendar; +import javax.xml.namespace.QName; + +import org.apache.commons.lang.StringUtils; +import org.apache.directory.api.ldap.model.cursor.CursorException; +import org.apache.directory.api.ldap.model.entry.*; +import org.apache.directory.api.ldap.model.exception.LdapException; +import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException; +import org.apache.directory.api.ldap.model.name.Ava; +import org.apache.directory.api.ldap.model.name.Rdn; +import org.apache.directory.ldap.client.api.LdapNetworkConnection; +import org.testng.AssertJUnit; +import org.testng.annotations.Listeners; +import org.testng.annotations.Test; + +import com.evolveum.midpoint.prism.PrismObject; +import com.evolveum.midpoint.prism.PrismProperty; +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.prism.query.ObjectPaging; +import com.evolveum.midpoint.prism.query.ObjectQuery; +import com.evolveum.midpoint.prism.query.OrderDirection; +import com.evolveum.midpoint.prism.util.PrismAsserts; +import com.evolveum.midpoint.prism.util.PrismTestUtil; +import com.evolveum.midpoint.prism.xml.XmlTypeConverter; +import com.evolveum.midpoint.schema.SearchResultList; +import com.evolveum.midpoint.schema.SearchResultMetadata; +import com.evolveum.midpoint.schema.constants.MidPointConstants; +import com.evolveum.midpoint.schema.constants.SchemaConstants; +import com.evolveum.midpoint.schema.internals.InternalCounters; +import com.evolveum.midpoint.schema.processor.ResourceAttribute; +import com.evolveum.midpoint.schema.processor.ResourceAttributeDefinition; +import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.schema.util.MiscSchemaUtil; +import com.evolveum.midpoint.schema.util.ObjectQueryUtil; +import com.evolveum.midpoint.schema.util.ShadowUtil; +import com.evolveum.midpoint.task.api.Task; +import com.evolveum.midpoint.test.IntegrationTestTools; +import com.evolveum.midpoint.test.util.MidPointTestConstants; +import com.evolveum.midpoint.test.util.TestUtil; +import com.evolveum.midpoint.testing.conntest.AbstractLdapSynchronizationTest; +import com.evolveum.midpoint.util.MiscUtil; +import com.evolveum.midpoint.util.exception.ObjectNotFoundException; +import com.evolveum.midpoint.util.exception.SchemaException; +import com.evolveum.midpoint.xml.ns._public.common.common_3.*; +import com.evolveum.prism.xml.ns._public.types_3.PolyStringType; +import com.evolveum.prism.xml.ns._public.types_3.ProtectedStringType; + +/** + * @author semancik + */ +@Listeners({ com.evolveum.midpoint.tools.testng.AlphabeticalMethodInterceptor.class }) +public abstract class AbstractAdLdapTest extends AbstractLdapSynchronizationTest + implements AdTestMixin { + + protected static final File TEST_DIR = new File(MidPointTestConstants.TEST_RESOURCES_DIR, "ad-ldap"); + + protected static final File ROLE_PIRATES_FILE = new File(TEST_DIR, "role-pirate.xml"); + protected static final String ROLE_PIRATES_OID = "5dd034e8-41d2-11e5-a123-001e8c717e5b"; + + protected static final File ROLE_META_ORG_FILE = new File(TEST_DIR, "role-meta-org.xml"); + protected static final String ROLE_META_ORG_OID = "f2ad0ace-45d7-11e5-af54-001e8c717e5b"; + + protected static final String ACCOUNT_JACK_SAM_ACCOUNT_NAME = "jack"; + protected static final String ACCOUNT_JACK_FULL_NAME = "Jack Sparrow"; + protected static final String ACCOUNT_JACK_PASSWORD = "qwe.123"; + + protected static final String USER_CPTBARBOSSA_FULL_NAME = "Captain Hector Barbossa"; + + private static final String GROUP_PIRATES_NAME = "pirates"; + private static final String GROUP_MELEE_ISLAND_NAME = "Mêlée Island"; + + protected static final int NUMBER_OF_ACCOUNTS = 12; + private static final String ASSOCIATION_GROUP_NAME = "group"; + + private static final String NS_EXTENSION = "http://whatever.com/my"; + private static final QName EXTENSION_SHOW_IN_ADVANCED_VIEW_ONLY_QNAME = new QName(NS_EXTENSION, "showInAdvancedViewOnly"); + + private boolean allowDuplicateSearchResults = false; + + protected String jackAccountOid; + protected String groupPiratesOid; + protected String accountBarbossaOid; + protected String orgMeleeIslandOid; + protected String groupMeleeOid; + + @Override + public String getStartSystemCommand() { + return null; + } + + @Override + public String getStopSystemCommand() { + return null; + } + + @Override + protected File getBaseDir() { + return TEST_DIR; + } + + @Override + protected String getSyncTaskOid() { + return "cd1e0ff2-0099-11e5-9e22-001e8c717e5b"; + } + + @Override + protected boolean useSsl() { + return true; + } + + @Override + protected String getLdapSuffix() { + return "DC=win,DC=evolveum,DC=com"; + } + + @Override + protected String getLdapBindDn() { + return "CN=midpoint admin1,CN=Users,DC=win,DC=evolveum,DC=com"; + } + + @Override + protected String getLdapBindPassword() { + return "mAZadlo911"; + } + + @Override + protected int getSearchSizeLimit() { + return -1; + } + + @Override + public String getPrimaryIdentifierAttributeName() { + return "objectGUID"; + } + + @Override + protected String getPeopleLdapSuffix() { + return "CN=Users," + getLdapSuffix(); + } + + @Override + protected String getGroupsLdapSuffix() { + return "CN=Users," + getLdapSuffix(); + } + + @Override + protected String getLdapAccountObjectClass() { + return "user"; + } + + @Override + protected String getLdapGroupObjectClass() { + return "group"; + } + + @Override + protected String getLdapGroupMemberAttribute() { + return "member"; + } + + private QName getAssociationGroupQName() { + return new QName(MidPointConstants.NS_RI, ASSOCIATION_GROUP_NAME); + } + + @Override + protected boolean allowDuplicateSearchResults() { + return allowDuplicateSearchResults; + } + + @Override + protected File getSyncTaskInetOrgPersonFile() { + return new File(getBaseDir(), "task-sync-user.xml"); + } + + @Override + protected boolean isGroupMemberMandatory() { + return false; + } + + protected String getLdapConnectorClassName() { + return AdTestMixin.AD_CONNECTOR_TYPE; + } + + @Override + public void initSystem(Task initTask, OperationResult initResult) throws Exception { + super.initSystem(initTask, initResult); + + binaryAttributeDetector.addBinaryAttribute(ATTRIBUTE_OBJECT_GUID_NAME); + binaryAttributeDetector.addBinaryAttribute(ATTRIBUTE_UNICODE_PWD_NAME); + + // Users + repoAddObjectFromFile(USER_BARBOSSA_FILE, initResult); + repoAddObjectFromFile(USER_GUYBRUSH_FILE, initResult); + + // Roles + repoAddObjectFromFile(ROLE_PIRATES_FILE, initResult); + repoAddObjectFromFile(ROLE_META_ORG_FILE, initResult); + + } + + @Test + @Override + public void test000Sanity() throws Exception { + super.test000Sanity(); + + assertLdapPasswordByFullName(ACCOUNT_JACK_FULL_NAME, ACCOUNT_JACK_PASSWORD); + cleanupDelete(toAccountDn(USER_BARBOSSA_USERNAME, USER_BARBOSSA_FULL_NAME)); + cleanupDelete(toAccountDn(USER_CPTBARBOSSA_USERNAME, USER_CPTBARBOSSA_FULL_NAME)); + cleanupDelete(toAccountDn(USER_GUYBRUSH_USERNAME, USER_GUYBRUSH_FULL_NAME)); + cleanupDelete(toGroupDn(GROUP_MELEE_ISLAND_NAME)); + cleanupDelete(toGroupDn(GROUP_FOOLS_CN)); + } + + @Test + @Override + public void test020Schema() throws Exception { + accountObjectClassDefinition = assertAdResourceSchema(resource, getAccountObjectClass(), prismContext); + + assertLdapConnectorInstances(1); + } + + // test050 in subclasses + + @Test + public void test100SeachJackBySamAccountName() throws Exception { + // GIVEN + Task task = getTestTask(); + OperationResult result = task.getResult(); + + ObjectQuery query = createSamAccountNameQuery(ACCOUNT_JACK_SAM_ACCOUNT_NAME); + + rememberCounter(InternalCounters.CONNECTOR_OPERATION_COUNT); + rememberCounter(InternalCounters.CONNECTOR_SIMULATED_PAGING_SEARCH_COUNT); + + // WHEN + when(); + SearchResultList> shadows = modelService.searchObjects(ShadowType.class, query, null, task, result); + + // THEN + assertSuccess(result); + + assertEquals("Unexpected search result: " + shadows, 1, shadows.size()); + + PrismObject shadow = shadows.get(0); + display("Shadow", shadow); + assertAccountShadow(shadow, toAccountDn(ACCOUNT_JACK_SAM_ACCOUNT_NAME, ACCOUNT_JACK_FULL_NAME)); + jackAccountOid = shadow.getOid(); + + assertCounterIncrement(InternalCounters.CONNECTOR_OPERATION_COUNT, 2); + assertCounterIncrement(InternalCounters.CONNECTOR_SIMULATED_PAGING_SEARCH_COUNT, 0); + + SearchResultMetadata metadata = shadows.getMetadata(); + if (metadata != null) { + assertFalse(metadata.isPartialResults()); + } + + assertLdapConnectorInstances(1); + } + + @Test + public void test105SeachPiratesByCn() throws Exception { + // GIVEN + Task task = getTestTask(); + OperationResult result = task.getResult(); + + ObjectQuery query = ObjectQueryUtil.createResourceAndObjectClassQuery(getResourceOid(), getGroupObjectClass(), prismContext); + ObjectQueryUtil.filterAnd(query.getFilter(), createAttributeFilter("cn", GROUP_PIRATES_NAME), prismContext); + + rememberCounter(InternalCounters.CONNECTOR_OPERATION_COUNT); + rememberCounter(InternalCounters.CONNECTOR_SIMULATED_PAGING_SEARCH_COUNT); + + // WHEN + when(); + SearchResultList> shadows = modelService.searchObjects(ShadowType.class, query, null, task, result); + + // THEN + assertSuccess(result); + + assertEquals("Unexpected search result: " + shadows, 1, shadows.size()); + + PrismObject shadow = shadows.get(0); + display("Shadow", shadow); + groupPiratesOid = shadow.getOid(); + + assertCounterIncrement(InternalCounters.CONNECTOR_OPERATION_COUNT, 1); + assertCounterIncrement(InternalCounters.CONNECTOR_SIMULATED_PAGING_SEARCH_COUNT, 0); + + SearchResultMetadata metadata = shadows.getMetadata(); + if (metadata != null) { + assertFalse(metadata.isPartialResults()); + } + + assertLdapConnectorInstances(1); + } + + @Test + public void test110GetJack() throws Exception { + // GIVEN + Task task = getTestTask(); + OperationResult result = task.getResult(); + + rememberCounter(InternalCounters.CONNECTOR_OPERATION_COUNT); + rememberCounter(InternalCounters.CONNECTOR_SIMULATED_PAGING_SEARCH_COUNT); + + // WHEN + when(); + PrismObject shadow = modelService.getObject(ShadowType.class, jackAccountOid, null, task, result); + + // THEN + assertSuccess(result); + display("Shadow", shadow); + assertAccountShadow(shadow, toAccountDn(ACCOUNT_JACK_SAM_ACCOUNT_NAME, ACCOUNT_JACK_FULL_NAME)); + jackAccountOid = shadow.getOid(); + + IntegrationTestTools.assertAssociation(shadow, getAssociationGroupQName(), groupPiratesOid); + + assertAttribute(shadow, "dn", "CN=Jack Sparrow,CN=Users,DC=win,DC=evolveum,DC=com"); + assertAttribute(shadow, "cn", ACCOUNT_JACK_FULL_NAME); + assertAttribute(shadow, "sn", "Sparrow"); + assertAttribute(shadow, "info", "The best pirate the world has ever seen"); + assertAttribute(shadow, "sAMAccountName", ACCOUNT_JACK_SAM_ACCOUNT_NAME); + assertAttribute(shadow, "lastLogon", 0L); + + assertCounterIncrement(InternalCounters.CONNECTOR_OPERATION_COUNT, 1); + assertCounterIncrement(InternalCounters.CONNECTOR_SIMULATED_PAGING_SEARCH_COUNT, 0); + + assertLdapConnectorInstances(1); + } + + /** + * No paging. It should return all accounts. + */ + @Test + public void test150SeachAllAccounts() throws Exception { + // GIVEN + Task task = getTestTask(); + OperationResult result = task.getResult(); + + ObjectQuery query = ObjectQueryUtil.createResourceAndObjectClassQuery(getResourceOid(), getAccountObjectClass(), prismContext); + + rememberCounter(InternalCounters.CONNECTOR_OPERATION_COUNT); + rememberCounter(InternalCounters.CONNECTOR_SIMULATED_PAGING_SEARCH_COUNT); + + // WHEN + SearchResultList> searchResultList = doSearch(query, + NUMBER_OF_ACCOUNTS, task, result); + + // TODO: why 11? should be 1 + assertCounterIncrement(InternalCounters.CONNECTOR_OPERATION_COUNT, 9); + assertCounterIncrement(InternalCounters.CONNECTOR_SIMULATED_PAGING_SEARCH_COUNT, 0); + + SearchResultMetadata metadata = searchResultList.getMetadata(); + if (metadata != null) { + assertFalse(metadata.isPartialResults()); + } + + assertLdapConnectorInstances(2); + } + + /** + * Blocksize is 5, so this is in one block. + */ + @Test + public void test152SeachFirst2Accounts() throws Exception { + // GIVEN + Task task = getTestTask(); + OperationResult result = task.getResult(); + + ObjectQuery query = ObjectQueryUtil.createResourceAndObjectClassQuery(getResourceOid(), getAccountObjectClass(), prismContext); + + ObjectPaging paging = prismContext.queryFactory().createPaging(); + paging.setMaxSize(2); + query.setPaging(paging); + + SearchResultList> searchResultList = doSearch(query, 2, task, result); + + assertCounterIncrement(InternalCounters.CONNECTOR_OPERATION_COUNT, 1); + assertCounterIncrement(InternalCounters.CONNECTOR_SIMULATED_PAGING_SEARCH_COUNT, 0); + + SearchResultMetadata metadata = searchResultList.getMetadata(); + if (metadata != null) { + assertFalse(metadata.isPartialResults()); + } + + assertLdapConnectorInstances(2); + } + + /** + * Blocksize is 5, so this gets more than two blocks. + */ + @Test + public void test154SeachFirst11Accounts() throws Exception { + // GIVEN + Task task = getTestTask(); + OperationResult result = task.getResult(); + + ObjectQuery query = ObjectQueryUtil.createResourceAndObjectClassQuery(getResourceOid(), getAccountObjectClass(), prismContext); + + ObjectPaging paging = prismContext.queryFactory().createPaging(); + paging.setMaxSize(11); + query.setPaging(paging); + + SearchResultList> searchResultList = doSearch(query, 11, task, result); + + assertCounterIncrement(InternalCounters.CONNECTOR_OPERATION_COUNT, 1); + assertCounterIncrement(InternalCounters.CONNECTOR_SIMULATED_PAGING_SEARCH_COUNT, 0); + + SearchResultMetadata metadata = searchResultList.getMetadata(); + if (metadata != null) { + assertFalse(metadata.isPartialResults()); + } + + assertLdapConnectorInstances(2); + } + + @Test + public void test162SeachFirst2AccountsOffset0() throws Exception { + // GIVEN + Task task = getTestTask(); + OperationResult result = task.getResult(); + + ObjectQuery query = ObjectQueryUtil.createResourceAndObjectClassQuery(getResourceOid(), getAccountObjectClass(), prismContext); + + ObjectPaging paging = prismContext.queryFactory().createPaging(); + paging.setOffset(0); + paging.setMaxSize(2); + query.setPaging(paging); + + SearchResultList> searchResultList = doSearch(query, 2, task, result); + + assertCounterIncrement(InternalCounters.CONNECTOR_OPERATION_COUNT, 1); + assertCounterIncrement(InternalCounters.CONNECTOR_SIMULATED_PAGING_SEARCH_COUNT, 0); + + SearchResultMetadata metadata = searchResultList.getMetadata(); + if (metadata != null) { + assertFalse(metadata.isPartialResults()); + } + + assertLdapConnectorInstances(2); + } + + /** + * Blocksize is 5, so this is in one block. + * There is offset, so VLV should be used. + * No explicit sorting. + */ + @Test + public void test172Search2AccountsOffset1() throws Exception { + // GIVEN + Task task = getTestTask(); + OperationResult result = task.getResult(); + + ObjectQuery query = ObjectQueryUtil.createResourceAndObjectClassQuery(getResourceOid(), getAccountObjectClass(), prismContext); + + ObjectPaging paging = prismContext.queryFactory().createPaging(1, 2); + query.setPaging(paging); + + SearchResultList> searchResultList = doSearch(query, 2, task, result); + + assertCounterIncrement(InternalCounters.CONNECTOR_OPERATION_COUNT, 1); + assertCounterIncrement(InternalCounters.CONNECTOR_SIMULATED_PAGING_SEARCH_COUNT, 0); + + SearchResultMetadata metadata = searchResultList.getMetadata(); + if (metadata != null) { + assertFalse(metadata.isPartialResults()); + } + + assertLdapConnectorInstances(2); + } + + /** + * Blocksize is 5, so this gets more than two blocks. + * There is offset, so VLV should be used. + * No explicit sorting. + */ + @Test + public void test174SeachFirst11AccountsOffset2() throws Exception { + // GIVEN + Task task = getTestTask(); + OperationResult result = task.getResult(); + + ObjectQuery query = ObjectQueryUtil.createResourceAndObjectClassQuery(getResourceOid(), getAccountObjectClass(), prismContext); + + ObjectPaging paging = prismContext.queryFactory().createPaging(2, 11); + query.setPaging(paging); + + allowDuplicateSearchResults = true; + + // WHEN + SearchResultList> searchResultList = doSearch(query, 11, task, result); + + // THEN + allowDuplicateSearchResults = false; + + assertCounterIncrement(InternalCounters.CONNECTOR_OPERATION_COUNT, 1); + assertCounterIncrement(InternalCounters.CONNECTOR_SIMULATED_PAGING_SEARCH_COUNT, 0); + + SearchResultMetadata metadata = searchResultList.getMetadata(); + if (metadata != null) { + assertFalse(metadata.isPartialResults()); + } + + assertLdapConnectorInstances(2); + } + + /** + * Blocksize is 5, so this is in one block. + * There is offset, so VLV should be used. + * Explicit sorting. + */ + @Test + public void test182Search2AccountsOffset1SortCn() throws Exception { + // GIVEN + Task task = getTestTask(); + OperationResult result = task.getResult(); + + ObjectQuery query = ObjectQueryUtil.createResourceAndObjectClassQuery(getResourceOid(), getAccountObjectClass(), prismContext); + + ObjectPaging paging = prismContext.queryFactory().createPaging(1, 2); + paging.setOrdering(getAttributePath(resource, "cn"), OrderDirection.ASCENDING); + query.setPaging(paging); + + SearchResultList> shadows = doSearch(query, 2, task, result); + +// assertAccountShadow(shadows.get(0), "CN=Administrator,CN=Users,DC=win,DC=evolveum,DC=com"); +// assertAccountShadow(shadows.get(1), "CN=Chuck LeChuck,CN=Users,DC=win,DC=evolveum,DC=com"); + + assertAccountShadow(shadows.get(0), "CN=Chuck LeChuck,CN=Users,DC=win,DC=evolveum,DC=com"); + assertAccountShadow(shadows.get(1), "CN=Guest,CN=Users,DC=win,DC=evolveum,DC=com"); + + assertCounterIncrement(InternalCounters.CONNECTOR_OPERATION_COUNT, 1); + assertCounterIncrement(InternalCounters.CONNECTOR_SIMULATED_PAGING_SEARCH_COUNT, 0); + + SearchResultMetadata metadata = shadows.getMetadata(); + if (metadata != null) { + assertFalse(metadata.isPartialResults()); + } + + assertLdapConnectorInstances(2); + } + + @Test + public void test200AssignAccountBarbossa() throws Exception { + // GIVEN + Task task = getTestTask(); + OperationResult result = task.getResult(); + long tsStart = System.currentTimeMillis(); + + // WHEN + when(); + assignAccountToUser(USER_BARBOSSA_OID, getResourceOid(), null, task, result); + + // THEN + then(); + assertSuccess(result); + + long tsEnd = System.currentTimeMillis(); + + Entry entry = assertLdapAccount(USER_BARBOSSA_USERNAME, USER_BARBOSSA_FULL_NAME); + assertAttribute(entry, "title", null); + + PrismObject user = getUser(USER_BARBOSSA_OID); + String shadowOid = getSingleLinkOid(user); + PrismObject shadow = getShadowModel(shadowOid); + display("Shadow (model)", shadow); + accountBarbossaOid = shadow.getOid(); + Collection> identifiers = ShadowUtil.getPrimaryIdentifiers(shadow); + String accountBarbossaIcfUid = (String) identifiers.iterator().next().getRealValue(); + assertNotNull("No identifier in " + shadow, accountBarbossaIcfUid); + + assertEquals("Wrong ICFS UID", + formatGuidToDashedNotation(MiscUtil.binaryToHex(entry.get(getPrimaryIdentifierAttributeName()).getBytes())), + accountBarbossaIcfUid); + + assertLdapPasswordByFullName(USER_BARBOSSA_FULL_NAME, USER_BARBOSSA_PASSWORD); + + assertAttribute(entry, ATTRIBUTE_USER_ACCOUNT_CONTROL_NAME, "512"); + + ResourceAttribute createTimestampAttribute = ShadowUtil.getAttribute(shadow, new QName(MidPointConstants.NS_RI, "createTimeStamp")); + assertNotNull("No createTimestamp in " + shadow, createTimestampAttribute); + XMLGregorianCalendar createTimestamp = createTimestampAttribute.getRealValue(); + // LDAP server may be on a different host. Allow for some clock offset. + TestUtil.assertBetween("Wrong createTimestamp in " + shadow, roundTsDown(tsStart) - 120000, roundTsUp(tsEnd) + 120000, XmlTypeConverter.toMillis(createTimestamp)); + + assertLdapConnectorInstances(2); + } + + @Test + public void test210ModifyAccountBarbossaTitle() throws Exception { + // GIVEN + Task task = getTestTask(); + OperationResult result = task.getResult(); + + ObjectDelta delta = prismContext.deltaFactory().object() + .createEmptyModifyDelta(ShadowType.class, accountBarbossaOid); + QName attrQName = new QName(MidPointConstants.NS_RI, "title"); + ResourceAttributeDefinition attrDef = accountObjectClassDefinition.findAttributeDefinition(attrQName); + PropertyDelta attrDelta = prismContext.deltaFactory().property().createModificationReplaceProperty( + ItemPath.create(ShadowType.F_ATTRIBUTES, attrQName), attrDef, "Captain"); + delta.addModification(attrDelta); + + // WHEN + when(); + modelService.executeChanges(MiscSchemaUtil.createCollection(delta), null, task, result); + + // THEN + then(); + result.computeStatus(); + TestUtil.assertSuccess(result); + + Entry entry = assertLdapAccount(USER_BARBOSSA_USERNAME, USER_BARBOSSA_FULL_NAME); + assertAttribute(entry, "title", "Captain"); + assertAttribute(entry, ATTRIBUTE_USER_ACCOUNT_CONTROL_NAME, "512"); + + PrismObject user = getUser(USER_BARBOSSA_OID); + String shadowOid = getSingleLinkOid(user); + assertEquals("Shadows have moved", accountBarbossaOid, shadowOid); + + assertLdapConnectorInstances(2); + } + + @Test + public void test212ModifyAccountBarbossaShowInAdvancedViewOnlyTrue() throws Exception { + // GIVEN + Task task = getTestTask(); + OperationResult result = task.getResult(); + + ObjectDelta delta = prismContext.deltaFactory().object() + .createEmptyModifyDelta(ShadowType.class, accountBarbossaOid); + QName attrQName = new QName(MidPointConstants.NS_RI, "showInAdvancedViewOnly"); + ResourceAttributeDefinition attrDef = accountObjectClassDefinition.findAttributeDefinition(attrQName); + PropertyDelta attrDelta = prismContext.deltaFactory().property().createModificationReplaceProperty( + ItemPath.create(ShadowType.F_ATTRIBUTES, attrQName), attrDef, Boolean.TRUE); + delta.addModification(attrDelta); + + // WHEN + when(); + modelService.executeChanges(MiscSchemaUtil.createCollection(delta), null, task, result); + + // THEN + then(); + result.computeStatus(); + TestUtil.assertSuccess(result); + + Entry entry = assertLdapAccount(USER_BARBOSSA_USERNAME, USER_BARBOSSA_FULL_NAME); + assertAttribute(entry, "showInAdvancedViewOnly", "TRUE"); + assertAttribute(entry, ATTRIBUTE_USER_ACCOUNT_CONTROL_NAME, "512"); + + PrismObject user = getUser(USER_BARBOSSA_OID); + String shadowOid = getSingleLinkOid(user); + assertEquals("Shadows have moved", accountBarbossaOid, shadowOid); + + assertLdapConnectorInstances(2); + } + + /** + * Modify USER, test boolean value mapping. + */ + @Test + public void test213ModifyUserBarbossaShowInAdvancedViewOnlyFalse() throws Exception { + // GIVEN + Task task = getTestTask(); + OperationResult result = task.getResult(); + + ObjectDelta delta = prismContext.deltaFactory().object() + .createEmptyModifyDelta(ShadowType.class, accountBarbossaOid); + QName attrQName = new QName(MidPointConstants.NS_RI, "showInAdvancedViewOnly"); + ResourceAttributeDefinition attrDef = accountObjectClassDefinition.findAttributeDefinition(attrQName); + PropertyDelta attrDelta = prismContext.deltaFactory().property().createModificationReplaceProperty( + ItemPath.create(ShadowType.F_ATTRIBUTES, attrQName), attrDef, Boolean.TRUE); + delta.addModification(attrDelta); + + // WHEN + when(); + modifyUserReplace(USER_BARBOSSA_OID, ItemPath.create(UserType.F_EXTENSION, EXTENSION_SHOW_IN_ADVANCED_VIEW_ONLY_QNAME), + task, result, Boolean.FALSE); + + // THEN + then(); + assertSuccess(result); + + Entry entry = assertLdapAccount(USER_BARBOSSA_USERNAME, USER_BARBOSSA_FULL_NAME); + assertAttribute(entry, "showInAdvancedViewOnly", "FALSE"); + assertAttribute(entry, ATTRIBUTE_USER_ACCOUNT_CONTROL_NAME, "512"); + + PrismObject user = getUser(USER_BARBOSSA_OID); + String shadowOid = getSingleLinkOid(user); + assertEquals("Shadows have moved", accountBarbossaOid, shadowOid); + + assertLdapConnectorInstances(2); + } + + @Test + public void test220ModifyUserBarbossaPassword() throws Exception { + // GIVEN + Task task = getTestTask(); + OperationResult result = task.getResult(); + + ProtectedStringType userPasswordPs = new ProtectedStringType(); + userPasswordPs.setClearValue(USER_BARBOSSA_PASSWORD_2); + + // WHEN + when(); + modifyUserReplace(USER_BARBOSSA_OID, PATH_CREDENTIALS_PASSWORD_VALUE, task, result, userPasswordPs); + + // THEN + then(); + assertSuccess(result); + + Entry entry = assertLdapAccount(USER_BARBOSSA_USERNAME, USER_BARBOSSA_FULL_NAME); + assertAttribute(entry, "title", "Captain"); + assertLdapPasswordByFullName(USER_BARBOSSA_FULL_NAME, USER_BARBOSSA_PASSWORD_2); + assertAttribute(entry, ATTRIBUTE_USER_ACCOUNT_CONTROL_NAME, "512"); + + PrismObject user = getUser(USER_BARBOSSA_OID); + String shadowOid = getSingleLinkOid(user); + assertEquals("Shadows have moved", accountBarbossaOid, shadowOid); + + assertLdapConnectorInstances(2); + } + + /** + * MID-5242 + */ + @Test + public void test222ModifyUserBarbossaPasswordNational() throws Exception { + // GIVEN + Task task = getTestTask(); + OperationResult result = task.getResult(); + + ProtectedStringType userPasswordPs = new ProtectedStringType(); + userPasswordPs.setClearValue(USER_BARBOSSA_PASSWORD_AD_1); + + // WHEN + when(); + modifyUserReplace(USER_BARBOSSA_OID, PATH_CREDENTIALS_PASSWORD_VALUE, task, result, userPasswordPs); + + // THEN + then(); + assertSuccess(result); + + Entry entry = assertLdapAccount(USER_BARBOSSA_USERNAME, USER_BARBOSSA_FULL_NAME); + assertAttribute(entry, "title", "Captain"); + assertLdapPasswordByFullName(USER_BARBOSSA_FULL_NAME, USER_BARBOSSA_PASSWORD_AD_1); + assertAttribute(entry, ATTRIBUTE_USER_ACCOUNT_CONTROL_NAME, "512"); + + PrismObject user = getUser(USER_BARBOSSA_OID); + String shadowOid = getSingleLinkOid(user); + assertEquals("Shadows have moved", accountBarbossaOid, shadowOid); + + assertLdapConnectorInstances(2); + } + + @Test + public void test230DisableUserBarbossa() throws Exception { + // GIVEN + Task task = getTestTask(); + OperationResult result = task.getResult(); + + // precondition + assertLdapPasswordByFullName(USER_BARBOSSA_FULL_NAME, USER_BARBOSSA_PASSWORD_AD_1); + + // WHEN + when(); + modifyUserReplace(USER_BARBOSSA_OID, PATH_ACTIVATION_ADMINISTRATIVE_STATUS, task, result, ActivationStatusType.DISABLED); + + // THEN + then(); + assertSuccess(result); + + assertLdapConnectorInstances(2); + + PrismObject user = getUser(USER_BARBOSSA_OID); + assertAdministrativeStatus(user, ActivationStatusType.DISABLED); + + Entry entry = assertLdapAccount(USER_BARBOSSA_USERNAME, USER_BARBOSSA_FULL_NAME); + assertAttribute(entry, ATTRIBUTE_USER_ACCOUNT_CONTROL_NAME, "514"); + + String shadowOid = getSingleLinkOid(user); + PrismObject shadow = getObject(ShadowType.class, shadowOid); + assertAccountDisabled(shadow); + + try { + assertLdapPasswordByFullName(USER_BARBOSSA_FULL_NAME, USER_BARBOSSA_PASSWORD_AD_1); + AssertJUnit.fail("Password authentication works, but it should fail"); + } catch (SecurityException e) { + // this is expected + } + + assertLdapConnectorInstances(2); + } + + @Test + public void test239EnableUserBarbossa() throws Exception { + // GIVEN + Task task = getTestTask(); + OperationResult result = task.getResult(); + + // WHEN + when(); + modifyUserReplace(USER_BARBOSSA_OID, PATH_ACTIVATION_ADMINISTRATIVE_STATUS, task, result, ActivationStatusType.ENABLED); + + // THEN + then(); + assertSuccess(result); + + PrismObject user = getUser(USER_BARBOSSA_OID); + assertAdministrativeStatus(user, ActivationStatusType.ENABLED); + + Entry entry = assertLdapAccount(USER_BARBOSSA_USERNAME, USER_BARBOSSA_FULL_NAME); + assertAttribute(entry, ATTRIBUTE_USER_ACCOUNT_CONTROL_NAME, "512"); + + String shadowOid = getSingleLinkOid(user); + PrismObject shadow = getObject(ShadowType.class, shadowOid); + assertAccountEnabled(shadow); + + assertLdapConnectorInstances(2); + } + + /** + * This should create account with a group. And disabled. + */ + @Test + public void test250AssignGuybrushPirates() throws Exception { + // GIVEN + Task task = getTestTask(); + OperationResult result = task.getResult(); + + modifyUserReplace(USER_GUYBRUSH_OID, PATH_ACTIVATION_ADMINISTRATIVE_STATUS, task, result, ActivationStatusType.DISABLED); + + // WHEN + when(); + assignRole(USER_GUYBRUSH_OID, ROLE_PIRATES_OID, task, result); + + // THEN + then(); + assertSuccess(result); + + Entry entry = assertLdapAccount(USER_GUYBRUSH_USERNAME, USER_GUYBRUSH_FULL_NAME); + display("Entry", entry); + assertAttribute(entry, ATTRIBUTE_USER_ACCOUNT_CONTROL_NAME, "514"); + + assertLdapGroupMember(entry, GROUP_PIRATES_NAME); + + PrismObject user = getUser(USER_GUYBRUSH_OID); + assertAdministrativeStatus(user, ActivationStatusType.DISABLED); + String shadowOid = getSingleLinkOid(user); + + PrismObject shadow = getObject(ShadowType.class, shadowOid); + IntegrationTestTools.assertAssociation(shadow, getAssociationGroupQName(), groupPiratesOid); + assertAccountDisabled(shadow); + + assertLdapConnectorInstances(2); + } + + @Test + public void test255ModifyUserGuybrushPassword() throws Exception { + // GIVEN + Task task = getTestTask(); + OperationResult result = task.getResult(); + + ProtectedStringType userPasswordPs = new ProtectedStringType(); + userPasswordPs.setClearValue("wanna.be.a.123"); + + // WHEN + when(); + modifyUserReplace(USER_GUYBRUSH_OID, PATH_CREDENTIALS_PASSWORD_VALUE, task, result, userPasswordPs); + + // THEN + then(); + result.computeStatus(); + TestUtil.assertSuccess(result); + + Entry entry = assertLdapAccount(USER_GUYBRUSH_USERNAME, USER_GUYBRUSH_FULL_NAME); + assertAttribute(entry, ATTRIBUTE_USER_ACCOUNT_CONTROL_NAME, "514"); + + try { + assertLdapPasswordByFullName(USER_GUYBRUSH_FULL_NAME, "wanna.be.a.123"); + AssertJUnit.fail("Password authentication works, but it should fail"); + } catch (SecurityException e) { + // this is expected, account is disabled + } + + assertLdapConnectorInstances(2); + } + + @Test + public void test260EnableGyubrush() throws Exception { + // GIVEN + Task task = getTestTask(); + OperationResult result = task.getResult(); + + // WHEN + when(); + modifyUserReplace(USER_GUYBRUSH_OID, PATH_ACTIVATION_ADMINISTRATIVE_STATUS, task, result, ActivationStatusType.ENABLED); + + // THEN + then(); + result.computeStatus(); + TestUtil.assertSuccess(result); + + PrismObject user = getUser(USER_GUYBRUSH_OID); + assertAdministrativeStatus(user, ActivationStatusType.ENABLED); + + Entry entry = assertLdapAccount(USER_GUYBRUSH_USERNAME, USER_GUYBRUSH_FULL_NAME); + assertAttribute(entry, ATTRIBUTE_USER_ACCOUNT_CONTROL_NAME, "512"); + + String shadowOid = getSingleLinkOid(user); + PrismObject shadow = getObject(ShadowType.class, shadowOid); + assertAccountEnabled(shadow); + + assertLdapPasswordByFullName(USER_GUYBRUSH_FULL_NAME, "wanna.be.a.123"); + + assertLdapConnectorInstances(2); + } + + @Test + public void test300AssignBarbossaPirates() throws Exception { + // GIVEN + Task task = getTestTask(); + OperationResult result = task.getResult(); + + // WHEN + when(); + assignRole(USER_BARBOSSA_OID, ROLE_PIRATES_OID, task, result); + + // THEN + then(); + result.computeStatus(); + TestUtil.assertSuccess(result); + + Entry entry = assertLdapAccount(USER_BARBOSSA_USERNAME, USER_BARBOSSA_FULL_NAME); + display("Entry", entry); + assertAttribute(entry, "title", "Captain"); + + assertLdapGroupMember(entry, GROUP_PIRATES_NAME); + + PrismObject user = getUser(USER_BARBOSSA_OID); + String shadowOid = getSingleLinkOid(user); + assertEquals("Shadows have moved", accountBarbossaOid, shadowOid); + + PrismObject shadow = getObject(ShadowType.class, shadowOid); + IntegrationTestTools.assertAssociation(shadow, getAssociationGroupQName(), groupPiratesOid); + + assertLdapConnectorInstances(2); + } + + @Test + public void test390ModifyUserBarbossaRename() throws Exception { + // GIVEN + Task task = getTestTask(); + OperationResult result = task.getResult(); + + ObjectDelta objectDelta = createModifyUserReplaceDelta(USER_BARBOSSA_OID, UserType.F_NAME, + PrismTestUtil.createPolyString(USER_CPTBARBOSSA_USERNAME)); + objectDelta.addModificationReplaceProperty(UserType.F_FULL_NAME, + PrismTestUtil.createPolyString(USER_CPTBARBOSSA_FULL_NAME)); + Collection> deltas = MiscSchemaUtil.createCollection(objectDelta); + + // WHEN + when(); + modelService.executeChanges(deltas, null, task, result); + + // THEN + then(); + result.computeStatus(); + TestUtil.assertSuccess(result); + + Entry entry = assertLdapAccount(USER_CPTBARBOSSA_USERNAME, USER_CPTBARBOSSA_FULL_NAME); + assertAttribute(entry, "title", "Captain"); + + PrismObject user = getUser(USER_BARBOSSA_OID); + String shadowOid = getSingleLinkOid(user); + assertEquals("Shadows have moved", accountBarbossaOid, shadowOid); + PrismObject shadow = getObject(ShadowType.class, shadowOid); + display("Shadow after rename (model)", shadow); + + PrismObject repoShadow = repositoryService.getObject(ShadowType.class, shadowOid, null, result); + display("Shadow after rename (repo)", repoShadow); + + assertNoLdapAccount(USER_BARBOSSA_USERNAME, USER_BARBOSSA_FULL_NAME); + + assertLdapConnectorInstances(2); + } + + // TODO: create account with a group membership + + @Test + public void test395UnAssignBarbossaPirates() throws Exception { + // TODO: do this on another account. There is a bad interference with rename. + + // GIVEN + Task task = getTestTask(); + OperationResult result = task.getResult(); + + // WHEN + when(); + unassignRole(USER_BARBOSSA_OID, ROLE_PIRATES_OID, task, result); + + // THEN + then(); + result.computeStatus(); + TestUtil.assertSuccess(result); + + Entry entry = assertLdapAccount(USER_CPTBARBOSSA_USERNAME, USER_CPTBARBOSSA_FULL_NAME); + display("Entry", entry); + assertAttribute(entry, "title", "Captain"); + + assertLdapNoGroupMember(entry, GROUP_PIRATES_NAME); + + PrismObject user = getUser(USER_BARBOSSA_OID); + String shadowOid = getSingleLinkOid(user); + assertEquals("Shadows have moved", accountBarbossaOid, shadowOid); + + PrismObject shadow = getObject(ShadowType.class, shadowOid); + IntegrationTestTools.assertNoAssociation(shadow, getAssociationGroupQName(), groupPiratesOid); + + assertLdapConnectorInstances(2); + } + + @Test + public void test399UnAssignAccountBarbossa() throws Exception { + // GIVEN + Task task = getTestTask(); + OperationResult result = task.getResult(); + + // WHEN + when(); + unassignAccountFromUser(USER_BARBOSSA_OID, getResourceOid(), null, task, result); + + // THEN + then(); + result.computeStatus(); + TestUtil.assertSuccess(result); + + assertNoLdapAccount(USER_BARBOSSA_USERNAME, USER_BARBOSSA_FULL_NAME); + assertNoLdapAccount(USER_CPTBARBOSSA_USERNAME, USER_CPTBARBOSSA_FULL_NAME); + + PrismObject user = getUser(USER_BARBOSSA_OID); + assertNoLinkedAccount(user); + + assertLdapConnectorInstances(2); + } + + @Test + public void test500AddOrgMeleeIsland() throws Exception { + // GIVEN + Task task = getTestTask(); + OperationResult result = task.getResult(); + + PrismObject org = prismContext.getSchemaRegistry().findObjectDefinitionByCompileTimeClass(OrgType.class).instantiate(); + OrgType orgType = org.asObjectable(); + orgType.setName(new PolyStringType(GROUP_MELEE_ISLAND_NAME)); + AssignmentType metaroleAssignment = new AssignmentType(); + ObjectReferenceType metaroleRef = new ObjectReferenceType(); + metaroleRef.setOid(ROLE_META_ORG_OID); + metaroleRef.setType(RoleType.COMPLEX_TYPE); + metaroleAssignment.setTargetRef(metaroleRef); + orgType.getAssignment().add(metaroleAssignment); + + // WHEN + when(); + addObject(org, task, result); + + // THEN + then(); + result.computeStatus(); + TestUtil.assertSuccess(result); + + orgMeleeIslandOid = org.getOid(); + assertLdapGroup(GROUP_MELEE_ISLAND_NAME); + + org = getObject(OrgType.class, orgMeleeIslandOid); + groupMeleeOid = getSingleLinkOid(org); + PrismObject shadow = getShadowModel(groupMeleeOid); + display("Shadow (model)", shadow); + + assertLdapConnectorInstances(2); + } + + @Test + public void test510AssignGuybrushMeleeIsland() throws Exception { + // GIVEN + Task task = getTestTask(); + OperationResult result = task.getResult(); + + // WHEN + when(); + assignOrg(USER_GUYBRUSH_OID, orgMeleeIslandOid, task, result); + + // THEN + then(); + assertSuccess(result); + + Entry entry = assertLdapAccount(USER_GUYBRUSH_USERNAME, USER_GUYBRUSH_FULL_NAME); + + PrismObject user = getUser(USER_GUYBRUSH_OID); + String shadowOid = getSingleLinkOid(user); + PrismObject shadow = getShadowModel(shadowOid); + display("Shadow (model)", shadow); + + assertLdapGroupMember(entry, GROUP_MELEE_ISLAND_NAME); + + IntegrationTestTools.assertAssociation(shadow, getAssociationGroupQName(), groupMeleeOid); + + assertLdapConnectorInstances(2); + } + + @Override + protected void doAdditionalRenameModifications(LdapNetworkConnection connection) throws LdapException { + Modification mod = new DefaultModification(ModificationOperation.REPLACE_ATTRIBUTE, + ATTRIBUTE_SAM_ACCOUNT_NAME_NAME, ACCOUNT_HTM_UID); + connection.modify(toAccountDn(ACCOUNT_HTM_UID, ACCOUNT_HTM_CN), mod); + display("Modified " + toAccountDn(ACCOUNT_HT_UID, ACCOUNT_HT_CN) + " " + ATTRIBUTE_SAM_ACCOUNT_NAME_NAME + + " -> " + ACCOUNT_HTM_UID + ": " + mod); + } + + @Override + protected String getAccountHtmCnAfterRename() { + return ACCOUNT_HTM_CN; + } + + @Override + protected void assertAccountShadow(PrismObject shadow, String dn) throws SchemaException { + super.assertAccountShadow(shadow, dn); + ResourceAttribute primaryIdAttr = ShadowUtil.getAttribute(shadow, getPrimaryIdentifierAttributeQName()); + assertNotNull("No primary identifier (" + getPrimaryIdentifierAttributeQName() + " in " + shadow, primaryIdAttr); + String primaryId = primaryIdAttr.getRealValue(); + assertTrue("Unexpected chars in primary ID: '" + primaryId + "'", primaryId.matches("[a-z0-9\\-]+")); + } + + @Override + protected Entry assertLdapAccount(String samAccountName, String cn) throws LdapException, IOException, CursorException { + Entry entry = searchLdapAccount("(cn=" + cn + ")"); + assertAttribute(entry, "cn", cn); + assertAttribute(entry, ATTRIBUTE_SAM_ACCOUNT_NAME_NAME, samAccountName); + return entry; + } + + @Override + protected void assertNoLdapAccount(String uid) { + throw new UnsupportedOperationException("Boom! Cannot do this here. This is bloody AD! We need full name!"); + } + + protected void assertNoLdapAccount(String uid, String cn) throws LdapException, IOException, CursorException { + LdapNetworkConnection connection = ldapConnect(); + List entriesCn = ldapSearch(connection, "(cn=" + cn + ")"); + List entriesSamAccountName = ldapSearch(connection, "(sAMAccountName=" + uid + ")"); + ldapDisconnect(connection); + + assertEquals("Unexpected number of entries for cn=" + cn + ": " + entriesCn, 0, entriesCn.size()); + assertEquals("Unexpected number of entries for sAMAccountName=" + uid + ": " + entriesSamAccountName, 0, entriesSamAccountName.size()); + } + + @Override + protected String toAccountDn(String username) { + throw new UnsupportedOperationException("Boom! Cannot do this here. This is bloody AD! We need full name!"); + } + + @Override + protected String toAccountDn(String username, String fullName) { + return "CN=" + fullName + "," + getPeopleLdapSuffix(); + } + + @Override + protected Rdn toAccountRdn(String username, String fullName) { + try { + return new Rdn(new Ava("CN", fullName)); + } catch (LdapInvalidDnException e) { + throw new IllegalStateException(e.getMessage(), e); + } + } + + protected void assertLdapPasswordByFullName(String fullName, String password) + throws LdapException, IOException, CursorException { + Entry entry = getLdapAccountByCn(fullName); + assertLdapPassword(entry, password); + } + + protected void assertLdapPassword(String uid, String password) { + throw new UnsupportedOperationException( + "Boom! Cannot do this here. This is bloody AD! We need full name!"); + } + + protected ObjectQuery createSamAccountNameQuery(String samAccountName) throws SchemaException { + ObjectQuery query = ObjectQueryUtil.createResourceAndObjectClassQuery(getResourceOid(), getAccountObjectClass(), prismContext); + ObjectQueryUtil.filterAnd(query.getFilter(), createAttributeFilter(ATTRIBUTE_SAM_ACCOUNT_NAME_NAME, samAccountName), + prismContext); + return query; + } + + @Override + protected Entry createAccountEntry(String uid, String cn, String givenName, String sn) throws LdapException { + byte[] password = encodePassword("Secret.123"); + Entry entry = new DefaultEntry(toAccountDn(uid, cn), + "objectclass", getLdapAccountObjectClass(), + ATTRIBUTE_SAM_ACCOUNT_NAME_NAME, uid, + "cn", cn, + "givenName", givenName, + "sn", sn, + ATTRIBUTE_USER_ACCOUNT_CONTROL_NAME, "512", + ATTRIBUTE_UNICODE_PWD_NAME, password); + return entry; + } + + private byte[] encodePassword(String password) { + String quotedPassword = "\"" + password + "\""; + return quotedPassword.getBytes(StandardCharsets.UTF_16LE); + } + + @Override + protected void assertStepSyncToken(String syncTaskOid, int step, long tsStart, long tsEnd) + throws ObjectNotFoundException, SchemaException { + OperationResult result = createOperationResult("assertStepSyncToken"); + Task task = taskManager.getTaskPlain(syncTaskOid, result); + PrismProperty syncTokenProperty = task.getExtensionPropertyOrClone(SchemaConstants.SYNC_TOKEN); + assertNotNull("No sync token", syncTokenProperty); + assertNotNull("No sync token value", syncTokenProperty.getRealValue()); + assertNotNull("Empty sync token value", StringUtils.isBlank(syncTokenProperty.getRealValue())); + result.computeStatus(); + TestUtil.assertSuccess(result); + } + + public void assertAttribute(PrismObject shadow, String attrName, T... expectedValues) { + assertAttribute(shadow, new QName(getResourceNamespace(), attrName), expectedValues); + } + + public void assertAttribute(PrismObject shadow, QName attrQname, T... expectedValues) { + List actualValues = ShadowUtil.getAttributeValues(shadow, attrQname); + PrismAsserts.assertSets("attribute " + attrQname + " in " + shadow, actualValues, expectedValues); + } + + protected abstract void assertAccountDisabled(PrismObject shadow); + + protected abstract void assertAccountEnabled(PrismObject shadow); +} diff --git a/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/ad/TestAdLdapMedusaSyncTimestamp.java b/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/ad/TestAdLdapMedusaSyncTimestamp.java new file mode 100644 index 00000000000..4b0280e3d93 --- /dev/null +++ b/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/ad/TestAdLdapMedusaSyncTimestamp.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2015-2016 Evolveum and contributors + * + * This work is dual-licensed under the Apache License 2.0 + * and European Union Public License. See LICENSE file for details. + */ +package com.evolveum.midpoint.testing.conntest.ad; + +import java.io.File; + +/** + * @author semancik + */ +public class TestAdLdapMedusaSyncTimestamp extends TestAdLdapMedusa { + + @Override + protected File getResourceFile() { + return new File(getBaseDir(), "resource-medusa-sync-timestamp.xml"); + } + + @Override + protected void syncWait() throws InterruptedException { + // Give us better chance to "catch" the event + Thread.sleep(5000L); + }; + +} diff --git a/testing/conntest/src/test/resources/ad-ldap/resource-medusa-sync-timestamp.xml b/testing/conntest/src/test/resources/ad-ldap/resource-medusa-sync-timestamp.xml new file mode 100644 index 00000000000..a4162fd201f --- /dev/null +++ b/testing/conntest/src/test/resources/ad-ldap/resource-medusa-sync-timestamp.xml @@ -0,0 +1,379 @@ + + + + Active Directory Medusa (LDAP) + + + + + c:connectorType + com.evolveum.polygon.connector.ldap.ad.AdLdapConnector + + + + + + + medusa.lab.evolveum.com + 636 + DC=win,DC=evolveum,DC=com + CN=midpoint admin1,CN=Users,DC=win,DC=evolveum,DC=com + ssl + + mAZadlo911 + + 5 + modifyTimestamp + CN=Users,DC=win,DC=evolveum,DC=com + + + false + false + false + + + + + + + + + + + + + + account + Default Account + true + ri:user + + + ri:dn + Distinguished Name + mr:distinguishedName + + + $user/fullName + + + + + + + + + ri:sAMAccountName + Login name + + + $user/name + + + + + name + + + + + + ri:cn + + 0 + + + + fullName + + + + + fullName + + + + + + ri:sn + + 0 + + + + familyName + + + + + familyName + + + + + + ri:givenName + + + givenName + + + + + givenName + + + + + + ri:userPrincipalName + + + $user/name + + + + + + + + + ri:pwdLastSet + + + -1 + + + + + + ri:createTimeStamp + explicit + + + + ri:nTSecurityDescriptor + + + 0 + + + + + ri:instanceType + + + 0 + + + + + ri:objectCategory + + + 0 + + + + CN=Person,CN=Schema,CN=Configuration,DC=win,DC=evolveum,DC=com + + + + + + ri:showInAdvancedViewOnly + + + extension/showInAdvancedViewOnly + + + + + + ri:group + AD Group Membership + entitlement + group + objectToSubject + ri:member + ri:dn + ri:memberOf + ri:dn + false + + + + + + + + + + + + + + + + + + entitlement + group + AD Group + true + ri:group + + dn + mr:stringIgnoreCase + + + $focus/name + + + + + + + + ri:cn + mr:stringIgnoreCase + + + $focus/name + + + + + name + + + + + ri:description + + strong + + description + + + + + description + + + + + + + + + + + Account sync + ri:user + account + default + UserType + true + + + + c:employeeNumber + + $shadow/attributes/employeeNumber + + + + + c:employeeNumber + + + + + + + linked + true + + + deleted + http://midpoint.evolveum.com/xml/ns/public/model/action-3#deleteFocus + + + unlinked + http://midpoint.evolveum.com/xml/ns/public/model/action-3#link + + + unmatched + http://midpoint.evolveum.com/xml/ns/public/model/action-3#addFocus + + + + + + Group sync + ri:group + entitlement + group + RoleType + true + + + c:name + + $shadow/attributes/cn + + + + + + linked + true + + + deleted + http://midpoint.evolveum.com/xml/ns/public/model/action-3#deleteFocus + + + unlinked + http://midpoint.evolveum.com/xml/ns/public/model/action-3#link + + + unmatched + http://midpoint.evolveum.com/xml/ns/public/model/action-3#addFocus + + + + + + diff --git a/testing/conntest/src/test/resources/logback-test.xml b/testing/conntest/src/test/resources/logback-test.xml index fc529df964b..6d7c4dae09f 100644 --- a/testing/conntest/src/test/resources/logback-test.xml +++ b/testing/conntest/src/test/resources/logback-test.xml @@ -48,6 +48,9 @@ + + + diff --git a/testing/conntest/src/test/resources/opendj-dumber/resource.xml b/testing/conntest/src/test/resources/opendj-dumber/resource.xml index 79db269222d..13b83969e5b 100644 --- a/testing/conntest/src/test/resources/opendj-dumber/resource.xml +++ b/testing/conntest/src/test/resources/opendj-dumber/resource.xml @@ -1,368 +1,369 @@ - - - - Localhost OpenDJ - - - - - - c:connectorType - com.evolveum.polygon.connector.ldap.LdapConnector - - - - - - - - 10389 - localhost - dc=example,dc=com - uid=idm,ou=Administrators,dc=example,dc=com - secret - auto - uid - ds-pwp-account-disabled - createTimestamp - never - (!(roomNumber=invisible)) - - - false - false - false - - - - - - default - Default Account - true - ri:inetOrgPerson - - ri:dn - Distinguished Name - mr:distinguishedName - - - $user/name - - - - - - - - ri:entryUUID - Entry UUID - mr:stringIgnoreCase - - - ri:cn - Common Name - - 1 - - - - fullName - - - - - fullName - - - - - ri:sn - Surname - - - familyName - - - - - familyName - - - - - ri:givenName - Given Name - - - givenName - - - - - givenName - - - - - ri:uid - Login Name - mr:stringIgnoreCase - - weak - - name - - - - - - - - name - - - - - ri:employeeType - mr:stringIgnoreCase - - - employeeType - - - - - - ri:group - LDAP Group Membership - entitlement - ldapGroup - objectToSubject - ri:uniqueMember - ri:dn - true - - - - 5 - - - - - - http://prism.evolveum.com/xml/ns/public/matching-rule-3#distinguishedName - attributes/ri:dn - uid=idm,ou=Administrators,dc=example,dc=com - - - - - - - - - - - - - - - strong - - - - - - - - - - entitlement - ldapGroup - LDAP Group - ri:groupOfUniqueNames - - ri:dn - mr:distinguishedName - - - - $focus/name - - - - - - - - ri:uniqueMember - mr:distinguishedName - - - ri:cn - mr:stringIgnoreCase - - weak - - $focus/name - - - - - name - - - - - ri:description - - - description - - - - - description - - - - - - - - - - - - ri:ds-pwp-account-disabled - - true - - - - - sequentialSearch - - - - - - true - - - - - - Account sync - ri:inetOrgPerson - account - default - UserType - true - - - - employeeNumber - - $projection/attributes/employeeNumber - - - - - employeeNumber - - - - - - - linked - true - - - deleted - http://midpoint.evolveum.com/xml/ns/public/model/action-3#deleteFocus - - - unlinked - http://midpoint.evolveum.com/xml/ns/public/model/action-3#link - - - unmatched - http://midpoint.evolveum.com/xml/ns/public/model/action-3#addFocus - - - - - - Group sync - ri:groupOfUniqueNames - entitlement - ldapGroup - RoleType - true - - - http://prism.evolveum.com/xml/ns/public/matching-rule-3#polyStringNorm - name - - $projection/attributes/cn - - - - - - linked - true - - - deleted - http://midpoint.evolveum.com/xml/ns/public/model/action-3#deleteFocus - - - unlinked - http://midpoint.evolveum.com/xml/ns/public/model/action-3#link - - - unmatched - http://midpoint.evolveum.com/xml/ns/public/model/action-3#addFocus - - - - - + + + + Localhost OpenDJ + + + + + + c:connectorType + com.evolveum.polygon.connector.ldap.LdapConnector + + + + + + + + 10389 + localhost + dc=example,dc=com + uid=idm,ou=Administrators,dc=example,dc=com + secret + auto + uid + ds-pwp-account-disabled + createTimestamp + never + (!(roomNumber=invisible)) + modifyTimestamp + + + false + false + false + + + + + + default + Default Account + true + ri:inetOrgPerson + + ri:dn + Distinguished Name + mr:distinguishedName + + + $user/name + + + + + + + + ri:entryUUID + Entry UUID + mr:stringIgnoreCase + + + ri:cn + Common Name + + 1 + + + + fullName + + + + + fullName + + + + + ri:sn + Surname + + + familyName + + + + + familyName + + + + + ri:givenName + Given Name + + + givenName + + + + + givenName + + + + + ri:uid + Login Name + mr:stringIgnoreCase + + weak + + name + + + + + + + + name + + + + + ri:employeeType + mr:stringIgnoreCase + + + employeeType + + + + + + ri:group + LDAP Group Membership + entitlement + ldapGroup + objectToSubject + ri:uniqueMember + ri:dn + true + + + + 5 + + + + + + http://prism.evolveum.com/xml/ns/public/matching-rule-3#distinguishedName + attributes/ri:dn + uid=idm,ou=Administrators,dc=example,dc=com + + + + + + + + + + + + + + + strong + + + + + + + + + + entitlement + ldapGroup + LDAP Group + ri:groupOfUniqueNames + + ri:dn + mr:distinguishedName + + + + $focus/name + + + + + + + + ri:uniqueMember + mr:distinguishedName + + + ri:cn + mr:stringIgnoreCase + + weak + + $focus/name + + + + + name + + + + + ri:description + + + description + + + + + description + + + + + + + + + + + + ri:ds-pwp-account-disabled + + true + + + + + sequentialSearch + + + + + + true + + + + + + Account sync + ri:inetOrgPerson + account + default + UserType + true + + + + employeeNumber + + $projection/attributes/employeeNumber + + + + + employeeNumber + + + + + + + linked + true + + + deleted + http://midpoint.evolveum.com/xml/ns/public/model/action-3#deleteFocus + + + unlinked + http://midpoint.evolveum.com/xml/ns/public/model/action-3#link + + + unmatched + http://midpoint.evolveum.com/xml/ns/public/model/action-3#addFocus + + + + + + Group sync + ri:groupOfUniqueNames + entitlement + ldapGroup + RoleType + true + + + http://prism.evolveum.com/xml/ns/public/matching-rule-3#polyStringNorm + name + + $projection/attributes/cn + + + + + + linked + true + + + deleted + http://midpoint.evolveum.com/xml/ns/public/model/action-3#deleteFocus + + + unlinked + http://midpoint.evolveum.com/xml/ns/public/model/action-3#link + + + unmatched + http://midpoint.evolveum.com/xml/ns/public/model/action-3#addFocus + + + + + From d1457219b767f7bf44c3ee697681cea9fef78e47 Mon Sep 17 00:00:00 2001 From: Radovan Semancik Date: Mon, 16 Mar 2020 17:21:08 +0100 Subject: [PATCH 08/21] Post-merge fix --- .../testing/conntest/AbstractLdapSynchronizationTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/AbstractLdapSynchronizationTest.java b/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/AbstractLdapSynchronizationTest.java index 068d5e9b3a0..8f9bac74141 100644 --- a/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/AbstractLdapSynchronizationTest.java +++ b/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/AbstractLdapSynchronizationTest.java @@ -160,7 +160,7 @@ public void test802ModifyAccountHtSn() throws Exception { // reread to show the timestamps. Good for timestamp debugging. Entry entryBefore = assertLdapAccount(ACCOUNT_HT_UID, ACCOUNT_HT_CN); - display("HT AD entry", entryBefore); + displayValue("HT AD entry", entryBefore); ldapDisconnect(connection); From 3887e4f2d1f33679f6d15cf37e9987840a8003e6 Mon Sep 17 00:00:00 2001 From: Pavol Mederly Date: Mon, 16 Mar 2020 17:31:13 +0100 Subject: [PATCH 09/21] Fix assignment validity determination When processing assignments, the validity of any given assignment depends on (besides the validity of the assignment itself) the lifecycle state of the assignment source. The original implementation referred to the lifecycle state of the focus. This is not correct when considering the validity of higher-order assignments. So we switched the consideration to assignment source. This resolves MID-6114. --- .../midpoint/common/ActivationComputer.java | 14 +- .../schema/util/ApprovalContextUtil.java | 6 +- .../TestPolicyDrivenRoleLifecycle.java | 2 - .../model/impl/lens/AssignmentEvaluator.java | 22 +- .../impl/lens/AssignmentPathSegmentImpl.java | 17 +- .../midpoint/model/impl/lens/LensUtil.java | 16 +- .../projector/focus/AssignmentProcessor.java | 6 +- .../focus/AssignmentTripleEvaluator.java | 6 +- .../processes/common/StageComputeHelper.java | 2 +- .../primary/PrimaryChangeProcessor.java | 4 +- .../policy/AssignmentPolicyAspectPart.java | 2 - .../primary/policy/PolicyRuleBasedAspect.java | 1 + .../AbstractTestAssignmentApproval.java | 236 +++++++++--------- .../TestAssignmentApprovalGlobal.java | 30 ++- ...estAssignmentApprovalMetaroleExplicit.java | 12 +- .../TestAssignmentApprovalPlainImplicit.java | 12 +- .../test/resources/assignments/user-draft.xml | 12 + .../test/resources/assignments/user-lead1.xml | 3 - .../test/resources/assignments/user-lead2.xml | 3 - .../test/resources/assignments/user-lead3.xml | 3 - 20 files changed, 208 insertions(+), 201 deletions(-) create mode 100644 model/workflow-impl/src/test/resources/assignments/user-draft.xml diff --git a/infra/common/src/main/java/com/evolveum/midpoint/common/ActivationComputer.java b/infra/common/src/main/java/com/evolveum/midpoint/common/ActivationComputer.java index ab1d32711a5..0e28eb59af3 100644 --- a/infra/common/src/main/java/com/evolveum/midpoint/common/ActivationComputer.java +++ b/infra/common/src/main/java/com/evolveum/midpoint/common/ActivationComputer.java @@ -90,15 +90,13 @@ public TimeIntervalStatusType getValidityStatus(ActivationType activationType, X XMLGregorianCalendar validTo = activationType.getValidTo(); if (validFrom == null && validTo == null) { return null; + } else if (validTo != null && referenceTime.compare(validTo) == DatatypeConstants.GREATER) { + return TimeIntervalStatusType.AFTER; + } else if (validFrom != null && referenceTime.compare(validFrom) == DatatypeConstants.LESSER) { + return TimeIntervalStatusType.BEFORE; + } else { + return TimeIntervalStatusType.IN; } - TimeIntervalStatusType status = TimeIntervalStatusType.IN; - if (validFrom != null && (referenceTime == null || referenceTime.compare(validFrom) == DatatypeConstants.LESSER)) { - status = TimeIntervalStatusType.BEFORE; - } - if (validTo != null && referenceTime.compare(validTo) == DatatypeConstants.GREATER) { - status = TimeIntervalStatusType.AFTER; - } - return status; } public void computeEffective(String lifecycleStatus, ActivationType activationType, LifecycleStateModelType stateModel) { diff --git a/infra/schema/src/main/java/com/evolveum/midpoint/schema/util/ApprovalContextUtil.java b/infra/schema/src/main/java/com/evolveum/midpoint/schema/util/ApprovalContextUtil.java index c354ff6f005..54bac8585f7 100644 --- a/infra/schema/src/main/java/com/evolveum/midpoint/schema/util/ApprovalContextUtil.java +++ b/infra/schema/src/main/java/com/evolveum/midpoint/schema/util/ApprovalContextUtil.java @@ -249,10 +249,6 @@ public static ApprovalStageDefinitionType getStageDefinition(ApprovalContextType } } - public static List getStages(ApprovalSchemaType approvalSchema) { - return !approvalSchema.getStage().isEmpty() ? approvalSchema.getStage() : null; - } - // we must be strict here; in case of suspicion, throw an exception @SuppressWarnings("unchecked") public static List getEventsForCurrentStage(@NotNull CaseType aCase, @NotNull Class clazz) { @@ -328,7 +324,7 @@ public static void normalizeStages(ApprovalSchemaType schema) { @NotNull private static List getSortedStages(ApprovalSchemaType schema) { - List stages = new ArrayList<>(getStages(schema)); + List stages = new ArrayList<>(schema.getStage()); stages.sort(Comparator.comparing(stage -> getNumber(stage), Comparator.nullsLast(Comparator.naturalOrder()))); return stages; } diff --git a/model/certification-impl/src/test/java/com/evolveum/midpoint/certification/test/complex/TestPolicyDrivenRoleLifecycle.java b/model/certification-impl/src/test/java/com/evolveum/midpoint/certification/test/complex/TestPolicyDrivenRoleLifecycle.java index f5ed0c18e3e..39ca0f90ee2 100644 --- a/model/certification-impl/src/test/java/com/evolveum/midpoint/certification/test/complex/TestPolicyDrivenRoleLifecycle.java +++ b/model/certification-impl/src/test/java/com/evolveum/midpoint/certification/test/complex/TestPolicyDrivenRoleLifecycle.java @@ -46,8 +46,6 @@ /** * A complex policy-drive role lifecycle scenario (see https://wiki.evolveum.com/display/midPoint/Sample+scenario). - * - * @author mederly */ @ContextConfiguration(locations = {"classpath:ctx-certification-test-main.xml"}) @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentEvaluator.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentEvaluator.java index b0285439f83..8489852b6c0 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentEvaluator.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentEvaluator.java @@ -222,7 +222,7 @@ private EvaluationContext(@NotNull EvaluatedAssignmentImpl evalAssignment, */ public EvaluatedAssignmentImpl evaluate( ItemDeltaItem,PrismContainerDefinition> assignmentIdi, - PlusMinusZero primaryAssignmentMode, boolean evaluateOld, ObjectType source, String sourceDescription, + PlusMinusZero primaryAssignmentMode, boolean evaluateOld, AssignmentHolderType source, String sourceDescription, AssignmentOrigin origin, Task task, OperationResult parentResult) throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException, PolicyViolationException, SecurityViolationException, ConfigurationException, CommunicationException { OperationResult result = parentResult.subresult(OP_EVALUATE) @@ -437,8 +437,12 @@ private boolean evaluateSegmentContent(AssignmentPathSegm AssignmentType assignment = getAssignmentType(segment, ctx); - boolean isAssignmentValid = LensUtil.isAssignmentValid(focusOdo.getNewObject().asObjectable(), assignment, - now, activationComputer, focusStateModel); + // Assignment validity is checked with respect to the assignment source, not to the focus object. + // So, if (e.g.) focus is in "draft" state, only validity of direct assignments should be influenced by this fact. + // Other assignments (e.g. from roles to metaroles) should be considered valid, provided these roles are + // in active lifecycle states. See also MID-6114. + AssignmentHolderType source = segment.isMatchingOrder() ? focusOdo.getNewObject().asObjectable() : segment.getSource(); + boolean isAssignmentValid = LensUtil.isAssignmentValid(source, assignment, now, activationComputer, focusStateModel); if (isAssignmentValid || segment.isValidityOverride()) { // Note: validityOverride is currently the same as "isDirectAssignment" - which is very probably OK. // Direct assignments are visited even if they are not valid (i.e. effectively disabled). @@ -458,7 +462,7 @@ private boolean evaluateSegmentContent(AssignmentPathSegm } } } - if (assignment.getPolicyRule() != null && !loginMode) { + if (!loginMode && assignment.getPolicyRule() != null) { // Here we ignore "reallyValid". It is OK, because reallyValid can be false here only when // evaluating direct assignments; and invalid ones are marked as such via EvaluatedAssignment.isValid. // TODO is it ok? @@ -953,7 +957,7 @@ private void evaluateAssignment(AssignmentPathSegmentImpl segment, PlusMinusZero } private void evaluateInducement(AssignmentPathSegmentImpl segment, PlusMinusZero mode, boolean isValid, EvaluationContext ctx, - AssignmentHolderType targetType, AssignmentType inducement, OperationResult result) + AssignmentHolderType target, AssignmentType inducement, OperationResult result) throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException, PolicyViolationException, SecurityViolationException, ConfigurationException, CommunicationException { ObjectType orderOneObject = getOrderOneObject(segment); @@ -961,7 +965,7 @@ private void evaluateInducement(AssignmentPathSegmentImpl segment, PlusMinusZero if (!isInducementApplicableToFocusType(inducement.getFocusType())) { if (LOGGER.isTraceEnabled()) { LOGGER.trace("Skipping application of inducement {} because the focusType does not match (specified: {}, actual: {})", - FocusTypeUtil.dumpAssignment(inducement), inducement.getFocusType(), targetType.getClass().getSimpleName()); + FocusTypeUtil.dumpAssignment(inducement), inducement.getFocusType(), target.getClass().getSimpleName()); } return; } @@ -971,8 +975,8 @@ private void evaluateInducement(AssignmentPathSegmentImpl segment, PlusMinusZero } return; } - String subSourceDescription = targetType+" in "+segment.sourceDescription; - AssignmentPathSegmentImpl nextSegment = new AssignmentPathSegmentImpl(targetType, subSourceDescription, inducement, false, relationRegistry, prismContext); + String subSourceDescription = target+" in "+segment.sourceDescription; + AssignmentPathSegmentImpl nextSegment = new AssignmentPathSegmentImpl(target, subSourceDescription, inducement, false, relationRegistry, prismContext); // note that 'old' and 'new' values for assignment in nextSegment are the same boolean nextIsMatchingOrder = AssignmentPathSegmentImpl.computeMatchingOrder( segment.getEvaluationOrder(), nextSegment.getAssignmentNew()); @@ -998,7 +1002,7 @@ private void evaluateInducement(AssignmentPathSegmentImpl segment, PlusMinusZero // processMembership attribute to false for these inducements. if (LOGGER.isTraceEnabled()) { LOGGER.trace("orig EO({}): evaluate {} inducement({}) {}; new EO({})", - segment.getEvaluationOrder().shortDump(), targetType, FocusTypeUtil.dumpInducementConstraints(inducement), + segment.getEvaluationOrder().shortDump(), target, FocusTypeUtil.dumpInducementConstraints(inducement), FocusTypeUtil.dumpAssignment(inducement), nextEvaluationOrderHolder.getValue().shortDump()); } assert !ctx.assignmentPath.isEmpty(); diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentPathSegmentImpl.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentPathSegmentImpl.java index 0d1c5eba458..69ed81a6b72 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentPathSegmentImpl.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentPathSegmentImpl.java @@ -26,8 +26,6 @@ import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.xml.ns._public.common.common_3.*; -import net.sf.ehcache.store.disk.ods.AATreeSet; - import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -53,7 +51,7 @@ public class AssignmentPathSegmentImpl implements AssignmentPathSegment { // "assignment path segment" information - final ObjectType source; // we avoid "getter" notation for some final fields to simplify client code + final AssignmentHolderType source; // we avoid "getter" notation for some final fields to simplify client code private final ItemDeltaItem,PrismContainerDefinition> assignmentIdi; private final boolean isAssignment; // false means inducement private QName relation; @@ -249,7 +247,7 @@ public class AssignmentPathSegmentImpl implements AssignmentPathSegment { * is like this: count the number of times the evaluation order for target reached ZERO level. First encounter with * that level is on "this target". And we assume that each subsequent marks a target that is among "others". * - * @see AssignmentEvaluator#appliesDirectly + * See AssignmentEvaluator.appliesDirectly */ private Boolean isMatchingOrder = null; private EvaluationOrder evaluationOrder; @@ -262,14 +260,14 @@ public class AssignmentPathSegmentImpl implements AssignmentPathSegment { private boolean evaluatedForOld; - AssignmentPathSegmentImpl(ObjectType source, String sourceDescription, + AssignmentPathSegmentImpl(AssignmentHolderType source, String sourceDescription, ItemDeltaItem, PrismContainerDefinition> assignmentIdi, boolean isAssignment, boolean evaluatedForOld, @NotNull RelationRegistry relationRegistry, @NotNull PrismContext prismContext) { this.source = source; this.sourceDescription = sourceDescription; if (assignmentIdi.getDefinition() == null) { - throw new IllegalArgumentException("Attept to set segment assignment IDI withough a definition"); + throw new IllegalArgumentException("Attempt to set segment assignment IDI without a definition"); } this.assignmentIdi = assignmentIdi; this.isAssignment = isAssignment; @@ -278,7 +276,7 @@ public class AssignmentPathSegmentImpl implements AssignmentPathSegment { this.prismContext = prismContext; } - public AssignmentPathSegmentImpl(ObjectType source, String sourceDescription, AssignmentType assignment, boolean isAssignment, + public AssignmentPathSegmentImpl(AssignmentHolderType source, String sourceDescription, AssignmentType assignment, boolean isAssignment, RelationRegistry relationRegistry, PrismContext prismContext) { this(source, sourceDescription, createAssignmentIdi(assignment), isAssignment, false, relationRegistry, prismContext); } @@ -286,6 +284,7 @@ public AssignmentPathSegmentImpl(ObjectType source, String sourceDescription, As private static ItemDeltaItem, PrismContainerDefinition> createAssignmentIdi( AssignmentType assignment) { try { + //noinspection unchecked,rawtypes return new ItemDeltaItem<>(LensUtil.createAssignmentSingleValueContainer(assignment), assignment.asPrismContainerValue().getDefinition()); } catch (SchemaException e) { // should not really occur! @@ -344,7 +343,7 @@ public void setTarget(ObjectType target) { } @Override - public ObjectType getSource() { + public AssignmentHolderType getSource() { return source; } @@ -501,6 +500,7 @@ public int hashCode() { return result; } + @SuppressWarnings("RedundantIfStatement") @Override public boolean equals(Object obj) { if (this == obj) @@ -649,6 +649,7 @@ public boolean matches(@NotNull List orderConstraints) { // preliminary implementation; use only to compare segments in paths (pointing to the same target OID) // that are to be checked for equivalency + @SuppressWarnings("SimplifiableIfStatement") @Override public boolean equivalent(AssignmentPathSegment otherSegment) { if (!prismContext.relationsEquivalent(relation, otherSegment.getRelation())) { 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 8b43c5a6981..44d33931aa5 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 @@ -552,22 +552,20 @@ public static boolean evaluateIterationCondition(LensCont /** * Used for assignments and similar objects that do not have separate lifecycle. */ - public static boolean isAssignmentValid(AssignmentHolderType focus, AssignmentType assignmentType, XMLGregorianCalendar now, + public static boolean isAssignmentValid(AssignmentHolderType focus, AssignmentType assignment, XMLGregorianCalendar now, ActivationComputer activationComputer, LifecycleStateModelType focusStateModel) { - ObjectReferenceType targetRef = assignmentType.getTargetRef(); - if (targetRef != null) { - if (QNameUtil.match(ArchetypeType.COMPLEX_TYPE, targetRef.getType())) { - // Archetype assignments are always valid, even in non-valid lifecycle states. - // The object cannot lose its (arche)type. - return true; - } + ObjectReferenceType targetRef = assignment.getTargetRef(); + if (targetRef != null && QNameUtil.match(ArchetypeType.COMPLEX_TYPE, targetRef.getType())) { + // Archetype assignments are always valid, even in non-valid lifecycle states. + // The object cannot lose its (arche)type. + return true; } String focusLifecycleState = focus.getLifecycleState(); if (!activationComputer.lifecycleHasActiveAssignments(focusLifecycleState, focusStateModel)) { return false; } - return isValid(assignmentType.getLifecycleState(), assignmentType.getActivation(), now, activationComputer, focusStateModel); + return isValid(assignment.getLifecycleState(), assignment.getActivation(), now, activationComputer, focusStateModel); } public static Collection getForcedAssignments(LifecycleStateModelType lifecycleModel, String targetLifecycle, diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/focus/AssignmentProcessor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/focus/AssignmentProcessor.java index a6a4c54c221..4830a18b583 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/focus/AssignmentProcessor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/focus/AssignmentProcessor.java @@ -190,7 +190,7 @@ private void processAssig // Initializing assignment evaluator. This will be used later to process all the assignments including the nested // assignments (roles). AssignmentEvaluator assignmentEvaluator = createAssignmentEvaluator(context, now); - ObjectType source = determineSource(focusContext); + AssignmentHolderType source = determineSource(focusContext); AssignmentTripleEvaluator assignmentTripleEvaluator = new AssignmentTripleEvaluator<>(); assignmentTripleEvaluator.setActivationComputer(activationComputer); @@ -585,9 +585,9 @@ private void checkAssignmentDeltaSanity(LensCon } } - private ObjectType determineSource(LensFocusContext focusContext) + private AssignmentHolderType determineSource(LensFocusContext focusContext) throws SchemaException { - ObjectDelta delta = focusContext.getWaveDelta(focusContext.getLensContext().getExecutionWave()); + ObjectDelta delta = focusContext.getWaveDelta(focusContext.getLensContext().getExecutionWave()); if (delta != null && !delta.isEmpty()) { return focusContext.getObjectNew().asObjectable(); } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/focus/AssignmentTripleEvaluator.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/focus/AssignmentTripleEvaluator.java index aa92bc91f7f..afd742f8bb4 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/focus/AssignmentTripleEvaluator.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/focus/AssignmentTripleEvaluator.java @@ -63,7 +63,7 @@ public class AssignmentTripleEvaluator { private static final String OP_EVALUATE_ASSIGNMENT = AssignmentTripleEvaluator.class.getName()+".evaluateAssignment"; private LensContext context; - private ObjectType source; + private AssignmentHolderType source; private AssignmentEvaluator assignmentEvaluator; private ActivationComputer activationComputer; private PrismContext prismContext; @@ -87,11 +87,11 @@ public void setContext(LensContext context) { } } - public ObjectType getSource() { + public AssignmentHolderType getSource() { return source; } - public void setSource(ObjectType source) { + public void setSource(AssignmentHolderType source) { this.source = source; } diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/common/StageComputeHelper.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/common/StageComputeHelper.java index b5c76b1b53b..24b86f975ef 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/common/StageComputeHelper.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/common/StageComputeHelper.java @@ -136,7 +136,7 @@ public ComputationResult computeStageApprovers(ApprovalStageDefinitionType stage return variables; }; - if (rv.predeterminedOutcome == null && stageDef.getAutomaticallyCompleted() != null) { + if (stageDef.getAutomaticallyCompleted() != null) { try { expressionVariables = enhancedVariablesProvider.get(); String outcome = evaluateAutoCompleteExpression(stageDef, expressionVariables, opTask, opResult); diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/PrimaryChangeProcessor.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/PrimaryChangeProcessor.java index 701575819a9..8336aebc3e8 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/PrimaryChangeProcessor.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/PrimaryChangeProcessor.java @@ -28,7 +28,6 @@ import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.schema.util.CaseTypeUtil; import com.evolveum.midpoint.schema.util.ObjectTypeUtil; -import com.evolveum.midpoint.schema.util.ApprovalContextUtil; import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.task.api.TaskExecutionStatus; import com.evolveum.midpoint.task.api.TaskManager; @@ -196,7 +195,7 @@ public boolean isEmpty(PcpStartInstruction instruction, if (actx == null) { return true; } - List stages = ApprovalContextUtil.getStages(actx.getApprovalSchema()); + List stages = actx.getApprovalSchema().getStage(); // first pass: if there is any stage that is obviously not skippable, let's return false without checking the expressions for (ApprovalStageDefinitionType stage : stages) { if (stage.getAutomaticallyCompleted() == null) { @@ -241,6 +240,7 @@ private List gatherStartInstructions logAspectResult(aspect, instructions, changesBeingDecomposed); startProcessInstructions.addAll(instructions); } + result.addParam("instructionsCount", startProcessInstructions.size()); return startProcessInstructions; } catch (Throwable t) { result.recordFatalError(t); diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/policy/AssignmentPolicyAspectPart.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/policy/AssignmentPolicyAspectPart.java index 9b907b55d83..e126043512e 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/policy/AssignmentPolicyAspectPart.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/policy/AssignmentPolicyAspectPart.java @@ -67,8 +67,6 @@ /** * Part of PolicyRuleBasedAspect related to assignments. - * - * @author mederly */ @Component public class AssignmentPolicyAspectPart { diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/policy/PolicyRuleBasedAspect.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/policy/PolicyRuleBasedAspect.java index 1ecc2589e75..074d3c389fb 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/policy/PolicyRuleBasedAspect.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/policy/PolicyRuleBasedAspect.java @@ -95,6 +95,7 @@ public List getStartInstructions(@No .extractAssignmentBasedInstructions(objectTreeDeltas, requester, instructions, ctx, result); objectPolicyAspectPart.extractObjectBasedInstructions(objectTreeDeltas, requester, instructions, ctx, result); } + result.addParam("instructionsCount", instructions.size()); return instructions; } catch (Throwable t) { result.recordFatalError(t); diff --git a/model/workflow-impl/src/test/java/com/evolveum/midpoint/wf/impl/assignments/AbstractTestAssignmentApproval.java b/model/workflow-impl/src/test/java/com/evolveum/midpoint/wf/impl/assignments/AbstractTestAssignmentApproval.java index ae6e449f42c..1010e8327c8 100644 --- a/model/workflow-impl/src/test/java/com/evolveum/midpoint/wf/impl/assignments/AbstractTestAssignmentApproval.java +++ b/model/workflow-impl/src/test/java/com/evolveum/midpoint/wf/impl/assignments/AbstractTestAssignmentApproval.java @@ -6,6 +6,7 @@ */ package com.evolveum.midpoint.wf.impl.assignments; +import static java.util.Collections.singletonList; import static org.testng.AssertJUnit.assertEquals; import static com.evolveum.midpoint.schema.util.ObjectTypeUtil.createAssignmentTo; @@ -17,6 +18,8 @@ import java.util.List; import javax.xml.namespace.QName; +import com.evolveum.midpoint.test.TestResource; + import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.annotation.DirtiesContext.ClassMode; import org.springframework.test.context.ContextConfiguration; @@ -48,8 +51,6 @@ * Testing also with deputies specified. *

* Subclasses provide specializations regarding ways how rules and/or approvers are attached to roles. - * - * @author mederly */ @ContextConfiguration(locations = { "classpath:ctx-workflow-test-main.xml" }) @DirtiesContext(classMode = ClassMode.AFTER_CLASS) @@ -59,73 +60,67 @@ public abstract class AbstractTestAssignmentApproval extends AbstractWfTestPolic private static final File METAROLE_DEFAULT_FILE = new File(TEST_RESOURCE_DIR, "metarole-default.xml"); - private static final File ROLE_ROLE1_FILE = new File(TEST_RESOURCE_DIR, "role-role1.xml"); - private static final File ROLE_ROLE1B_FILE = new File(TEST_RESOURCE_DIR, "role-role1b.xml"); - private static final File ROLE_ROLE2_FILE = new File(TEST_RESOURCE_DIR, "role-role2.xml"); - private static final File ROLE_ROLE2B_FILE = new File(TEST_RESOURCE_DIR, "role-role2b.xml"); - private static final File ROLE_ROLE3_FILE = new File(TEST_RESOURCE_DIR, "role-role3.xml"); - private static final File ROLE_ROLE3B_FILE = new File(TEST_RESOURCE_DIR, "role-role3b.xml"); - private static final File ROLE_ROLE4_FILE = new File(TEST_RESOURCE_DIR, "role-role4.xml"); - private static final File ROLE_ROLE4B_FILE = new File(TEST_RESOURCE_DIR, "role-role4b.xml"); - private static final File ROLE_ROLE10_FILE = new File(TEST_RESOURCE_DIR, "role-role10.xml"); - private static final File ROLE_ROLE10B_FILE = new File(TEST_RESOURCE_DIR, "role-role10b.xml"); - private static final File ROLE_ROLE15_FILE = new File(TEST_RESOURCE_DIR, "role-role15.xml"); - - private static final File USER_JACK_DEPUTY_FILE = new File(TEST_RESOURCE_DIR, "user-jack-deputy.xml"); // delegation is created only when needed - private static final File USER_LEAD1_FILE = new File(TEST_RESOURCE_DIR, "user-lead1.xml"); - private static final File USER_LEAD1_DEPUTY_1_FILE = new File(TEST_RESOURCE_DIR, "user-lead1-deputy1.xml"); - private static final File USER_LEAD1_DEPUTY_2_FILE = new File(TEST_RESOURCE_DIR, "user-lead1-deputy2.xml"); - private static final File USER_LEAD2_FILE = new File(TEST_RESOURCE_DIR, "user-lead2.xml"); - private static final File USER_LEAD3_FILE = new File(TEST_RESOURCE_DIR, "user-lead3.xml"); - private static final File USER_LEAD10_FILE = new File(TEST_RESOURCE_DIR, "user-lead10.xml"); - private static final File USER_LEAD15_FILE = new File(TEST_RESOURCE_DIR, "user-lead15.xml"); - - String roleRole1Oid; - String roleRole1bOid; - String roleRole2Oid; - String roleRole2bOid; - String roleRole3Oid; - String roleRole3bOid; - String roleRole4Oid; - String roleRole4bOid; - String roleRole10Oid; - String roleRole10bOid; - String roleRole15Oid; - - private String userJackDeputyOid; - private String userLead1Oid; - private String userLead1Deputy1Oid; - private String userLead1Deputy2Oid; - private String userLead2Oid; - private String userLead3Oid; + // Roles 1-3 are approved using implicit or global policy rule -- they have no metarole causing approval + // The approval is triggered because Lead 1-3 are set as approvers for these roles. + // There is no approver for role 4 so it does not undertake aby approval. + static final TestResource ROLE1 = new TestResource(TEST_RESOURCE_DIR, "role-role1.xml", "00000001-d34d-b33f-f00d-000000000001"); + static final TestResource ROLE2 = new TestResource(TEST_RESOURCE_DIR, "role-role2.xml", "00000001-d34d-b33f-f00d-000000000002"); + static final TestResource ROLE3 = new TestResource(TEST_RESOURCE_DIR, "role-role3.xml", "00000001-d34d-b33f-f00d-000000000003"); + static final TestResource ROLE4 = new TestResource(TEST_RESOURCE_DIR, "role-role4.xml", "00000001-d34d-b33f-f00d-000000000004"); + + // Roles 1b-3b are approved using metarole holding a policy rule that engages users with "special-approver" relation. + // The approval is triggered because Lead 1-3 are set as "special approvers" for these roles. + // There is no approver for role 4 so it does not undertake aby approval. + static final TestResource ROLE1B = new TestResource(TEST_RESOURCE_DIR, "role-role1b.xml", "00000001-d34d-b33f-f00d-00000000001b"); + static final TestResource ROLE2B = new TestResource(TEST_RESOURCE_DIR, "role-role2b.xml", "00000001-d34d-b33f-f00d-00000000002b"); + static final TestResource ROLE3B = new TestResource(TEST_RESOURCE_DIR, "role-role3b.xml", "00000001-d34d-b33f-f00d-00000000003b"); + static final TestResource ROLE4B = new TestResource(TEST_RESOURCE_DIR, "role-role4b.xml", "00000001-d34d-b33f-f00d-00000000004b"); + + // Note: Role10/10b is induced so it is _not_ being approved. Only direct assignments are covered by approvals. + static final TestResource ROLE10 = new TestResource(TEST_RESOURCE_DIR, "role-role10.xml", "00000001-d34d-b33f-f00d-000000000010"); + static final TestResource ROLE10B = new TestResource(TEST_RESOURCE_DIR, "role-role10b.xml", "00000001-d34d-b33f-f00d-00000000010b"); + + // delegation for jack-deputy is created only when needed + private static final TestResource USER_JACK_DEPUTY = new TestResource(TEST_RESOURCE_DIR, "user-jack-deputy.xml", "e44769f2-030b-4e9c-9ddf-76bb3a348f9c"); + private static final TestResource USER_LEAD1 = new TestResource(TEST_RESOURCE_DIR, "user-lead1.xml", "00000001-d34d-b33f-f00d-L00000000001"); + private static final TestResource USER_LEAD1_DEPUTY_1 = new TestResource(TEST_RESOURCE_DIR, "user-lead1-deputy1.xml", "00000001-d34d-b33f-f00d-LD1000000001"); + private static final TestResource USER_LEAD1_DEPUTY_2 = new TestResource(TEST_RESOURCE_DIR, "user-lead1-deputy2.xml", "00000001-d34d-b33f-f00d-LD1000000002"); + private static final TestResource USER_LEAD2 = new TestResource(TEST_RESOURCE_DIR, "user-lead2.xml", "00000001-d34d-b33f-f00d-L00000000002"); + private static final TestResource USER_LEAD3 = new TestResource(TEST_RESOURCE_DIR, "user-lead3.xml", "00000001-d34d-b33f-f00d-L00000000003"); + private static final TestResource USER_LEAD10 = new TestResource(TEST_RESOURCE_DIR, "user-lead10.xml", "00000001-d34d-b33f-f00d-L00000000010"); + + // Draft user. His assignments should undertake approvals just like other users' assignments (MID-6113). + private static final TestResource USER_DRAFT = new TestResource(TEST_RESOURCE_DIR, "user-draft.xml","e3c00bba-8ce0-4727-a294-91842264c2de"); protected abstract String getRoleOid(int number); protected abstract String getRoleName(int number); + private boolean lead1DeputiesLoaded; + @Override public void initSystem(Task initTask, OperationResult initResult) throws Exception { super.initSystem(initTask, initResult); repoAddObjectFromFile(METAROLE_DEFAULT_FILE, initResult); - roleRole1Oid = repoAddObjectFromFile(ROLE_ROLE1_FILE, initResult).getOid(); - roleRole1bOid = repoAddObjectFromFile(ROLE_ROLE1B_FILE, initResult).getOid(); - roleRole2Oid = repoAddObjectFromFile(ROLE_ROLE2_FILE, initResult).getOid(); - roleRole2bOid = repoAddObjectFromFile(ROLE_ROLE2B_FILE, initResult).getOid(); - roleRole3Oid = repoAddObjectFromFile(ROLE_ROLE3_FILE, initResult).getOid(); - roleRole3bOid = repoAddObjectFromFile(ROLE_ROLE3B_FILE, initResult).getOid(); - roleRole4Oid = repoAddObjectFromFile(ROLE_ROLE4_FILE, initResult).getOid(); - roleRole4bOid = repoAddObjectFromFile(ROLE_ROLE4B_FILE, initResult).getOid(); - roleRole10Oid = repoAddObjectFromFile(ROLE_ROLE10_FILE, initResult).getOid(); - roleRole10bOid = repoAddObjectFromFile(ROLE_ROLE10B_FILE, initResult).getOid(); - roleRole15Oid = repoAddObjectFromFile(ROLE_ROLE15_FILE, initResult).getOid(); - - userJackDeputyOid = repoAddObjectFromFile(USER_JACK_DEPUTY_FILE, initResult).getOid(); - userLead1Oid = addAndRecomputeUser(USER_LEAD1_FILE, initTask, initResult); - userLead2Oid = addAndRecomputeUser(USER_LEAD2_FILE, initTask, initResult); - userLead3Oid = addAndRecomputeUser(USER_LEAD3_FILE, initTask, initResult); - addAndRecomputeUser(USER_LEAD15_FILE, initTask, initResult); + repoAdd(ROLE1, initResult); + repoAdd(ROLE1B, initResult); + repoAdd(ROLE2, initResult); + repoAdd(ROLE2B, initResult); + repoAdd(ROLE3, initResult); + repoAdd(ROLE3B, initResult); + repoAdd(ROLE4, initResult); + repoAdd(ROLE4B, initResult); + repoAdd(ROLE10, initResult); + repoAdd(ROLE10B, initResult); + + repoAdd(USER_JACK_DEPUTY, initResult); + addAndRecomputeUser(USER_LEAD1.file, initTask, initResult); + addAndRecomputeUser(USER_LEAD2.file, initTask, initResult); + addAndRecomputeUser(USER_LEAD3.file, initTask, initResult); // LEAD10 will be imported later! + + repoAdd(USER_DRAFT, initResult); } /** @@ -137,7 +132,7 @@ public void initSystem(Task initTask, OperationResult initResult) throws Excepti public void test010AddRole1Assignment() throws Exception { login(userAdministrator); - OperationResult result = executeAssignRole1ToJack(false, false, null, null, true); + OperationResult result = executeAssignRole1(userJackOid, false, false, USER_LEAD1.oid, null, true); // MID-5814 OperationResultAsserter.forResult(result) @@ -180,7 +175,7 @@ public void test030AddRole1AssignmentAgain() throws Exception { importLead10(getTestTask(), getTestOperationResult()); - executeAssignRole1ToJack(false, false, null, null, false); + executeAssignRole1(userJackOid, false, false, USER_LEAD1.oid, null, false); } /** @@ -191,7 +186,7 @@ public void test040AddRole1AssignmentImmediate() throws Exception { login(userAdministrator); unassignAllRoles(userJackOid); - executeAssignRole1ToJack(true, false, null, null, false); + executeAssignRole1(userJackOid, true, false, USER_LEAD1.oid, null, false); } /** @@ -205,7 +200,7 @@ public void test050AddRoles123AssignmentNNN() throws Exception { login(userAdministrator); unassignAllRoles(userJackOid); - executeAssignRoles123ToJack(null, false, false, false, false); + executeAssignRoles123ToJack(false, false, false, false); } /** @@ -216,7 +211,7 @@ public void test052AddRoles123AssignmentNNNImmediate() throws Exception { login(userAdministrator); unassignAllRoles(userJackOid); - executeAssignRoles123ToJack(null, true, false, false, false); + executeAssignRoles123ToJack(true, false, false, false); } /** @@ -230,7 +225,7 @@ public void test060AddRoles123AssignmentYNN() throws Exception { login(userAdministrator); unassignAllRoles(userJackOid); - executeAssignRoles123ToJack(null, false, true, false, false); + executeAssignRoles123ToJack(false, true, false, false); } @Test @@ -238,7 +233,7 @@ public void test062AddRoles123AssignmentYNNImmediate() throws Exception { login(userAdministrator); unassignAllRoles(userJackOid); - executeAssignRoles123ToJack(null, true, true, false, false); + executeAssignRoles123ToJack(true, true, false, false); } /** @@ -252,7 +247,7 @@ public void test070AddRoles123AssignmentYYY() throws Exception { login(userAdministrator); unassignAllRoles(userJackOid); - executeAssignRoles123ToJack(null, false, true, true, true); + executeAssignRoles123ToJack(false, true, true, true); } @Test @@ -260,7 +255,7 @@ public void test072AddRoles123AssignmentYYYImmediate() throws Exception { login(userAdministrator); unassignAllRoles(userJackOid); - executeAssignRoles123ToJack(null, true, true, true, true); + executeAssignRoles123ToJack(true, true, true, true); } @Test // MID-4355 @@ -272,12 +267,12 @@ public void test100AddCreateDelegation() throws Exception { OperationResult result = getTestOperationResult(); // WHEN - assignDeputy(userJackDeputyOid, userJackOid, a -> { + assignDeputy(USER_JACK_DEPUTY.oid, userJackOid, a -> { //a.beginLimitTargetContent().allowTransitive(true); }, task, result); // THEN - PrismObject deputy = getUser(userJackDeputyOid); + PrismObject deputy = getUser(USER_JACK_DEPUTY.oid); display("deputy after", deputy); result.computeStatus(); @@ -296,7 +291,7 @@ public void test130AddRole1aAssignmentWithDeputy() throws Exception { importLead1Deputies(task, getTestOperationResult()); unassignAllRoles(userJackOid); - executeAssignRole1ToJack(false, true, null, null, false); + executeAssignRole1(userJackOid, false, true, USER_LEAD1.oid, null, false); } /** @@ -307,7 +302,7 @@ public void test132AddRole1aAssignmentWithDeputyApprovedByDeputy1() throws Excep login(userAdministrator); unassignAllRoles(userJackOid); - executeAssignRole1ToJack(false, true, userLead1Deputy1Oid, null, false); + executeAssignRole1(userJackOid, false, true, USER_LEAD1_DEPUTY_1.oid, null, false); } @Test(enabled = false) @@ -315,30 +310,38 @@ public void test150AddRole1ApproverAssignment() throws Exception { login(userAdministrator); unassignAllRoles(userJackOid); - executeAssignRole1ToJack(false, true, null, SchemaConstants.ORG_APPROVER, false); + executeAssignRole1(userJackOid, false, true, USER_LEAD1.oid, SchemaConstants.ORG_APPROVER, false); + } + + @Test + public void test200AddRole1AssignmentToDraftUser() throws Exception { + login(userAdministrator); + + executeAssignRole1(USER_DRAFT.oid, false, true, USER_LEAD1.oid, null, false); } // in memory tracing is required to check for MID-5814 - private OperationResult executeAssignRole1ToJack(boolean immediate, boolean deputy, String approverOid, QName relation, + private OperationResult executeAssignRole1(String userOid, boolean immediate, boolean deputiesOfLeadOneSeeItems, String approverOid, QName relation, boolean useInMemoryTracing) throws Exception { - String testName = getTestNameShort(); - PrismObject jack = getUser(userJackOid); - AssignmentType assignment = createAssignmentTo(getRoleOid(1), ObjectTypes.ROLE, prismContext); - assignment.getTargetRef().setRelation(relation); - ObjectDelta addRole1Delta = prismContext + PrismObject user = getUser(userOid); + String userName = user.getName().getOrig(); + // @formatter:off + ObjectDelta delta = prismContext .deltaFor(UserType.class) - .item(UserType.F_ASSIGNMENT).add(assignment) - .asObjectDelta(userJackOid); - String realApproverOid = approverOid != null ? approverOid : userLead1Oid; + .item(UserType.F_ASSIGNMENT) + .add(new AssignmentType(prismContext) + .targetRef(getRoleOid(1), RoleType.COMPLEX_TYPE, relation)) + .asObjectDelta(userOid); + // @formatter:on return executeTest2(new TestDetails2() { @Override protected PrismObject getFocus(OperationResult result) { - return jack.clone(); + return user.clone(); } @Override protected ObjectDelta getFocusDelta() { - return addRole1Delta.clone(); + return delta.clone(); } @Override @@ -348,56 +351,59 @@ protected int getNumberOfDeltasToApprove() { @Override protected List getApprovals() { - return Collections.singletonList(true); + return singletonList(true); } @Override protected List> getExpectedDeltasToApprove() { - return Collections.singletonList(addRole1Delta.clone()); + return singletonList(delta.clone()); } @Override protected ObjectDelta getExpectedDelta0() { return prismContext.deltaFactory().object() - .createModifyDelta(jack.getOid(), Collections.emptyList(), UserType.class); + .createModifyDelta(user.getOid(), Collections.emptyList(), UserType.class); } @Override protected String getObjectOid() { - return jack.getOid(); + return user.getOid(); } @Override protected List getExpectedTasks() { - return Collections.singletonList(new ExpectedTask(getRoleOid(1), "Assigning role \"" + getRoleName(1) + "\" to user \"jack\"")); + return singletonList(new ExpectedTask(getRoleOid(1), "Assigning role \"" + + getRoleName(1) + "\" to user \"" + userName + "\"")); } @Override protected List getExpectedWorkItems() { ExpectedTask expTask = getExpectedTasks().get(0); - return Collections.singletonList(new ExpectedWorkItem(userLead1Oid, getRoleOid(1), expTask)); + return singletonList(new ExpectedWorkItem(USER_LEAD1.oid, getRoleOid(1), expTask)); } @Override protected void assertDeltaExecuted(int number, boolean yes, Task opTask, OperationResult result) throws Exception { if (number == 1) { if (yes) { - assertAssignedRole(userJackOid, getRoleOid(1), result); + assertAssignedRole(userOid, getRoleOid(1), result); checkAuditRecords(createResultMap(getRoleOid(1), WorkflowResult.APPROVED)); - checkUserApprovers(userJackOid, Collections.singletonList(realApproverOid), result); + checkUserApprovers(userOid, singletonList(approverOid), result); } else { - assertNotAssignedRole(userJackOid, getRoleOid(1), result); + assertNotAssignedRole(userOid, getRoleOid(1), result); } } } @Override protected Boolean decideOnApproval(CaseWorkItemType caseWorkItem) throws Exception { - assertActiveWorkItems(userLead1Oid, 1); - assertActiveWorkItems(userLead1Deputy1Oid, deputy ? 1 : 0); - assertActiveWorkItems(userLead1Deputy2Oid, deputy ? 1 : 0); + assertActiveWorkItems(USER_LEAD1.oid, 1); + if (lead1DeputiesLoaded || deputiesOfLeadOneSeeItems) { + assertActiveWorkItems(USER_LEAD1_DEPUTY_1.oid, deputiesOfLeadOneSeeItems ? 1 : 0); + assertActiveWorkItems(USER_LEAD1_DEPUTY_2.oid, deputiesOfLeadOneSeeItems ? 1 : 0); + } checkTargetOid(caseWorkItem, getRoleOid(1)); - login(getUser(realApproverOid)); + login(getUser(approverOid)); return true; } @@ -438,27 +444,22 @@ private void assertActiveWorkItems(String approverOid, int expectedCount) throws assertEquals("Wrong active work items for " + approverOid, expectedCount, items.size()); } - private void executeAssignRoles123ToJack(String testNameExplicit, boolean immediate, boolean approve1, boolean approve2, boolean approve3) throws Exception { - String testName = testNameExplicit != null ? testNameExplicit : getTestNameShort(); + private void executeAssignRoles123ToJack(boolean immediate, boolean approve1, boolean approve2, boolean approve3) throws Exception { + String testName = getTestNameShort(); PrismObject jack = getUser(userJackOid); - ObjectDelta addRole1Delta = prismContext - .deltaFor(UserType.class) + ObjectDelta addRole1Delta = prismContext.deltaFor(UserType.class) .item(UserType.F_ASSIGNMENT).add(createAssignmentTo(getRoleOid(1), ObjectTypes.ROLE, prismContext)) .asObjectDelta(userJackOid); - ObjectDelta addRole2Delta = prismContext - .deltaFor(UserType.class) + ObjectDelta addRole2Delta = prismContext.deltaFor(UserType.class) .item(UserType.F_ASSIGNMENT).add(createAssignmentTo(getRoleOid(2), ObjectTypes.ROLE, prismContext)) .asObjectDelta(userJackOid); - ObjectDelta addRole3Delta = prismContext - .deltaFor(UserType.class) + ObjectDelta addRole3Delta = prismContext.deltaFor(UserType.class) .item(UserType.F_ASSIGNMENT).add(createAssignmentTo(getRoleOid(3), ObjectTypes.ROLE, prismContext)) .asObjectDelta(userJackOid); - ObjectDelta addRole4Delta = prismContext - .deltaFor(UserType.class) + ObjectDelta addRole4Delta = prismContext.deltaFor(UserType.class) .item(UserType.F_ASSIGNMENT).add(createAssignmentTo(getRoleOid(4), ObjectTypes.ROLE, prismContext)) .asObjectDelta(userJackOid); - ObjectDelta changeDescriptionDelta = prismContext - .deltaFor(UserType.class) + ObjectDelta changeDescriptionDelta = prismContext.deltaFor(UserType.class) .item(UserType.F_DESCRIPTION).replace(testName) .asObjectDelta(userJackOid); ObjectDelta primaryDelta = ObjectDeltaCollectionsUtil @@ -513,9 +514,9 @@ protected List getExpectedTasks() { protected List getExpectedWorkItems() { List expTasks = getExpectedTasks(); return Arrays.asList( - new ExpectedWorkItem(userLead1Oid, getRoleOid(1), expTasks.get(0)), - new ExpectedWorkItem(userLead2Oid, getRoleOid(2), expTasks.get(1)), - new ExpectedWorkItem(userLead3Oid, getRoleOid(3), expTasks.get(2)) + new ExpectedWorkItem(USER_LEAD1.oid, getRoleOid(1), expTasks.get(0)), + new ExpectedWorkItem(USER_LEAD2.oid, getRoleOid(2), expTasks.get(1)), + new ExpectedWorkItem(USER_LEAD3.oid, getRoleOid(3), expTasks.get(2)) ); } @@ -552,13 +553,13 @@ protected void assertDeltaExecuted(int number, boolean yes, Task opTask, Operati protected Boolean decideOnApproval(CaseWorkItemType caseWorkItem) throws Exception { String targetOid = getTargetOid(caseWorkItem); if (getRoleOid(1).equals(targetOid)) { - login(getUser(userLead1Oid)); + login(getUser(USER_LEAD1.oid)); return approve1; } else if (getRoleOid(2).equals(targetOid)) { - login(getUser(userLead2Oid)); + login(getUser(USER_LEAD2.oid)); return approve2; } else if (getRoleOid(3).equals(targetOid)) { - login(getUser(userLead3Oid)); + login(getUser(USER_LEAD3.oid)); return approve3; } else { throw new IllegalStateException("Unexpected approval request for " + targetOid); @@ -573,11 +574,12 @@ public void test300ApprovalAndEnforce() throws Exception { } private void importLead10(Task task, OperationResult result) throws Exception { - addAndRecomputeUser(USER_LEAD10_FILE, task, result); + addAndRecomputeUser(USER_LEAD10.file, task, result); } private void importLead1Deputies(Task task, OperationResult result) throws Exception { - userLead1Deputy1Oid = addAndRecomputeUser(USER_LEAD1_DEPUTY_1_FILE, task, result); - userLead1Deputy2Oid = addAndRecomputeUser(USER_LEAD1_DEPUTY_2_FILE, task, result); + addAndRecomputeUser(USER_LEAD1_DEPUTY_1.file, task, result); + addAndRecomputeUser(USER_LEAD1_DEPUTY_2.file, task, result); + lead1DeputiesLoaded = true; } } diff --git a/model/workflow-impl/src/test/java/com/evolveum/midpoint/wf/impl/assignments/TestAssignmentApprovalGlobal.java b/model/workflow-impl/src/test/java/com/evolveum/midpoint/wf/impl/assignments/TestAssignmentApprovalGlobal.java index eb8a0f7a3be..fd32d1fc47e 100644 --- a/model/workflow-impl/src/test/java/com/evolveum/midpoint/wf/impl/assignments/TestAssignmentApprovalGlobal.java +++ b/model/workflow-impl/src/test/java/com/evolveum/midpoint/wf/impl/assignments/TestAssignmentApprovalGlobal.java @@ -9,6 +9,7 @@ import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.task.api.Task; +import com.evolveum.midpoint.test.TestResource; import com.evolveum.midpoint.util.exception.PolicyViolationException; import com.evolveum.midpoint.xml.ns._public.common.common_3.CaseWorkItemType; @@ -18,14 +19,25 @@ import static org.testng.AssertJUnit.assertEquals; /** - * Shouldn't be used, as global policy rules for assignments are not implemented yet. * - * @author mederly */ public class TestAssignmentApprovalGlobal extends AbstractTestAssignmentApproval { private static final File SYSTEM_CONFIGURATION_GLOBAL_FILE = new File(TEST_RESOURCE_DIR, "system-configuration-global.xml"); + // Role15 has its approver but there is also a global policy rule that prevents it from being assigned. + private static final TestResource ROLE15 = new TestResource(TEST_RESOURCE_DIR, "role-role15.xml", "00000001-d34d-b33f-f00d-000000000015"); + + private static final TestResource USER_LEAD15 = new TestResource(TEST_RESOURCE_DIR, "user-lead15.xml", "00000001-d34d-b33f-f00d-L00000000015"); + + @Override + public void initSystem(Task initTask, OperationResult initResult) throws Exception { + super.initSystem(initTask, initResult); + + repoAdd(ROLE15, initResult); + addAndRecomputeUser(USER_LEAD15.file, initTask, initResult); + } + @Override protected File getSystemConfigurationFile() { return SYSTEM_CONFIGURATION_GLOBAL_FILE; @@ -35,11 +47,11 @@ protected File getSystemConfigurationFile() { @Override protected String getRoleOid(int number) { switch (number) { - case 1: return roleRole1Oid; - case 2: return roleRole2Oid; - case 3: return roleRole3Oid; - case 4: return roleRole4Oid; - case 10: return roleRole10Oid; + case 1: return ROLE1.oid; + case 2: return ROLE2.oid; + case 3: return ROLE3.oid; + case 4: return ROLE4.oid; + case 10: return ROLE10.oid; default: throw new IllegalArgumentException("Wrong role number: " + number); } } @@ -67,9 +79,9 @@ public void test300ApprovalAndEnforce() throws Exception { OperationResult result = getTestOperationResult(); try { - assignRole(userJackOid, roleRole15Oid, task, result); + assignRole(userJackOid, ROLE15.oid, task, result); + fail("Unexpected success"); } catch (PolicyViolationException e) { - // ok System.out.println("Got expected exception: " + e); } List currentWorkItems = modelService.searchContainers(CaseWorkItemType.class, getOpenItemsQuery(), null, task, result); diff --git a/model/workflow-impl/src/test/java/com/evolveum/midpoint/wf/impl/assignments/TestAssignmentApprovalMetaroleExplicit.java b/model/workflow-impl/src/test/java/com/evolveum/midpoint/wf/impl/assignments/TestAssignmentApprovalMetaroleExplicit.java index 29696826e91..9f0c978ed4b 100644 --- a/model/workflow-impl/src/test/java/com/evolveum/midpoint/wf/impl/assignments/TestAssignmentApprovalMetaroleExplicit.java +++ b/model/workflow-impl/src/test/java/com/evolveum/midpoint/wf/impl/assignments/TestAssignmentApprovalMetaroleExplicit.java @@ -9,8 +9,6 @@ /** * Tests assigning of roles 1..3 with explicitly assigned metaroles (with policy rules). - * - * @author mederly */ @SuppressWarnings("Duplicates") public class TestAssignmentApprovalMetaroleExplicit extends AbstractTestAssignmentApproval { @@ -18,11 +16,11 @@ public class TestAssignmentApprovalMetaroleExplicit extends AbstractTestAssignme @Override protected String getRoleOid(int number) { switch (number) { - case 1: return roleRole1bOid; - case 2: return roleRole2bOid; - case 3: return roleRole3bOid; - case 4: return roleRole4bOid; - case 10: return roleRole10bOid; + case 1: return ROLE1B.oid; + case 2: return ROLE2B.oid; + case 3: return ROLE3B.oid; + case 4: return ROLE4B.oid; + case 10: return ROLE10B.oid; default: throw new IllegalArgumentException("Wrong role number: " + number); } } diff --git a/model/workflow-impl/src/test/java/com/evolveum/midpoint/wf/impl/assignments/TestAssignmentApprovalPlainImplicit.java b/model/workflow-impl/src/test/java/com/evolveum/midpoint/wf/impl/assignments/TestAssignmentApprovalPlainImplicit.java index fb3a08197a0..b32d3e1d26a 100644 --- a/model/workflow-impl/src/test/java/com/evolveum/midpoint/wf/impl/assignments/TestAssignmentApprovalPlainImplicit.java +++ b/model/workflow-impl/src/test/java/com/evolveum/midpoint/wf/impl/assignments/TestAssignmentApprovalPlainImplicit.java @@ -10,8 +10,6 @@ /** * Tests assigning of roles 1..3 with implicitly defined approvers (i.e. via org:approver assignment). * As for policy rules, the default ones are used. - * - * @author mederly */ @SuppressWarnings("Duplicates") public class TestAssignmentApprovalPlainImplicit extends AbstractTestAssignmentApproval { @@ -19,11 +17,11 @@ public class TestAssignmentApprovalPlainImplicit extends AbstractTestAssignmentA @Override protected String getRoleOid(int number) { switch (number) { - case 1: return roleRole1Oid; - case 2: return roleRole2Oid; - case 3: return roleRole3Oid; - case 4: return roleRole4Oid; - case 10: return roleRole10Oid; + case 1: return ROLE1.oid; + case 2: return ROLE2.oid; + case 3: return ROLE3.oid; + case 4: return ROLE4.oid; + case 10: return ROLE10.oid; default: throw new IllegalArgumentException("Wrong role number: " + number); } } diff --git a/model/workflow-impl/src/test/resources/assignments/user-draft.xml b/model/workflow-impl/src/test/resources/assignments/user-draft.xml new file mode 100644 index 00000000000..3535937b57c --- /dev/null +++ b/model/workflow-impl/src/test/resources/assignments/user-draft.xml @@ -0,0 +1,12 @@ + + + + draft + draft + Draft + diff --git a/model/workflow-impl/src/test/resources/assignments/user-lead1.xml b/model/workflow-impl/src/test/resources/assignments/user-lead1.xml index 7ff753d829c..442b446a831 100644 --- a/model/workflow-impl/src/test/resources/assignments/user-lead1.xml +++ b/model/workflow-impl/src/test/resources/assignments/user-lead1.xml @@ -24,9 +24,6 @@ - - - Lead1 Lead1 diff --git a/model/workflow-impl/src/test/resources/assignments/user-lead2.xml b/model/workflow-impl/src/test/resources/assignments/user-lead2.xml index f9b9529a833..d3b88e53fd5 100644 --- a/model/workflow-impl/src/test/resources/assignments/user-lead2.xml +++ b/model/workflow-impl/src/test/resources/assignments/user-lead2.xml @@ -16,9 +16,6 @@ - - - Lead2 Lead2 diff --git a/model/workflow-impl/src/test/resources/assignments/user-lead3.xml b/model/workflow-impl/src/test/resources/assignments/user-lead3.xml index ff6c19fb353..497f33d1721 100644 --- a/model/workflow-impl/src/test/resources/assignments/user-lead3.xml +++ b/model/workflow-impl/src/test/resources/assignments/user-lead3.xml @@ -16,9 +16,6 @@ - - - Lead3 Lead3 From 25d44e3c5fa175f52feab8153f456d706b6edcdb Mon Sep 17 00:00:00 2001 From: Katarina Valalikova Date: Mon, 16 Mar 2020 18:28:50 +0100 Subject: [PATCH 10/21] minor fix to be able to delete "unreadable" objects using denug pages. --- .../impl/controller/ModelController.java | 4812 +++++++++-------- 1 file changed, 2408 insertions(+), 2404 deletions(-) diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelController.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelController.java index 3c2c6a74d65..83f66d32cd9 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelController.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelController.java @@ -1,2404 +1,2408 @@ -/* - * Copyright (c) 2010-2019 Evolveum and contributors - * - * This work is dual-licensed under the Apache License 2.0 - * and European Union Public License. See LICENSE file for details. - */ -package com.evolveum.midpoint.model.impl.controller; - -import com.evolveum.midpoint.audit.api.AuditEventRecord; -import com.evolveum.midpoint.audit.api.AuditEventStage; -import com.evolveum.midpoint.audit.api.AuditEventType; -import com.evolveum.midpoint.certification.api.CertificationManager; -import com.evolveum.midpoint.common.LocalizationService; -import com.evolveum.midpoint.model.api.*; -import com.evolveum.midpoint.model.api.authentication.GuiProfiledPrincipalManager; -import com.evolveum.midpoint.model.api.hooks.HookRegistry; -import com.evolveum.midpoint.model.api.hooks.ReadHook; -import com.evolveum.midpoint.model.common.SystemObjectCache; -import com.evolveum.midpoint.model.impl.ModelObjectResolver; -import com.evolveum.midpoint.model.impl.importer.ImportAccountsFromResourceTaskHandler; -import com.evolveum.midpoint.model.impl.importer.ObjectImporter; -import com.evolveum.midpoint.model.impl.lens.*; -import com.evolveum.midpoint.model.impl.scripting.ExecutionContext; -import com.evolveum.midpoint.model.impl.scripting.ScriptingExpressionEvaluator; -import com.evolveum.midpoint.model.impl.util.AuditHelper; -import com.evolveum.midpoint.model.impl.util.ModelImplUtils; -import com.evolveum.midpoint.prism.*; -import com.evolveum.midpoint.prism.crypto.Protector; -import com.evolveum.midpoint.prism.delta.*; -import com.evolveum.midpoint.prism.path.*; -import com.evolveum.midpoint.prism.polystring.PolyString; -import com.evolveum.midpoint.prism.query.*; -import com.evolveum.midpoint.prism.util.CloneUtil; -import com.evolveum.midpoint.provisioning.api.*; -import com.evolveum.midpoint.repo.api.PreconditionViolationException; -import com.evolveum.midpoint.repo.api.RepoAddOptions; -import com.evolveum.midpoint.repo.api.RepositoryService; -import com.evolveum.midpoint.repo.cache.RepositoryCache; -import com.evolveum.midpoint.schema.*; -import com.evolveum.midpoint.schema.constants.ObjectTypes; -import com.evolveum.midpoint.schema.constants.SchemaConstants; -import com.evolveum.midpoint.schema.expression.VariablesMap; -import com.evolveum.midpoint.schema.internals.InternalsConfig; -import com.evolveum.midpoint.schema.result.OperationResult; -import com.evolveum.midpoint.schema.result.OperationResultRunner; -import com.evolveum.midpoint.schema.result.OperationResultStatus; -import com.evolveum.midpoint.schema.util.ObjectQueryUtil; -import com.evolveum.midpoint.schema.util.ObjectTypeUtil; -import com.evolveum.midpoint.schema.util.ShadowUtil; -import com.evolveum.midpoint.schema.util.WorkItemId; -import com.evolveum.midpoint.security.api.AuthorizationConstants; -import com.evolveum.midpoint.security.api.SecurityContextManager; -import com.evolveum.midpoint.security.enforcer.api.AuthorizationParameters; -import com.evolveum.midpoint.security.enforcer.api.SecurityEnforcer; -import com.evolveum.midpoint.task.api.Task; -import com.evolveum.midpoint.task.api.TaskManager; -import com.evolveum.midpoint.util.DebugUtil; -import com.evolveum.midpoint.util.MiscUtil; -import com.evolveum.midpoint.util.QNameUtil; -import com.evolveum.midpoint.util.exception.*; -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.wf.api.WorkflowManager; -import com.evolveum.midpoint.wf.util.ApprovalUtils; -import com.evolveum.midpoint.xml.ns._public.common.api_types_3.CompareResultType; -import com.evolveum.midpoint.xml.ns._public.common.api_types_3.ImportOptionsType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.*; -import com.evolveum.midpoint.xml.ns._public.model.scripting_3.ExecuteScriptType; -import com.evolveum.midpoint.xml.ns._public.model.scripting_3.ScriptingExpressionType; -import com.evolveum.prism.xml.ns._public.types_3.EvaluationTimeType; -import com.evolveum.prism.xml.ns._public.types_3.ObjectDeltaType; -import com.evolveum.prism.xml.ns._public.types_3.PolyStringType; - -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang.StringUtils; -import org.apache.commons.lang.Validate; -import org.jetbrains.annotations.NotNull; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.stereotype.Component; - -import javax.xml.namespace.QName; -import java.io.*; -import java.util.*; - -import static java.util.Collections.emptyList; -import static java.util.Collections.singleton; - -/** - * This used to be an interface, but it was switched to class for simplicity. I - * don't expect that the implementation of the controller will be ever replaced. - * In extreme case the whole Model will be replaced by a different - * implementation, but not just the controller. - *

- * However, the common way to extend the functionality will be the use of hooks - * that are implemented here. - *

- * Great deal of code is copied from the old ModelControllerImpl. - * - * @author lazyman - * @author Radovan Semancik - * - * Note: don't autowire this bean by implementing class (ModelController), as it is proxied by Spring AOP. - * Use its interfaces instead. - */ -@Component -public class ModelController implements ModelService, TaskService, WorkflowService, ScriptingService, AccessCertificationService { - - // Constants for OperationResult - public static final String CLASS_NAME_WITH_DOT = ModelController.class.getName() + "."; - public static final String ADD_OBJECT_WITH_EXCLUSION = CLASS_NAME_WITH_DOT + "addObjectWithExclusion"; - public static final String MODIFY_OBJECT_WITH_EXCLUSION = CLASS_NAME_WITH_DOT - + "modifyObjectWithExclusion"; - public static final String CHANGE_ACCOUNT = CLASS_NAME_WITH_DOT + "changeAccount"; - - public static final String GET_SYSTEM_CONFIGURATION = CLASS_NAME_WITH_DOT + "getSystemConfiguration"; - public static final String RESOLVE_USER_ATTRIBUTES = CLASS_NAME_WITH_DOT + "resolveUserAttributes"; - public static final String RESOLVE_ACCOUNT_ATTRIBUTES = CLASS_NAME_WITH_DOT + "resolveAccountAttributes"; - public static final String CREATE_ACCOUNT = CLASS_NAME_WITH_DOT + "createAccount"; - public static final String UPDATE_ACCOUNT = CLASS_NAME_WITH_DOT + "updateAccount"; - public static final String PROCESS_USER_TEMPLATE = CLASS_NAME_WITH_DOT + "processUserTemplate"; - private static final String RESOLVE_REFERENCE = CLASS_NAME_WITH_DOT + "resolveReference"; - - private static final Trace LOGGER = TraceManager.getTrace(ModelController.class); - - private static final Trace OP_LOGGER = TraceManager.getTrace(ModelService.OPERATION_LOGGGER_NAME); - - @Autowired private Clockwork clockwork; - @Autowired private PrismContext prismContext; - @Autowired private ProvisioningService provisioning; - @Autowired private ModelObjectResolver objectResolver; - @Autowired private transient ImportAccountsFromResourceTaskHandler importAccountsFromResourceTaskHandler; - @Autowired private transient ObjectImporter objectImporter; - @Autowired private HookRegistry hookRegistry; - @Autowired private TaskManager taskManager; - @Autowired private ScriptingExpressionEvaluator scriptingExpressionEvaluator; - @Autowired private AuditHelper auditHelper; - @Autowired private SecurityEnforcer securityEnforcer; - @Autowired private SecurityContextManager securityContextManager; - @Autowired private GuiProfiledPrincipalManager focusProfileService; - @Autowired private Protector protector; - @Autowired private LocalizationService localizationService; - @Autowired private ContextFactory contextFactory; - @Autowired private SchemaTransformer schemaTransformer; - @Autowired private ObjectMerger objectMerger; - @Autowired private SystemObjectCache systemObjectCache; - @Autowired private ClockworkMedic clockworkMedic; - @Autowired private ChangeNotificationDispatcher dispatcher; - @Autowired - @Qualifier("cacheRepositoryService") - private transient RepositoryService cacheRepositoryService; - - @Autowired(required = false) // not required in all circumstances - private WorkflowManager workflowManager; - - @Autowired(required = false) // not required in all circumstances - private CertificationManager certificationManager; - - public ModelObjectResolver getObjectResolver() { - return objectResolver; - } - - private WorkflowManager getWorkflowManagerChecked() { - if (workflowManager == null) { - throw new SystemException("Workflow manager not present"); - } - return workflowManager; - } - - private CertificationManager getCertificationManagerChecked() { - if (certificationManager == null) { - throw new SystemException("Certification manager not present"); - } - return certificationManager; - } - - - @Override - public PrismObject getObject(Class clazz, String oid, - Collection> rawOptions, Task task, OperationResult parentResult) throws ObjectNotFoundException, - SchemaException, CommunicationException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { - Validate.notEmpty(oid, "Object oid must not be null or empty."); - Validate.notNull(parentResult, "Operation result must not be null."); - Validate.notNull(clazz, "Object class must not be null."); - enterModelMethod(); - - PrismObject object; - - OP_LOGGER.trace("MODEL OP enter getObject({},{},{})", clazz.getSimpleName(), oid, rawOptions); - - GetOperationOptions rootOptions = null; - - OperationResult result = parentResult.subresult(GET_OBJECT) - .setMinor() - .addParam("oid", oid) - .addArbitraryObjectCollectionAsParam("options", rawOptions) - .addParam("class", clazz) - .build(); - try { - Collection> options = preProcessOptionsSecurity(rawOptions, task, parentResult); - rootOptions = SelectorOptions.findRootOptions(options); - - if (GetOperationOptions.isRaw(rootOptions)) { // MID-2218 - QNameUtil.setTemporarilyTolerateUndeclaredPrefixes(true); - } - ObjectReferenceType ref = new ObjectReferenceType(); - ref.setOid(oid); - ref.setType(ObjectTypes.getObjectType(clazz).getTypeQName()); - ModelImplUtils.clearRequestee(task); - -// Special-purpose code to hunt down read-write resource fetch from GUI. -// Normally the code is not active. It is too brutal. Just for MID-3424. -// if (ResourceType.class == clazz && !GetOperationOptions.isRaw(rootOptions) && !GetOperationOptions.isReadOnly(rootOptions)) { -// LOGGER.info("READWRITE resource get: {} {}:\n{}", oid, options, -// LoggingUtils.dumpStackTrace()); -// } - - object = (PrismObject) objectResolver.getObject(clazz, oid, options, task, result).asPrismObject(); - - object = object.cloneIfImmutable(); - schemaTransformer.applySchemasAndSecurity(object, rootOptions, options, null, task, result); - executeResolveOptions(object.asObjectable(), options, task, result); - - } catch (SchemaException | CommunicationException | ConfigurationException | SecurityViolationException | ExpressionEvaluationException | RuntimeException | Error e) { - OP_LOGGER.debug("MODEL OP error getObject({},{},{}): {}: {}", clazz.getSimpleName(), oid, rawOptions, e.getClass().getSimpleName(), e.getMessage()); - ModelImplUtils.recordFatalError(result, e); - throw e; - } catch (ObjectNotFoundException e) { - OP_LOGGER.debug("MODEL OP error getObject({},{},{}): {}: {}", clazz.getSimpleName(), oid, rawOptions, e.getClass().getSimpleName(), e.getMessage()); - if (GetOperationOptions.isAllowNotFound(rootOptions)){ - result.getLastSubresult().setStatus(OperationResultStatus.HANDLED_ERROR); - } else { - ModelImplUtils.recordFatalError(result, e); - } - throw e; - } finally { - result.computeStatusIfUnknown(); - QNameUtil.setTemporarilyTolerateUndeclaredPrefixes(false); - exitModelMethod(); - } - - result.cleanupResult(); - - OP_LOGGER.debug("MODEL OP exit getObject({},{},{}): {}", clazz.getSimpleName(), oid, rawOptions, object); - if (OP_LOGGER.isTraceEnabled()) { - OP_LOGGER.trace("MODEL OP exit getObject({},{},{}):\n{}", clazz.getSimpleName(), oid, rawOptions, object.debugDump(1)); - } - return object; - } - - private void executeResolveOptions(@NotNull Containerable containerable, Collection> options, - Task task, OperationResult result) { - if (options == null) { - return; - } - for (SelectorOptions option: options) { - if (GetOperationOptions.isResolve(option.getOptions())) { - ObjectSelector selector = option.getSelector(); - if (selector != null) { - ItemPath path = selector.getPath(); - ItemPath.checkNoSpecialSymbolsExceptParent(path); - executeResolveOption(containerable, path, option, task, result); - } - } - } - } - - // TODO clean this mess - private void executeResolveOption(Containerable containerable, ItemPath path, - SelectorOptions option, Task task, OperationResult result) { - if (path == null || path.isEmpty()) { - return; - } - Object first = path.first(); - ItemPath rest = path.rest(); - PrismContainerValue containerValue = containerable.asPrismContainerValue(); - if (ItemPath.isName(first)) { - QName firstName = ItemPath.toName(first); - PrismReference reference = containerValue.findReferenceByCompositeObjectElementName(firstName); - if (reference == null) { - reference = containerValue.findReference(firstName); // alternatively look up by reference name (e.g. linkRef) - } - if (reference != null) { - for (PrismReferenceValue refVal : reference.getValues()) { - //noinspection unchecked - PrismObject refObject = refVal.getObject(); - if (refObject == null) { - refObject = resolveReferenceUsingOption(refVal, option, containerable, task, result); - } - if (!rest.isEmpty() && refObject != null) { - executeResolveOption(refObject.asObjectable(), rest, option, task, result); - } - } - return; - } - } - if (rest.isEmpty()) { - return; - } - if (ItemPath.isParent(first)) { - PrismContainerValue parent = containerValue.getParentContainerValue(); - if (parent != null) { - executeResolveOption(parent.asContainerable(), rest, option, task, result); - } - } else { - QName nextName = ItemPath.toName(first); - PrismContainer nextContainer = containerValue.findContainer(nextName); - if (nextContainer != null) { - for (PrismContainerValue pcv : nextContainer.getValues()) { - executeResolveOption(pcv.asContainerable(), rest, option, task, result); - } - } - } - } - - private PrismObject resolveReferenceUsingOption(@NotNull PrismReferenceValue refVal, - SelectorOptions option, Containerable containerable, Task task, OperationResult parentResult) { - OperationResult result = parentResult.createMinorSubresult(RESOLVE_REFERENCE); - try { - PrismObject refObject; - refObject = objectResolver.resolve(refVal, containerable.toString(), option.getOptions(), task, result); - if (refObject != null) { - refObject = refObject.cloneIfImmutable(); - schemaTransformer.applySchemasAndSecurity(refObject, option.getOptions(), - SelectorOptions.createCollection(option.getOptions()), null, task, result); - refVal.setObject(refObject); - } - return refObject; - } catch (CommonException e) { - result.recordWarning("Couldn't resolve reference to " + ObjectTypeUtil.toShortString(refVal) + ": " + e.getMessage(), e); - return null; - } finally { - result.computeStatusIfUnknown(); - } - } - - @Override - public Collection> executeChanges(final Collection> deltas, ModelExecuteOptions options, - Task task, OperationResult parentResult) throws ObjectAlreadyExistsException, ObjectNotFoundException, - SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException, - PolicyViolationException, SecurityViolationException { - return executeChanges(deltas, options, task, null, parentResult); - } - - /* (non-Javadoc) - * @see com.evolveum.midpoint.model.api.ModelService#executeChanges(java.util.Collection, com.evolveum.midpoint.task.api.Task, com.evolveum.midpoint.schema.result.OperationResult) - */ - @Override - public Collection> executeChanges(Collection> deltas, ModelExecuteOptions options, - Task task, Collection statusListeners, OperationResult parentResult) throws ObjectAlreadyExistsException, ObjectNotFoundException, - SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException, - PolicyViolationException, SecurityViolationException { - - enterModelMethod(); - - OperationResult result = parentResult.createSubresult(EXECUTE_CHANGES); - result.addArbitraryObjectAsParam(OperationResult.PARAM_OPTIONS, options); - - try { - - // Search filters treatment: if reevaluation is requested, we have to deal with three cases: - // 1) for ADD operation: filters contained in object-to-be-added -> these are treated here - // 2) for MODIFY operation: filters contained in existing object (not touched by deltas) -> these are treated after the modify operation - // 3) for MODIFY operation: filters contained in deltas -> these have to be treated here, because if OID is missing from such a delta, the change would be rejected by the repository - if (ModelExecuteOptions.isReevaluateSearchFilters(options)) { - for (ObjectDelta delta : deltas) { - ModelImplUtils.resolveReferences(delta, cacheRepositoryService, false, true, EvaluationTimeType.IMPORT, true, prismContext, result); - } - } else if (ModelExecuteOptions.isIsImport(options)) { - // if plain import is requested, we simply evaluate filters in ADD operation (and we do not force reevaluation if OID is already set) - for (ObjectDelta delta : deltas) { - if (delta.isAdd()) { - ModelImplUtils.resolveReferences(delta.getObjectToAdd(), cacheRepositoryService, false, false, EvaluationTimeType.IMPORT, true, prismContext, result); - } - } - } - // Make sure everything is encrypted as needed before logging anything. - // But before that we need to make sure that we have proper definition, otherwise we - // might miss some encryptable data in dynamic schemas - applyDefinitions(deltas, options, task, result); - ModelImplUtils.encrypt(deltas, protector, options, result); - computePolyStrings(deltas, options, result); - - LOGGER.trace("MODEL.executeChanges(\n deltas:\n{}\n options:{}", DebugUtil.debugDumpLazily(deltas, 2), options); - - if (InternalsConfig.consistencyChecks) { - OperationResultRunner.run(result, () -> { - for (ObjectDelta delta : deltas) { - delta.checkConsistence(); - } - }); - } - - if (ModelExecuteOptions.isRaw(options)) { - return executeChangesRaw(deltas, options, task, result); - } else { - return executeChangesNonRaw(deltas, options, task, statusListeners, result); - } - - // Note: caches are invalidated automatically via RepositoryCache.invalidateCacheEntries method - - } catch (RuntimeException e) { // just for sure (TODO split this method into two: raw and non-raw case) - ModelImplUtils.recordFatalError(result, e); - throw e; - } finally { - exitModelMethod(); - } - } - - private Collection> executeChangesNonRaw( - Collection> deltas, ModelExecuteOptions options, Task task, - Collection statusListeners, OperationResult result) - throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, - ExpressionEvaluationException, SecurityViolationException, PolicyViolationException, ObjectAlreadyExistsException { - try { - LensContext context = contextFactory.createContext(deltas, options, task, result); - - authorizePartialExecution(context, options, task, result); - - if (ModelExecuteOptions.isReevaluateSearchFilters(options)) { - String m = "ReevaluateSearchFilters option is not fully supported for non-raw operations yet. Filters already present in the object will not be touched."; - LOGGER.warn("{} Context = {}", m, context.debugDump()); - result.createSubresult(CLASS_NAME_WITH_DOT+"reevaluateSearchFilters").recordWarning(m); - } - - context.setProgressListeners(statusListeners); - // Note: Request authorization happens inside clockwork - - clockwork.run(context, task, result); - - // prepare return value - Collection> executedDeltas = new ArrayList<>(); - if (context.getFocusContext() != null) { - executedDeltas.addAll(context.getFocusContext().getExecutedDeltas()); - } - for (LensProjectionContext projectionContext : context.getProjectionContexts()) { - executedDeltas.addAll(projectionContext.getExecutedDeltas()); - } - - if (context.hasExplosiveProjection()) { - PrismObject focus = context.getFocusContext().getObjectAny(); - - LOGGER.debug("Recomputing {} because there was explosive projection", focus); - - LensContext recomputeContext = contextFactory.createRecomputeContext(focus, options, task, result); - recomputeContext.setDoReconciliationForAllProjections(true); - LOGGER.trace("Recomputing {}, context:\n{}", focus, recomputeContext.debugDumpLazily()); - clockwork.run(recomputeContext, task, result); - } - - cleanupOperationResult(result); - return executedDeltas; - - } catch (ObjectAlreadyExistsException | ObjectNotFoundException | SchemaException | ExpressionEvaluationException | - CommunicationException|ConfigurationException|PolicyViolationException|SecurityViolationException|RuntimeException e) { - ModelImplUtils.recordFatalError(result, e); - throw e; - - } catch (PreconditionViolationException e) { - ModelImplUtils.recordFatalError(result, e); - // TODO: Temporary fix for 3.6.1 - // We do not want to propagate PreconditionViolationException to model API as that might break compatiblity - // ... and we do not really need that in 3.6.1 - // TODO: expose PreconditionViolationException in 3.7 - throw new SystemException(e); - - } finally { - task.markObjectActionExecutedBoundary(); - } - } - - private Collection> executeChangesRaw(Collection> deltas, - ModelExecuteOptions options, Task task, OperationResult result) - throws ExpressionEvaluationException, PolicyViolationException, SecurityViolationException, SchemaException, - ObjectNotFoundException, CommunicationException, ConfigurationException, ObjectAlreadyExistsException { - - AuditEventRecord auditRecord = new AuditEventRecord(AuditEventType.EXECUTE_CHANGES_RAW, AuditEventStage.REQUEST); - String requestIdentifier = ModelImplUtils.generateRequestIdentifier(); - auditRecord.setRequestIdentifier(requestIdentifier); - auditRecord.addDeltas(ObjectDeltaOperation.cloneDeltaCollection(deltas)); - auditRecord.setTarget(ModelImplUtils.determineAuditTarget(deltas, prismContext)); - // we don't know auxiliary information (resource, objectName) at this moment -- so we do nothing - auditHelper.audit(auditRecord, null, task, result); - - Collection> executedDeltas = new ArrayList<>(); - try { - for (ObjectDelta delta : deltas) { - OperationResult result1 = result.createSubresult(EXECUTE_CHANGE); - - // MID-2486 - if (delta.getObjectTypeClass() == ShadowType.class || delta.getObjectTypeClass() == ResourceType.class) { - try { - provisioning.applyDefinition(delta, task, result1); - } catch (SchemaException | ObjectNotFoundException | CommunicationException | ConfigurationException | RuntimeException e) { - // we can tolerate this - if there's a real problem with definition, repo call below will fail - LoggingUtils.logExceptionAsWarning(LOGGER, "Couldn't apply definition on shadow/resource raw-mode delta {} -- continuing the operation.", e, delta); - result1.muteLastSubresultError(); - } - } - - final boolean preAuthorized = ModelExecuteOptions.isPreAuthorized(options); - PrismObject objectToDetermineDetailsForAudit = null; - try { - if (delta.isAdd()) { - RepoAddOptions repoOptions = new RepoAddOptions(); - if (ModelExecuteOptions.isNoCrypt(options)) { - repoOptions.setAllowUnencryptedValues(true); - } - if (ModelExecuteOptions.isOverwrite(options)) { - repoOptions.setOverwrite(true); - } - PrismObject objectToAdd = delta.getObjectToAdd(); - if (!preAuthorized) { - securityEnforcer.authorize(ModelAuthorizationAction.RAW_OPERATION.getUrl(), null, AuthorizationParameters.Builder.buildObjectAdd(objectToAdd), null, task, result1); - securityEnforcer.authorize(ModelAuthorizationAction.ADD.getUrl(), null, AuthorizationParameters.Builder.buildObjectAdd(objectToAdd), null, task, result1); - } - String oid; - try { - oid = cacheRepositoryService.addObject(objectToAdd, repoOptions, result1); - task.recordObjectActionExecuted(objectToAdd, null, oid, ChangeType.ADD, task.getChannel(), null); - } catch (Throwable t) { - task.recordObjectActionExecuted(objectToAdd, null, null, ChangeType.ADD, task.getChannel(), t); - throw t; - } - delta.setOid(oid); - objectToDetermineDetailsForAudit = objectToAdd; - } else if (delta.isDelete()) { - QNameUtil.setTemporarilyTolerateUndeclaredPrefixes(true); // MID-2218 - try { - PrismObject existingObject = null; - try { - existingObject = cacheRepositoryService.getObject(delta.getObjectTypeClass(), delta.getOid(), null, result1); - objectToDetermineDetailsForAudit = existingObject; - } catch (Throwable t) { - if (!securityEnforcer.isAuthorized(AuthorizationConstants.AUTZ_ALL_URL, null, AuthorizationParameters.EMPTY, null, task, result1)) { - throw t; - } else { - // in case of administrator's request we continue - in order to allow deleting malformed (unreadable) objects - } - } - if (!preAuthorized) { - securityEnforcer.authorize(ModelAuthorizationAction.RAW_OPERATION.getUrl(), null, AuthorizationParameters.Builder.buildObjectDelete(existingObject), null, task, result1); - securityEnforcer.authorize(ModelAuthorizationAction.DELETE.getUrl(), null, AuthorizationParameters.Builder.buildObjectDelete(existingObject), null, task, result1); - } - try { - if (ObjectTypes.isClassManagedByProvisioning(delta.getObjectTypeClass())) { - ModelImplUtils.clearRequestee(task); - provisioning.deleteObject(delta.getObjectTypeClass(), delta.getOid(), - ProvisioningOperationOptions.createRaw(), null, task, result1); - } else { - cacheRepositoryService.deleteObject(delta.getObjectTypeClass(), delta.getOid(), - result1); - } - task.recordObjectActionExecuted(objectToDetermineDetailsForAudit, delta.getObjectTypeClass(), delta.getOid(), ChangeType.DELETE, task.getChannel(), null); - } catch (Throwable t) { - task.recordObjectActionExecuted(objectToDetermineDetailsForAudit, delta.getObjectTypeClass(), delta.getOid(), ChangeType.DELETE, task.getChannel(), t); - throw t; - } - } finally { - QNameUtil.setTemporarilyTolerateUndeclaredPrefixes(false); - } - } else if (delta.isModify()) { - QNameUtil.setTemporarilyTolerateUndeclaredPrefixes(true); // MID-2218 - try { - PrismObject existingObject = cacheRepositoryService.getObject(delta.getObjectTypeClass(), delta.getOid(), null, result1); - objectToDetermineDetailsForAudit = existingObject; - if (!preAuthorized) { - AuthorizationParameters autzParams = AuthorizationParameters.Builder.buildObjectDelta(existingObject, delta); - securityEnforcer.authorize(ModelAuthorizationAction.RAW_OPERATION.getUrl(), null, autzParams, null, task, result1); - securityEnforcer.authorize(ModelAuthorizationAction.MODIFY.getUrl(), null, autzParams, null, task, result1); - } - try { - cacheRepositoryService.modifyObject(delta.getObjectTypeClass(), delta.getOid(), - delta.getModifications(), result1); - task.recordObjectActionExecuted(existingObject, ChangeType.MODIFY, null); - } catch (Throwable t) { - task.recordObjectActionExecuted(existingObject, ChangeType.MODIFY, t); - throw t; - } - } finally { - QNameUtil.setTemporarilyTolerateUndeclaredPrefixes(false); - } - if (ModelExecuteOptions.isReevaluateSearchFilters(options)) { // treat filters that already exist in the object (case #2 above) - reevaluateSearchFilters(delta.getObjectTypeClass(), delta.getOid(), task, result1); - } - } else { - throw new IllegalArgumentException("Wrong delta type " + delta.getChangeType() + " in " + delta); - } - } catch (ObjectAlreadyExistsException | SchemaException | ObjectNotFoundException | ConfigurationException | CommunicationException | SecurityViolationException | RuntimeException e) { - ModelImplUtils.recordFatalError(result1, e); - throw e; - } finally { // to have a record with the failed delta as well - result1.computeStatus(); - ObjectDeltaOperation odoToAudit = new ObjectDeltaOperation<>(delta, result1); - if (objectToDetermineDetailsForAudit != null) { - odoToAudit.setObjectName(objectToDetermineDetailsForAudit.getName()); - if (objectToDetermineDetailsForAudit.asObjectable() instanceof ShadowType) { - ShadowType shadow = (ShadowType) objectToDetermineDetailsForAudit.asObjectable(); - odoToAudit.setResourceOid(ShadowUtil.getResourceOid(shadow)); - odoToAudit.setResourceName(ShadowUtil.getResourceName(shadow)); - } - } - executedDeltas.add(odoToAudit); - } - } - return executedDeltas; - } finally { - cleanupOperationResult(result); - auditRecord.setTimestamp(System.currentTimeMillis()); - auditRecord.setOutcome(result.getStatus()); - auditRecord.setEventStage(AuditEventStage.EXECUTION); - auditRecord.getDeltas().clear(); - auditRecord.getDeltas().addAll(executedDeltas); - auditHelper.audit(auditRecord, null, task, result); - - task.markObjectActionExecutedBoundary(); - } - } - - private void authorizePartialExecution(LensContext context, ModelExecuteOptions options, Task task, OperationResult result) throws SecurityViolationException, SchemaException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException { - PartialProcessingOptionsType partialProcessing = ModelExecuteOptions.getPartialProcessing(options); - if (partialProcessing != null) { - PrismObject object = context.getFocusContext().getObjectAny(); - securityEnforcer.authorize(ModelAuthorizationAction.PARTIAL_EXECUTION.getUrl(), null, AuthorizationParameters.Builder.buildObject(object), null, task, result); - } - } - - protected void cleanupOperationResult(OperationResult result) { - // Clockwork.run sets "in-progress" flag just at the root level - // and result.computeStatus() would erase it. - // So we deal with it in a special way, in order to preserve this information for the user. - if (result.isInProgress()) { - result.computeStatus(); - if (result.isSuccess()) { - result.recordInProgress(); - } - } else { - result.computeStatus(); - } - - result.cleanupResult(); - } - - private void reevaluateSearchFilters(Class objectTypeClass, String oid, Task task, OperationResult parentResult) throws SchemaException, ObjectNotFoundException, ObjectAlreadyExistsException { - OperationResult result = parentResult.createSubresult(CLASS_NAME_WITH_DOT+"reevaluateSearchFilters"); - try { - PrismObject storedObject = cacheRepositoryService.getObject(objectTypeClass, oid, null, result); - PrismObject updatedObject = storedObject.clone(); - ModelImplUtils.resolveReferences(updatedObject, cacheRepositoryService, false, true, EvaluationTimeType.IMPORT, true, prismContext, result); - ObjectDelta delta = storedObject.diff(updatedObject); - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("reevaluateSearchFilters found delta: {}", delta.debugDump()); - } - if (!delta.isEmpty()) { - try { - cacheRepositoryService.modifyObject(objectTypeClass, oid, delta.getModifications(), result); - task.recordObjectActionExecuted(updatedObject, ChangeType.MODIFY, null); - } catch (Throwable t) { - task.recordObjectActionExecuted(updatedObject, ChangeType.MODIFY, t); - throw t; - } - } - result.recordSuccess(); - } catch (SchemaException|ObjectNotFoundException|ObjectAlreadyExistsException|RuntimeException e) { - result.recordFatalError("Couldn't reevaluate search filters: "+e.getMessage(), e); - throw e; - } - } - - @Override - public void recompute(Class type, String oid, Task task, OperationResult parentResult) throws SchemaException, PolicyViolationException, ExpressionEvaluationException, ObjectNotFoundException, ObjectAlreadyExistsException, CommunicationException, ConfigurationException, SecurityViolationException { - ModelExecuteOptions options = ModelExecuteOptions.createReconcile(); - recompute(type, oid, options, task, parentResult); - } - - @Override - public void recompute(Class type, String oid, ModelExecuteOptions options, Task task, OperationResult parentResult) throws SchemaException, PolicyViolationException, ExpressionEvaluationException, ObjectNotFoundException, ObjectAlreadyExistsException, CommunicationException, ConfigurationException, SecurityViolationException { - - OperationResult result = parentResult.createMinorSubresult(RECOMPUTE); - result.addParam(OperationResult.PARAM_OID, oid); - result.addParam(OperationResult.PARAM_TYPE, type); - - enterModelMethod(); - - try { - - ModelImplUtils.clearRequestee(task); - PrismObject focus = objectResolver.getObject(type, oid, null, task, result).asPrismContainer(); - - LOGGER.debug("Recomputing {}", focus); - - LensContext lensContext = contextFactory.createRecomputeContext(focus, options, task, result); - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Recomputing {}, context:\n{}", focus, lensContext.debugDump()); - } - clockwork.run(lensContext, task, result); - - result.computeStatus(); - - LOGGER.trace("Recomputing of {}: {}", focus, result.getStatus()); - - result.cleanupResult(); - - } catch (ExpressionEvaluationException | SchemaException | PolicyViolationException | ObjectNotFoundException | - ObjectAlreadyExistsException | CommunicationException | ConfigurationException | SecurityViolationException | - RuntimeException | Error e) { - ModelImplUtils.recordFatalError(result, e); - throw e; - - } catch (PreconditionViolationException e) { - ModelImplUtils.recordFatalError(result, e); - // TODO: Temporary fix for 3.6.1 - // We do not want to propagate PreconditionViolationException to model API as that might break compatiblity - // ... and we do not really need that in 3.6.1 - // TODO: expose PreconditionViolationException in 3.7 - throw new SystemException(e); - - } finally { - exitModelMethod(); - } - } - - private void applyDefinitions(Collection> deltas, ModelExecuteOptions options, - Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, ExpressionEvaluationException { - for(ObjectDelta delta: deltas) { - Class type = delta.getObjectTypeClass(); - if (delta.hasCompleteDefinition()) { - continue; - } - if (type == ResourceType.class || ShadowType.class.isAssignableFrom(type)) { - try { - provisioning.applyDefinition(delta, task, result); - } catch (SchemaException | ObjectNotFoundException | CommunicationException | ConfigurationException | ExpressionEvaluationException e) { - if (ModelExecuteOptions.isRaw(options)) { - ModelImplUtils.recordPartialError(result, e); - // just go on, this is raw, we need to continue even without complete schema - } else { - ModelImplUtils.recordFatalError(result, e); - throw e; - } - } - } else { - PrismObjectDefinition objDef = prismContext.getSchemaRegistry().findObjectDefinitionByCompileTimeClass(delta.getObjectTypeClass()); - if (objDef == null) { - throw new SchemaException("No definition for delta object type class: " + delta.getObjectTypeClass()); - } - boolean tolerateNoDefinition = ModelExecuteOptions.isRaw(options); - delta.applyDefinitionIfPresent(objDef, tolerateNoDefinition); - } - } - } - - @Override - public SearchResultList> searchObjects(Class type, ObjectQuery query, - Collection> rawOptions, Task task, OperationResult parentResult) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { - - Validate.notNull(type, "Object type must not be null."); - Validate.notNull(parentResult, "Operation result must not be null."); - if (query != null) { - ModelImplUtils.validatePaging(query.getPaging()); - } - - OP_LOGGER.trace("MODEL OP enter searchObjects({},{},{})", type.getSimpleName(), query, rawOptions); - - OperationResult result = parentResult.createSubresult(SEARCH_OBJECTS); - result.addParam(OperationResult.PARAM_TYPE, type); - result.addParam(OperationResult.PARAM_QUERY, query); - - Collection> options = preProcessOptionsSecurity(rawOptions, task, result); - GetOperationOptions rootOptions = SelectorOptions.findRootOptions(options); - - ObjectTypes.ObjectManager searchProvider = ObjectTypes.getObjectManagerForClass(type); - if (searchProvider == null || searchProvider == ObjectTypes.ObjectManager.MODEL || GetOperationOptions.isRaw(rootOptions)) { - searchProvider = ObjectTypes.ObjectManager.REPOSITORY; - } - result.addArbitraryObjectAsParam("searchProvider", searchProvider); - - ObjectQuery processedQuery = preProcessQuerySecurity(type, query, rootOptions, task, result); - if (isFilterNone(processedQuery, result)) { - return new SearchResultList<>(new ArrayList<>()); - } - - enterModelMethod(); // outside try-catch because if this ends with an exception, cache is not entered yet - SearchResultList> list; - try { - logQuery(processedQuery); - - try { - if (GetOperationOptions.isRaw(rootOptions)) { // MID-2218 - QNameUtil.setTemporarilyTolerateUndeclaredPrefixes(true); - } - switch (searchProvider) { - case REPOSITORY: - list = cacheRepositoryService.searchObjects(type, processedQuery, options, result); - break; - case PROVISIONING: - list = provisioning.searchObjects(type, processedQuery, options, task, result); - break; - case TASK_MANAGER: - list = taskManager.searchObjects(type, processedQuery, options, result); - break; - default: - throw new AssertionError("Unexpected search provider: " + searchProvider); - } - result.computeStatus(); - result.cleanupResult(); - } catch (CommunicationException | ConfigurationException | SchemaException | SecurityViolationException | RuntimeException | ObjectNotFoundException e) { - processSearchException(e, rootOptions, searchProvider, result); - throw e; - } finally { - QNameUtil.setTemporarilyTolerateUndeclaredPrefixes(false); - if (LOGGER.isTraceEnabled()) { - LOGGER.trace(result.dump(false)); - } - } - - if (list == null) { - list = new SearchResultList<>(new ArrayList>()); - } - - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Basic search returned {} results (before hooks, security, etc.)", list.size()); - } - - for (PrismObject object : list) { - if (hookRegistry != null) { - for (ReadHook hook : hookRegistry.getAllReadHooks()) { - hook.invoke(object, options, task, result); - } - } - executeResolveOptions(object.asObjectable(), options, task, result); - } - - // postprocessing objects that weren't handled by their correct provider (e.g. searching for ObjectType, and retrieving tasks, resources, shadows) - // currently only resources and shadows are handled in this way - // TODO generalize this approach somehow (something like "postprocess" in task/provisioning interface) - if (searchProvider == ObjectTypes.ObjectManager.REPOSITORY && !GetOperationOptions.isRaw(rootOptions)) { - for (PrismObject object : list) { - if (object.asObjectable() instanceof ResourceType || object.asObjectable() instanceof ShadowType) { - provisioning.applyDefinition(object, task, result); - } - } - } - // better to use cache here (MID-4059) - schemaTransformer.applySchemasAndSecurityToObjects(list, rootOptions, options, null, task, result); - - } finally { - exitModelMethod(); - } - - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Final search returned {} results (after hooks, security and all other processing)", list.size()); - } - - // TODO: log errors - - if (OP_LOGGER.isDebugEnabled()) { - OP_LOGGER.debug("MODEL OP exit searchObjects({},{},{}): {}", type.getSimpleName(), query, rawOptions, list.shortDump()); - } - if (OP_LOGGER.isTraceEnabled()) { - OP_LOGGER.trace("MODEL OP exit searchObjects({},{},{}): {}\n{}", type.getSimpleName(), query, rawOptions, list.shortDump(), - DebugUtil.debugDump(list.getList(), 1)); - } - - return list; - } - - private class ContainerOperationContext { - final boolean isCertCase; - final boolean isCaseMgmtWorkItem; - final ObjectTypes.ObjectManager manager; - final ObjectQuery refinedQuery; - - // TODO: task and result here are ugly and probably wrong - ContainerOperationContext(Class type, ObjectQuery query, Task task, OperationResult result) throws SchemaException, SecurityViolationException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException { - isCertCase = AccessCertificationCaseType.class.equals(type); - isCaseMgmtWorkItem = CaseWorkItemType.class.equals(type); - - if (!isCertCase && !isCaseMgmtWorkItem) { - throw new UnsupportedOperationException("searchContainers/countContainers methods are currently supported only for AccessCertificationCaseType and CaseWorkItemType classes"); - } - - if (isCertCase) { - refinedQuery = preProcessSubobjectQuerySecurity(AccessCertificationCaseType.class, AccessCertificationCampaignType.class, query, task, result); - manager = ObjectTypes.ObjectManager.REPOSITORY; - } else //noinspection ConstantConditions - if (isCaseMgmtWorkItem) { - refinedQuery = query; // TODO - manager = ObjectTypes.ObjectManager.REPOSITORY; - } else { - throw new IllegalStateException(); - } - } - } - - @Override - public SearchResultList searchContainers( - Class type, ObjectQuery query, Collection> rawOptions, - Task task, OperationResult parentResult) throws SchemaException, SecurityViolationException, ConfigurationException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException { - - Validate.notNull(type, "Container value type must not be null."); - Validate.notNull(parentResult, "Result type must not be null."); - if (query != null) { - ModelImplUtils.validatePaging(query.getPaging()); - } - - final OperationResult result = parentResult.createSubresult(SEARCH_CONTAINERS); - result.addParam(OperationResult.PARAM_TYPE, type); - result.addParam(OperationResult.PARAM_QUERY, query); - - final ContainerOperationContext ctx = new ContainerOperationContext<>(type, query, task, result); - - Collection> options = preProcessOptionsSecurity(rawOptions, task, result); - final GetOperationOptions rootOptions = SelectorOptions.findRootOptions(options); - - query = ctx.refinedQuery; - - if (isFilterNone(query, result)) { - return new SearchResultList<>(new ArrayList<>()); - } - - enterModelMethod(); // outside try-catch because if this ends with an exception, cache is not entered yet - SearchResultList list; - try { - logQuery(query); - - try { - if (GetOperationOptions.isRaw(rootOptions)) { // MID-2218 - QNameUtil.setTemporarilyTolerateUndeclaredPrefixes(true); - } - //noinspection SwitchStatementWithTooFewBranches - switch (ctx.manager) { - case REPOSITORY: list = cacheRepositoryService.searchContainers(type, query, options, result); break; - default: throw new IllegalStateException(); - } - result.computeStatus(); - result.cleanupResult(); - } catch (SchemaException|RuntimeException e) { - processSearchException(e, rootOptions, ctx.manager, result); - throw e; - } finally { - QNameUtil.setTemporarilyTolerateUndeclaredPrefixes(false); - if (LOGGER.isTraceEnabled()) { - LOGGER.trace(result.dump(false)); - } - } - - if (list == null) { - list = new SearchResultList<>(new ArrayList<>()); - } - - for (T object : list) { - // TODO implement read hook, if necessary - executeResolveOptions(object, options, task, result); - } - } finally { - exitModelMethod(); - } - - if (ctx.isCertCase) { - list = schemaTransformer.applySchemasAndSecurityToContainers(list, AccessCertificationCampaignType.class, - AccessCertificationCampaignType.F_CASE, rootOptions, options, null, task, result); - } else if (ctx.isCaseMgmtWorkItem) { - // TODO implement security post processing for CaseWorkItems - } else { - throw new IllegalStateException(); - } - - return list; - } - - @Override - public Integer countContainers( - Class type, ObjectQuery query, Collection> rawOptions, - Task task, OperationResult parentResult) throws SchemaException, SecurityViolationException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException { - - Validate.notNull(type, "Container value type must not be null."); - Validate.notNull(parentResult, "Result type must not be null."); - - final OperationResult result = parentResult.createSubresult(COUNT_CONTAINERS); - result.addParam(OperationResult.PARAM_TYPE, type); - result.addParam(OperationResult.PARAM_QUERY, query); - - final ContainerOperationContext ctx = new ContainerOperationContext<>(type, query, task, result); - - final Collection> options = preProcessOptionsSecurity(rawOptions, task, result); - final GetOperationOptions rootOptions = SelectorOptions.findRootOptions(options); - - query = ctx.refinedQuery; - - if (isFilterNone(query, result)) { - return 0; - } - - enterModelMethod(); // outside try-catch because if this ends with an exception, cache is not entered yet - Integer count; - try { - - logQuery(query); - - try { - //noinspection SwitchStatementWithTooFewBranches - switch (ctx.manager) { - case REPOSITORY: count = cacheRepositoryService.countContainers(type, query, options, result); break; - default: throw new IllegalStateException(); - } - result.computeStatus(); - result.cleanupResult(); - } catch (RuntimeException e) { - processSearchException(e, rootOptions, ctx.manager, result); - throw e; - } finally { - if (LOGGER.isTraceEnabled()) { - LOGGER.trace(result.dump(false)); - } - } - } finally { - exitModelMethod(); - } - - return count; - } - -// // TODO - fix this temporary implementation (perhaps by storing 'groups' in user context on logon) -// // TODO: currently we check only the direct assignments, we need to implement more complex mechanism -// public List getGroupsForUser(UserType user) { -// List retval = new ArrayList<>(); -// for (AssignmentType assignmentType : user.getAssignmentNew()) { -// ObjectReferenceType ref = assignmentType.getTargetRef(); -// if (ref != null) { -// retval.add(ref.clone().asReferenceValue()); -// } -// } -// return retval; -// } - - private ObjectQuery preProcessWorkItemSecurity(ObjectQuery query) throws SchemaException, SecurityViolationException { - // TODO uncomment the following, after our "query interpreter" will be able to interpret OR-clauses - return query; - -// if (securityEnforcer.isAuthorized(ModelAuthorizationAction.READ_ALL_WORK_ITEMS.getUrl(), null, null, null, null, null)) { -// return query; -// } -// ObjectFilter filter = query != null ? query.getFilter() : null; -// UserType currentUser = securityEnforcer.getPrincipal().getUser(); -// -// ObjectFilter secFilter = QueryBuilder.queryFor(CaseWorkItemType.class, getPrismContext()) -// .item(CaseWorkItemType.F_CANDIDATE_ROLES_REF).ref(getGroupsForUser(currentUser)) -// .or().item(CaseWorkItemType.F_ASSIGNEE_REF).ref(ObjectTypeUtil.createObjectRef(currentUser).asReferenceValue()) -// .buildFilter(); -// -// return updateObjectQuery(query, -// filter != null ? AndFilter.createAnd(filter, secFilter) : secFilter); - } - - protected boolean isFilterNone(ObjectQuery query, OperationResult result) { - if (query != null && query.getFilter() != null && query.getFilter() instanceof NoneFilter) { - LOGGER.trace("Security denied the search"); - result.recordStatus(OperationResultStatus.NOT_APPLICABLE, "Denied"); - return true; - } - return false; - } - - protected void logQuery(ObjectQuery query) { - if (!LOGGER.isTraceEnabled()) { - return; - } - if (query != null) { - if (query.getPaging() == null) { - LOGGER.trace("Searching objects with null paging. Processed query:\n{}", query.debugDump(1)); - } else { - LOGGER.trace("Searching objects from {} to {} ordered {} by {}. Processed query:\n{}", - query.getPaging().getOffset(), query.getPaging().getMaxSize(), - query.getPaging().getDirection(), query.getPaging().getOrderBy(), - query.debugDump(1)); - } - } else { - LOGGER.trace("Searching objects with null paging and null (processed) query."); - } - } - - @Override - public SearchResultMetadata searchObjectsIterative(Class type, ObjectQuery query, - final ResultHandler handler, final Collection> rawOptions, - final Task task, OperationResult parentResult) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { - - Validate.notNull(type, "Object type must not be null."); - Validate.notNull(parentResult, "Result type must not be null."); - if (query != null) { - ModelImplUtils.validatePaging(query.getPaging()); - } - - OP_LOGGER.trace("MODEL OP enter searchObjectsIterative({},{},{})", type.getSimpleName(), query, rawOptions); - - final OperationResult result = parentResult.createSubresult(SEARCH_OBJECTS); - result.addParam(OperationResult.PARAM_QUERY, query); - - final Collection> options = preProcessOptionsSecurity(rawOptions, task, result); - final GetOperationOptions rootOptions = SelectorOptions.findRootOptions(options); - ObjectTypes.ObjectManager searchProvider = ObjectTypes.getObjectManagerForClass(type); - if (searchProvider == null || searchProvider == ObjectTypes.ObjectManager.MODEL || GetOperationOptions.isRaw(rootOptions)) { - searchProvider = ObjectTypes.ObjectManager.REPOSITORY; - } - result.addArbitraryObjectAsParam("searchProvider", searchProvider); - - ObjectQuery processedQuery = preProcessQuerySecurity(type, query, rootOptions, task, result); - if (isFilterNone(processedQuery, result)) { - LOGGER.trace("Skipping search because filter is NONE"); - return null; - } - - ResultHandler internalHandler = (object, parentResult1) -> { - try { - object = object.cloneIfImmutable(); - if (hookRegistry != null) { - for (ReadHook hook : hookRegistry.getAllReadHooks()) { - hook.invoke(object, options, task, result); // TODO result or parentResult??? [med] - } - } - executeResolveOptions(object.asObjectable(), options, task, result); - schemaTransformer.applySchemasAndSecurity(object, rootOptions, options, null, task, parentResult1); - } catch (SchemaException | ObjectNotFoundException | SecurityViolationException | ExpressionEvaluationException - | CommunicationException | ConfigurationException ex) { - parentResult1.recordFatalError(ex); - throw new SystemException(ex.getMessage(), ex); - } - - OP_LOGGER.debug("MODEL OP handle searchObjects({},{},{}): {}", type.getSimpleName(), query, rawOptions, object); - if (OP_LOGGER.isTraceEnabled()) { - OP_LOGGER.trace("MODEL OP handle searchObjects({},{},{}):\n{}", type.getSimpleName(), query, rawOptions, object.debugDump(1)); - } - - return handler.handle(object, parentResult1); - }; - - SearchResultMetadata metadata; - try { - enterModelMethodNoRepoCache(); // skip using cache to avoid potentially many objects there (MID-4615, MID-4959) - logQuery(processedQuery); - - try { - switch (searchProvider) { - case REPOSITORY: metadata = cacheRepositoryService.searchObjectsIterative(type, processedQuery, internalHandler, options, true, result); break; - case PROVISIONING: metadata = provisioning.searchObjectsIterative(type, processedQuery, options, internalHandler, task, result); break; - case TASK_MANAGER: metadata = taskManager.searchObjectsIterative(type, processedQuery, options, internalHandler, result); break; - default: throw new AssertionError("Unexpected search provider: " + searchProvider); - } - result.computeStatusIfUnknown(); - result.cleanupResult(); - } catch (CommunicationException | ConfigurationException | ObjectNotFoundException | SchemaException | SecurityViolationException | ExpressionEvaluationException | RuntimeException | Error e) { - processSearchException(e, rootOptions, searchProvider, result); - throw e; - } finally { - if (LOGGER.isTraceEnabled()) { - LOGGER.trace(result.dump(false)); - } - } - } finally { - exitModelMethodNoRepoCache(); - } - - // TODO: log errors - - if (OP_LOGGER.isDebugEnabled()) { - OP_LOGGER.debug("MODEL OP exit searchObjects({},{},{}): {}", type.getSimpleName(), query, rawOptions, metadata); - } - - return metadata; - } - - private void processSearchException(Throwable e, GetOperationOptions rootOptions, - ObjectTypes.ObjectManager searchProvider, OperationResult result) { - String message; - switch (searchProvider) { - case REPOSITORY: message = "Couldn't search objects in repository"; break; - case PROVISIONING: message = "Couldn't search objects in provisioning"; break; - case TASK_MANAGER: message = "Couldn't search objects in task manager"; break; - default: message = "Couldn't search objects"; break; // should not occur - } - LoggingUtils.logUnexpectedException(LOGGER, message, e); - result.recordFatalError(message, e); - result.cleanupResult(e); - } - - @Override - public Integer countObjects(Class type, ObjectQuery query, - Collection> rawOptions, Task task, OperationResult parentResult) - throws SchemaException, ObjectNotFoundException, ConfigurationException, SecurityViolationException, CommunicationException, ExpressionEvaluationException { - - OperationResult result = parentResult.createMinorSubresult(COUNT_OBJECTS); - result.addParam(OperationResult.PARAM_QUERY, query); - - enterModelMethod(); // outside try-catch because if this ends with an exception, cache is not entered yet - Integer count; - try { - - Collection> options = preProcessOptionsSecurity(rawOptions, task, result); - GetOperationOptions rootOptions = SelectorOptions.findRootOptions(options); - - ObjectQuery processedQuery = preProcessQuerySecurity(type, query, rootOptions, task, result); - if (isFilterNone(processedQuery, result)) { - LOGGER.trace("Skipping count because filter is NONE"); - return 0; - } - - ObjectTypes.ObjectManager objectManager = ObjectTypes.getObjectManagerForClass(type); - if (GetOperationOptions.isRaw(rootOptions) || objectManager == null || objectManager == ObjectTypes.ObjectManager.MODEL) { - objectManager = ObjectTypes.ObjectManager.REPOSITORY; - } - switch (objectManager) { - case PROVISIONING: - count = provisioning.countObjects(type, processedQuery, options, task, parentResult); - break; - case REPOSITORY: - count = cacheRepositoryService.countObjects(type, processedQuery, options, parentResult); - break; - case TASK_MANAGER: - count = taskManager.countObjects(type, processedQuery, parentResult); - break; - default: throw new AssertionError("Unexpected objectManager: " + objectManager); - } - } catch (ConfigurationException | SecurityViolationException | SchemaException | ObjectNotFoundException | CommunicationException | ExpressionEvaluationException | RuntimeException | Error e) { - ModelImplUtils.recordFatalError(result, e); - throw e; - } finally { - exitModelMethod(); - } - - result.computeStatus(); - result.cleanupResult(); - return count; - - } - - @Override - @Deprecated - public PrismObject findShadowOwner(String accountOid, Task task, OperationResult parentResult) - throws ObjectNotFoundException, SecurityViolationException, SchemaException, ConfigurationException, ExpressionEvaluationException, CommunicationException { - Validate.notEmpty(accountOid, "Account oid must not be null or empty."); - Validate.notNull(parentResult, "Result type must not be null."); - - enterModelMethod(); - - PrismObject user; - - LOGGER.trace("Listing account shadow owner for account with oid {}.", new Object[]{accountOid}); - - OperationResult result = parentResult.createSubresult(LIST_ACCOUNT_SHADOW_OWNER); - result.addParam("accountOid", accountOid); - - try { - - user = cacheRepositoryService.listAccountShadowOwner(accountOid, result); - result.recordSuccess(); - } catch (ObjectNotFoundException ex) { - LoggingUtils.logException(LOGGER, "Account with oid {} doesn't exists", ex, accountOid); - result.recordFatalError("Account with oid '" + accountOid + "' doesn't exists", ex); - throw ex; - } catch (RuntimeException | Error ex) { - LoggingUtils.logException(LOGGER, "Couldn't list account shadow owner from repository" - + " for account with oid {}", ex, accountOid); - result.recordFatalError("Couldn't list account shadow owner for account with oid '" - + accountOid + "'.", ex); - throw ex; - } finally { - if (LOGGER.isTraceEnabled()) { - LOGGER.trace(result.dump(false)); - } - exitModelMethod(); - result.cleanupResult(); - } - - if (user != null) { - try { - user = user.cloneIfImmutable(); - schemaTransformer.applySchemasAndSecurity(user, null, null,null, task, result); - } catch (SchemaException | SecurityViolationException | ConfigurationException | - ExpressionEvaluationException | ObjectNotFoundException | CommunicationException ex) { - LoggingUtils.logException(LOGGER, "Couldn't list account shadow owner from repository" - + " for account with oid {}", ex, accountOid); - result.recordFatalError("Couldn't list account shadow owner for account with oid '" - + accountOid + "'.", ex); - throw ex; - } - } - - return user; - } - - @Override - public PrismObject searchShadowOwner(String shadowOid, Collection> rawOptions, Task task, OperationResult parentResult) - throws ObjectNotFoundException, SecurityViolationException, SchemaException, ConfigurationException, ExpressionEvaluationException, CommunicationException { - Validate.notEmpty(shadowOid, "Account oid must not be null or empty."); - Validate.notNull(parentResult, "Result type must not be null."); - - enterModelMethod(); - - PrismObject focus; - - LOGGER.trace("Listing account shadow owner for account with oid {}.", new Object[]{shadowOid}); - - OperationResult result = parentResult.createSubresult(LIST_ACCOUNT_SHADOW_OWNER); - result.addParam("shadowOid", shadowOid); - - try { - Collection> options = preProcessOptionsSecurity(rawOptions, task, result); - focus = cacheRepositoryService.searchShadowOwner(shadowOid, options, result); - result.recordSuccess(); - } catch (RuntimeException | Error ex) { - LoggingUtils.logException(LOGGER, "Couldn't list account shadow owner from repository" - + " for account with oid {}", ex, shadowOid); - result.recordFatalError("Couldn't list account shadow owner for account with oid '" - + shadowOid + "'.", ex); - throw ex; - } finally { - if (LOGGER.isTraceEnabled()) { - LOGGER.trace(result.dump(false)); - } - exitModelMethod(); - result.cleanupResult(); - } - - if (focus != null) { - try { - focus = focus.cloneIfImmutable(); - schemaTransformer.applySchemasAndSecurity(focus, null, null, null, task, result); - } catch (SchemaException | SecurityViolationException | ConfigurationException - | ObjectNotFoundException | CommunicationException ex) { - LoggingUtils.logException(LOGGER, "Couldn't list account shadow owner from repository" - + " for account with oid {}", ex, shadowOid); - result.recordFatalError("Couldn't list account shadow owner for account with oid '" - + shadowOid + "'.", ex); - throw ex; - } - } - - return focus; - } - - @Deprecated - @Override - public List> listResourceObjects(String resourceOid, - QName objectClass, ObjectPaging paging, Task task, OperationResult parentResult) throws SchemaException, - ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { - Validate.notEmpty(resourceOid, "Resource oid must not be null or empty."); - Validate.notNull(objectClass, "Object type must not be null."); - Validate.notNull(paging, "Paging must not be null."); - Validate.notNull(parentResult, "Result type must not be null."); - ModelImplUtils.validatePaging(paging); - - enterModelMethod(); - - List> list; - - try { - LOGGER.trace( - "Listing resource objects {} from resource, oid {}, from {} to {} ordered {} by {}.", - objectClass, resourceOid, paging.getOffset(), paging.getMaxSize(), - paging.getOrderBy(), paging.getDirection()); - - OperationResult result = parentResult.createSubresult(LIST_RESOURCE_OBJECTS); - result.addParam("resourceOid", resourceOid); - result.addParam("objectType", objectClass); - - try { - - list = provisioning.listResourceObjects(resourceOid, objectClass, paging, task, result); - - } catch (SchemaException | CommunicationException | ConfigurationException | SecurityViolationException | ObjectNotFoundException | ExpressionEvaluationException | RuntimeException | Error ex) { - ModelImplUtils.recordFatalError(result, ex); - throw ex; - } - result.recordSuccess(); - result.cleanupResult(); - - if (list == null) { - list = new ArrayList<>(); - } - } finally { - exitModelMethod(); - } - return list; - } - - // This returns OperationResult instead of taking it as in/out argument. - // This is different - // from the other methods. The testResource method is not using - // OperationResult to track its own - // execution but rather to track the execution of resource tests (that in - // fact happen in provisioning). - @Override - public OperationResult testResource(String resourceOid, Task task) throws ObjectNotFoundException { - Validate.notEmpty(resourceOid, "Resource oid must not be null or empty."); - enterModelMethod(); - LOGGER.trace("Testing resource OID: {}", new Object[]{resourceOid}); - - OperationResult testResult; - try { - testResult = provisioning.testResource(resourceOid, task); - } catch (ObjectNotFoundException ex) { - LOGGER.error("Error testing resource OID: {}: Object not found: {} ", resourceOid, ex.getMessage(), ex); - RepositoryCache.exit(); - throw ex; - } catch (SystemException ex) { - LOGGER.error("Error testing resource OID: {}: {} ", resourceOid, ex.getMessage(), ex); - RepositoryCache.exit(); - throw ex; - } catch (Exception ex) { - LOGGER.error("Error testing resource OID: {}: {} ", resourceOid, ex.getMessage(), ex); - RepositoryCache.exit(); - throw new SystemException(ex.getMessage(), ex); - } finally { - exitModelMethod(); - } - - if (testResult != null) { - LOGGER.debug("Finished testing resource OID: {}, result: {} ", resourceOid, - testResult.getStatus()); - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Test result:\n{}", testResult.dump(false)); - } - } else { - LOGGER.error("Test resource returned null result"); - } - return testResult; - } - - // Note: The result is in the task. No need to pass it explicitly - @Override - public void importFromResource(String resourceOid, QName objectClass, Task task, - OperationResult parentResult) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { - Validate.notEmpty(resourceOid, "Resource oid must not be null or empty."); - Validate.notNull(objectClass, "Object class must not be null."); - Validate.notNull(task, "Task must not be null."); - enterModelMethod(); - LOGGER.trace("Launching import from resource with oid {} for object class {}.", new Object[]{ - resourceOid, objectClass}); - - OperationResult result = parentResult.createSubresult(IMPORT_ACCOUNTS_FROM_RESOURCE); - result.addParam("resourceOid", resourceOid); - result.addParam("objectClass", objectClass); - result.addArbitraryObjectAsParam(OperationResult.PARAM_TASK, task); - // TODO: add context to the result - - // Fetch resource definition from the repo/provisioning - ResourceType resource; - try { - resource = getObject(ResourceType.class, resourceOid, null, task, result).asObjectable(); - - if (resource.getSynchronization() == null || resource.getSynchronization().getObjectSynchronization().isEmpty()) { - OperationResult subresult = result.createSubresult(IMPORT_ACCOUNTS_FROM_RESOURCE+".check"); - subresult.recordWarning("No synchronization settings in "+resource+", import will probably do nothing"); - LOGGER.warn("No synchronization settings in "+resource+", import will probably do nothing"); - } else { - ObjectSynchronizationType syncType = resource.getSynchronization().getObjectSynchronization().iterator().next(); - if (syncType.isEnabled() != null && !syncType.isEnabled()) { - OperationResult subresult = result.createSubresult(IMPORT_ACCOUNTS_FROM_RESOURCE+".check"); - subresult.recordWarning("Synchronization is disabled for "+resource+", import will probably do nothing"); - LOGGER.warn("Synchronization is disabled for "+resource+", import will probably do nothing"); - } - } - - result.recordStatus(OperationResultStatus.IN_PROGRESS, "Task running in background"); - - importAccountsFromResourceTaskHandler.launch(resource, objectClass, task, result); - - // The launch should switch task to asynchronous. It is in/out, so no - // other action is needed - - if (!task.isAsynchronous()) { - result.recordSuccess(); - } - - result.cleanupResult(); - - } catch (ObjectNotFoundException | CommunicationException | ConfigurationException | SecurityViolationException | ExpressionEvaluationException | RuntimeException | Error ex) { - ModelImplUtils.recordFatalError(result, ex); - throw ex; - } finally { - exitModelMethod(); - } - - } - - @Override - public void importFromResource(String shadowOid, Task task, OperationResult parentResult) - throws ObjectNotFoundException, SchemaException, CommunicationException, - ConfigurationException, SecurityViolationException, ExpressionEvaluationException { - Validate.notNull(shadowOid, "Shadow OID must not be null."); - Validate.notNull(task, "Task must not be null."); - enterModelMethod(); - LOGGER.trace("Launching importing shadow {} from resource.", shadowOid); - - OperationResult result = parentResult.createSubresult(IMPORT_ACCOUNTS_FROM_RESOURCE); - result.addParam(OperationResult.PARAM_OID, shadowOid); - result.addArbitraryObjectAsParam(OperationResult.PARAM_TASK, task); - // TODO: add context to the result - - try { - boolean wasOk = importAccountsFromResourceTaskHandler.importSingleShadow(shadowOid, task, result); - - if (wasOk) { - result.recordSuccess(); - } else { - // the error should be in the result already, compute should reveal that to the top-level - result.computeStatus(); - } - - - result.cleanupResult(); - - } catch (ObjectNotFoundException | CommunicationException | ConfigurationException | SecurityViolationException | ExpressionEvaluationException| RuntimeException | Error ex) { - ModelImplUtils.recordFatalError(result, ex); - throw ex; - } finally { - exitModelMethod(); - } - - } - - @Override - public void importObjectsFromFile(File input, ImportOptionsType options, Task task, - OperationResult parentResult) throws FileNotFoundException { - OperationResult result = parentResult.createSubresult(IMPORT_OBJECTS_FROM_FILE); - FileInputStream fis = null; - try { - fis = new FileInputStream(input); - } catch (FileNotFoundException e) { - IOUtils.closeQuietly(fis); - String msg = "Error reading from file " + input + ": " + e.getMessage(); - result.recordFatalError(msg, e); - throw e; - } - try { - importObjectsFromStream(fis, PrismContext.LANG_XML, options, task, parentResult); - } catch (RuntimeException e) { - result.recordFatalError(e); - throw e; - } finally { - try { - fis.close(); - } catch (IOException e) { - LOGGER.error("Error closing file " + input + ": " + e.getMessage(), e); - } - } - result.computeStatus(); - } - - @Override - public void importObjectsFromStream(InputStream input, String language, ImportOptionsType options, Task task, OperationResult parentResult) { - enterModelMethod(); - OperationResult result = parentResult.createSubresult(IMPORT_OBJECTS_FROM_STREAM); - result.addArbitraryObjectAsParam(OperationResult.PARAM_OPTIONS, options); - result.addParam(OperationResult.PARAM_LANGUAGE, language); - try { - objectImporter.importObjects(input, language, options, task, result); - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Import result:\n{}", result.debugDump()); - } - // No need to compute status. The validator inside will do it. - // result.computeStatus("Couldn't import object from input stream."); - } catch (RuntimeException e) { - result.recordFatalError(e.getMessage(), e); // shouldn't really occur - } finally { - exitModelMethod(); - } - result.cleanupResult(); - } - - /* - * (non-Javadoc) - * - * @see - * com.evolveum.midpoint.model.api.ModelService#discoverConnectors(com.evolveum - * .midpoint.xml.ns._public.common.common_1.ConnectorHostType, - * com.evolveum.midpoint.common.result.OperationResult) - */ - @Override - public Set discoverConnectors(ConnectorHostType hostType, Task task, OperationResult parentResult) - throws CommunicationException, SecurityViolationException, SchemaException, ConfigurationException, ObjectNotFoundException, ExpressionEvaluationException { - enterModelMethod(); - OperationResult result = parentResult.createSubresult(DISCOVER_CONNECTORS); - Set discoverConnectors; - try { - discoverConnectors = provisioning.discoverConnectors(hostType, result); - } catch (CommunicationException | RuntimeException | Error e) { - result.recordFatalError(e.getMessage(), e); - exitModelMethod(); - throw e; - } - List connectorList = new ArrayList<>(discoverConnectors); - schemaTransformer.applySchemasAndSecurityToObjectTypes(connectorList, null, null,null, task, result); - result.computeStatus("Connector discovery failed"); - exitModelMethod(); - result.cleanupResult(); - return new HashSet<>(connectorList); - } - - - /* - * (non-Javadoc) - * - * @see - * com.evolveum.midpoint.model.api.ModelService#initialize(com.evolveum. - * midpoint.common.result.OperationResult) - */ - @Override - public void postInit(OperationResult parentResult) { - systemObjectCache.invalidateCaches(); // necessary for testing situations where we re-import different system configurations with the same version (on system init) - - enterModelMethod(); - OperationResult result = parentResult.createSubresult(POST_INIT); - result.addContext(OperationResult.CONTEXT_IMPLEMENTATION_CLASS, ModelController.class); - - try { - // Repository service itself might have been initialized. - // But there are situations (e.g. in tests or after factory reset) in which only this method is called. - // So let's be conservative and rather execute repository postInit twice than zero times. - cacheRepositoryService.postInit(result); - } catch (SchemaException e) { - result.recordFatalError(e); - throw new SystemException(e.getMessage(), e); - } - - securityContextManager.setUserProfileService(focusProfileService); - - taskManager.postInit(result); - - // Initialize provisioning - provisioning.postInit(result); - - if (result.isUnknown()) { - result.computeStatus(); - } - - exitModelMethod(); - result.cleanupResult(); - } - - @Override - public void shutdown() { - - enterModelMethod(); - - provisioning.shutdown(); - -// taskManager.shutdown(); - - exitModelMethod(); - } - - @Override - public CompareResultType compareObject(PrismObject provided, - Collection> rawReadOptions, ModelCompareOptions compareOptions, - @NotNull List ignoreItems, Task task, OperationResult parentResult) - throws SchemaException, ObjectNotFoundException, SecurityViolationException, CommunicationException, - ConfigurationException, ExpressionEvaluationException { - Validate.notNull(provided, "Object must not be null or empty."); - Validate.notNull(parentResult, "Operation result must not be null."); - - OperationResult result = parentResult.createMinorSubresult(COMPARE_OBJECT); - result.addParam(OperationResult.PARAM_OID, provided.getOid()); - result.addParam(OperationResult.PARAM_NAME, provided.getName()); - result.addArbitraryObjectCollectionAsParam("readOptions", rawReadOptions); - result.addArbitraryObjectAsParam("compareOptions", compareOptions); - result.addArbitraryObjectCollectionAsParam("ignoreItems", ignoreItems); - - Collection> readOptions = preProcessOptionsSecurity(rawReadOptions, task, result); - - CompareResultType rv = new CompareResultType(); - - try { - boolean c2p = ModelCompareOptions.isComputeCurrentToProvided(compareOptions); - boolean p2c = ModelCompareOptions.isComputeProvidedToCurrent(compareOptions); - boolean returnC = ModelCompareOptions.isReturnCurrent(compareOptions); - boolean returnP = ModelCompareOptions.isReturnNormalized(compareOptions); - boolean ignoreOperational = ModelCompareOptions.isIgnoreOperationalItems(compareOptions); - - if (!c2p && !p2c && !returnC && !returnP) { - return rv; - } - PrismObject current = null; - if (c2p || p2c || returnC) { - current = fetchCurrentObject(provided.getCompileTimeClass(), provided.getOid(), provided.getName(), readOptions, task, result); - removeIgnoredItems(current, ignoreItems); - if (ignoreOperational) { - removeOperationalItems(current); - } - } - removeIgnoredItems(provided, ignoreItems); - if (ignoreOperational) { - removeOperationalItems(provided); - } - - if (c2p) { - rv.setCurrentToProvided(DeltaConvertor.toObjectDeltaType(DiffUtil.diff(current, provided))); - } - if (p2c) { - rv.setProvidedToCurrent(DeltaConvertor.toObjectDeltaType(DiffUtil.diff(provided, current))); - } - if (returnC && current != null) { - rv.setCurrentObject(current.asObjectable()); - } - if (returnP) { - rv.setNormalizedObject(provided.asObjectable()); - } - } finally { - result.computeStatus(); - result.cleanupResult(); - } - return rv; - } - - private void removeIgnoredItems(PrismObject object, List ignoreItems) { - if (object != null) { - object.getValue().removeItems(ignoreItems); - } - } - - private void removeOperationalItems(PrismObject object) { - if (object != null) { - object.getValue().removeOperationalItems(); - } - } - - private PrismObject fetchCurrentObject(Class type, String oid, PolyString name, - Collection> readOptions, Task task, - OperationResult result) - throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, - SecurityViolationException, ExpressionEvaluationException { - - if (readOptions == null) { - readOptions = new ArrayList<>(); - } - GetOperationOptions root = SelectorOptions.findRootOptions(readOptions); - if (root == null) { - readOptions.add(SelectorOptions.create(GetOperationOptions.createAllowNotFound())); - } else { - root.setAllowNotFound(true); - } - - if (oid != null) { - try { - return getObject(type, oid, readOptions, task, result); - } catch (ObjectNotFoundException e) { - return null; - } - } - if (name == null || name.getOrig() == null) { - throw new IllegalArgumentException("Neither OID nor name of the object is known."); - } - ObjectQuery nameQuery = prismContext.queryFor(type) - .item(ObjectType.F_NAME).eqPoly(name.getOrig()) - .build(); - List> objects = searchObjects(type, nameQuery, readOptions, task, result); - if (objects.isEmpty()) { - return null; - } else if (objects.size() == 1) { - return objects.get(0); - } else { - throw new SchemaException("More than 1 object of type " + type + " with the name of " + name + ": There are " + objects.size() + " of them."); - } - } - - private Collection> preProcessOptionsSecurity(Collection> options, Task task, OperationResult result) - throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException, SecurityViolationException { - GetOperationOptions rootOptions = SelectorOptions.findRootOptions(options); - if (GetOperationOptions.isAttachDiagData(rootOptions) && - !securityEnforcer.isAuthorized(AuthorizationConstants.AUTZ_ALL_URL, null, AuthorizationParameters.EMPTY, null, task, result)) { - Collection> reducedOptions = CloneUtil.cloneCollectionMembers(options); - SelectorOptions.findRootOptions(reducedOptions).setAttachDiagData(false); - return reducedOptions; - } else { - return options; - } - } - - private ObjectQuery preProcessQuerySecurity(Class objectType, ObjectQuery origQuery, GetOperationOptions rootOptions, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException, SecurityViolationException { - ObjectFilter origFilter = null; - if (origQuery != null) { - origFilter = origQuery.getFilter(); - } - AuthorizationPhaseType phase = null; - if (GetOperationOptions.isExecutionPhase(rootOptions)) { - phase = AuthorizationPhaseType.EXECUTION; - } - ObjectFilter secFilter = securityEnforcer.preProcessObjectFilter(ModelAuthorizationAction.AUTZ_ACTIONS_URLS_SEARCH, phase, objectType, null, origFilter, null, null, task, result); - return updateObjectQuery(origQuery, secFilter); - } - - // we expect that objectType is a direct parent of containerType - private ObjectQuery preProcessSubobjectQuerySecurity(Class containerType, Class objectType, ObjectQuery origQuery, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException, SecurityViolationException { - // Search containers is an operation on one object. Therefore even if it works with a search filter, it requires GET authorizations - ObjectFilter secParentFilter = securityEnforcer.preProcessObjectFilter(ModelAuthorizationAction.AUTZ_ACTIONS_URLS_GET, null, objectType, null, null, null, null, task, result); - if (secParentFilter == null || secParentFilter instanceof AllFilter) { - return origQuery; // no need to update the query - } - ObjectFilter secChildFilter; - if (secParentFilter instanceof NoneFilter) { - secChildFilter = FilterCreationUtil.createNone(prismContext); - } else { - ObjectFilter origChildFilter = origQuery != null ? origQuery.getFilter() : null; - ObjectFilter secChildFilterParentPart = prismContext.queryFactory().createExists(ItemName.fromQName(PrismConstants.T_PARENT), // fixme - containerType, prismContext, secParentFilter); - if (origChildFilter == null) { - secChildFilter = secChildFilterParentPart; - } else { - secChildFilter = prismContext.queryFactory().createAnd(origChildFilter, secChildFilterParentPart); - } - } - return updateObjectQuery(origQuery, secChildFilter); - } - - private ObjectQuery updateObjectQuery(ObjectQuery origQuery, ObjectFilter updatedFilter) { - if (origQuery != null) { - origQuery.setFilter(updatedFilter); - return origQuery; - } else if (updatedFilter == null) { - return null; - } else { - return getPrismContext().queryFactory().createQuery(updatedFilter); - } - } - - //region Task-related operations - - @Override - public boolean suspendTasks(Collection taskOids, long waitForStop, Task operationTask, OperationResult parentResult) throws SecurityViolationException, ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException { - authorizeTaskCollectionOperation(ModelAuthorizationAction.SUSPEND_TASK, taskOids, operationTask, parentResult); - return taskManager.suspendTasks(taskOids, waitForStop, parentResult); - } - - @Override - public boolean suspendTask(String taskOid, long waitForStop, Task operationTask, OperationResult parentResult) throws SecurityViolationException, ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException { - authorizeTaskOperation(ModelAuthorizationAction.SUSPEND_TASK, taskOid, operationTask, parentResult); - return taskManager.suspendTask(taskOid, waitForStop, parentResult); - } - - @Override - public boolean suspendTaskTree(String taskOid, long waitForStop, Task operationTask, OperationResult parentResult) throws SecurityViolationException, ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException { - authorizeTaskCollectionOperation(ModelAuthorizationAction.SUSPEND_TASK, singleton(taskOid), operationTask, parentResult); - return taskManager.suspendTaskTree(taskOid, waitForStop, parentResult); - } - - @Override - public void suspendAndDeleteTasks(Collection taskOids, long waitForStop, boolean alsoSubtasks, Task operationTask, OperationResult parentResult) throws SecurityViolationException, ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException { - List> taskRefs = new ArrayList<>(taskOids.size()); - - for (String taskOid : taskOids) { - PrismObject task = cacheRepositoryService.getObject(TaskType.class, taskOid, SelectorOptions.createCollection(GetOperationOptions.createRaw()), parentResult); - taskRefs.add(task); - } - - authorizeTaskCollectionOperation(ModelAuthorizationAction.DELETE, taskOids, operationTask, parentResult); - - for (PrismObject taskRef : taskRefs) { - auditTaskOperation(ObjectTypeUtil.createObjectRef(taskRef, SchemaConstants.ORG_DEFAULT).asReferenceValue(), AuditEventStage.REQUEST, operationTask, parentResult); - } - taskManager.suspendAndDeleteTasks(taskOids, waitForStop, alsoSubtasks, parentResult); - parentResult.computeStatusIfUnknown(); - for (PrismObject taskRef : taskRefs) { - auditTaskOperation(ObjectTypeUtil.createObjectRef(taskRef, SchemaConstants.ORG_DEFAULT).asReferenceValue(), AuditEventStage.EXECUTION, operationTask, parentResult); - } - } - - @Override - public void suspendAndDeleteTask(String taskOid, long waitForStop, boolean alsoSubtasks, Task operationTask, OperationResult parentResult) throws SecurityViolationException, ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException { - PrismObject task = cacheRepositoryService.getObject(TaskType.class, taskOid, SelectorOptions.createCollection(GetOperationOptions.createRaw()), parentResult); - authorizeTaskOperation(ModelAuthorizationAction.DELETE, task, operationTask, parentResult); - PrismReferenceValue taskRef = ObjectTypeUtil.createObjectRef(task, SchemaConstants.ORG_DEFAULT).asReferenceValue(); - auditTaskOperation(taskRef, AuditEventStage.REQUEST, operationTask, parentResult); - taskManager.suspendAndDeleteTask(taskOid, waitForStop, alsoSubtasks, parentResult); - auditTaskOperation(taskRef, AuditEventStage.EXECUTION, operationTask, parentResult); - } - - private void auditTaskOperation(PrismReferenceValue taskRef, AuditEventStage stage, Task operationTask, OperationResult parentResult) { - AuditEventRecord auditRecord = new AuditEventRecord(AuditEventType.DELETE_OBJECT, stage); - String requestIdentifier = ModelImplUtils.generateRequestIdentifier(); - auditRecord.setRequestIdentifier(requestIdentifier); - auditRecord.setTarget(taskRef); - ObjectDelta delta = prismContext.deltaFactory().object().createDeleteDelta(TaskType.class, taskRef.getOid()); - ObjectDeltaOperation odo = new ObjectDeltaOperation<>(delta, parentResult); - auditRecord.getDeltas().add(odo); - if (AuditEventStage.EXECUTION == stage) { - auditRecord.setOutcome(parentResult.getStatus()); - - } - auditHelper.audit(auditRecord, null, operationTask, parentResult); - } - - @Override - public void resumeTasks(Collection taskOids, Task operationTask, OperationResult parentResult) throws SecurityViolationException, ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException { - authorizeTaskCollectionOperation(ModelAuthorizationAction.RESUME_TASK, taskOids, operationTask, parentResult); - taskManager.resumeTasks(taskOids, parentResult); - } - - @Override - public void resumeTask(String taskOid, Task operationTask, OperationResult parentResult) throws SecurityViolationException, ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException { - authorizeTaskOperation(ModelAuthorizationAction.RESUME_TASK, taskOid, operationTask, parentResult); - taskManager.resumeTask(taskOid, parentResult); - } - - @Override - public void resumeTaskTree(String coordinatorOid, Task operationTask, OperationResult parentResult) throws SecurityViolationException, ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException { - authorizeTaskOperation(ModelAuthorizationAction.RESUME_TASK, coordinatorOid, operationTask, parentResult); - taskManager.resumeTaskTree(coordinatorOid, parentResult); - } - - @Override - public void scheduleTasksNow(Collection taskOids, Task operationTask, OperationResult parentResult) throws SecurityViolationException, ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException { - authorizeTaskCollectionOperation(ModelAuthorizationAction.RUN_TASK_IMMEDIATELY, taskOids, operationTask, parentResult); - taskManager.scheduleTasksNow(taskOids, parentResult); - } - - @Override - public void scheduleTaskNow(String taskOid, Task operationTask, OperationResult parentResult) throws SecurityViolationException, ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException { - authorizeTaskOperation(ModelAuthorizationAction.RUN_TASK_IMMEDIATELY, taskOid, operationTask, parentResult); - taskManager.scheduleTaskNow(taskOid, parentResult); - } - - @Override - public PrismObject getTaskByIdentifier(String identifier, Collection> rawOptions, Task operationTask, OperationResult parentResult) throws SchemaException, ObjectNotFoundException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException, CommunicationException { - Collection> options = preProcessOptionsSecurity(rawOptions, operationTask, parentResult); - PrismObject task = taskManager.getTaskTypeByIdentifier(identifier, options, parentResult); - GetOperationOptions rootOptions = SelectorOptions.findRootOptions(options); - task = task.cloneIfImmutable(); - schemaTransformer.applySchemasAndSecurity(task, rootOptions, options,null, null, parentResult); - return task; - } - - @Override - public boolean deactivateServiceThreads(long timeToWait, Task operationTask, OperationResult parentResult) throws SchemaException, SecurityViolationException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException { - securityEnforcer.authorize(ModelAuthorizationAction.STOP_SERVICE_THREADS.getUrl(), null, AuthorizationParameters.EMPTY, null, operationTask, parentResult); - return taskManager.deactivateServiceThreads(timeToWait, parentResult); - } - - @Override - public void reactivateServiceThreads(Task operationTask, OperationResult parentResult) throws SchemaException, SecurityViolationException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException { - securityEnforcer.authorize(ModelAuthorizationAction.START_SERVICE_THREADS.getUrl(), null, AuthorizationParameters.EMPTY, null, operationTask, parentResult); - taskManager.reactivateServiceThreads(parentResult); - } - - @Override - public boolean getServiceThreadsActivationState() { - return taskManager.getServiceThreadsActivationState(); - } - - @Override - public void stopSchedulers(Collection nodeIdentifiers, Task operationTask, OperationResult parentResult) throws SecurityViolationException, ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException { - authorizeNodeCollectionOperation(ModelAuthorizationAction.STOP_TASK_SCHEDULER, nodeIdentifiers, operationTask, parentResult); - taskManager.stopSchedulers(nodeIdentifiers, parentResult); - } - - @Override - public boolean stopSchedulersAndTasks(Collection nodeIdentifiers, long waitTime, Task operationTask, OperationResult parentResult) throws SecurityViolationException, ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException { - authorizeNodeCollectionOperation(ModelAuthorizationAction.STOP_TASK_SCHEDULER, nodeIdentifiers, operationTask, parentResult); - return taskManager.stopSchedulersAndTasks(nodeIdentifiers, waitTime, parentResult); - } - - @Override - public void startSchedulers(Collection nodeIdentifiers, Task operationTask, OperationResult parentResult) throws SecurityViolationException, ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException { - authorizeNodeCollectionOperation(ModelAuthorizationAction.START_TASK_SCHEDULER, nodeIdentifiers, operationTask, parentResult); - taskManager.startSchedulers(nodeIdentifiers, parentResult); - } - - @Override - public void synchronizeTasks(Task operationTask, OperationResult parentResult) throws SchemaException, SecurityViolationException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException { - securityEnforcer.authorize(ModelAuthorizationAction.SYNCHRONIZE_TASKS.getUrl(), null, AuthorizationParameters.EMPTY, null, operationTask, parentResult); - taskManager.synchronizeTasks(parentResult); - } - - @Override - public void reconcileWorkers(String oid, Task opTask, OperationResult result) - throws CommunicationException, ObjectNotFoundException, SchemaException, SecurityViolationException, - ConfigurationException, ExpressionEvaluationException, ObjectAlreadyExistsException { - securityEnforcer.authorize(AuthorizationConstants.AUTZ_ALL_URL, null, AuthorizationParameters.EMPTY, null, opTask, result); - taskManager.reconcileWorkers(oid, null, result); - } - - @Override - public void deleteWorkersAndWorkState(String rootTaskOid, boolean deleteWorkers, long subtasksWaitTime, Task operationTask, - OperationResult parentResult) - throws SecurityViolationException, ObjectNotFoundException, SchemaException, ExpressionEvaluationException, - CommunicationException, ConfigurationException { - securityEnforcer.authorize(AuthorizationConstants.AUTZ_ALL_URL, null, AuthorizationParameters.EMPTY, null, operationTask, parentResult); - taskManager.deleteWorkersAndWorkState(rootTaskOid, deleteWorkers, subtasksWaitTime, parentResult); - } - - @Override - public List getAllTaskCategories() { - return taskManager.getAllTaskCategories(); - } - - @Override - public String getHandlerUriForCategory(String category) { - return taskManager.getHandlerUriForCategory(category); - } - - private void authorizeTaskOperation(ModelAuthorizationAction action, String oid, Task task, OperationResult parentResult) throws SchemaException, ObjectNotFoundException, SecurityViolationException, ExpressionEvaluationException, CommunicationException, ConfigurationException { - authorizeTaskCollectionOperation(action, singleton(oid), task, parentResult); - } - - private void authorizeTaskOperation(ModelAuthorizationAction action, PrismObject existingTask, Task task, OperationResult parentResult) throws SchemaException, ObjectNotFoundException, SecurityViolationException, ExpressionEvaluationException, CommunicationException, ConfigurationException { - authorizeResolvedTaskCollectionOperation(action, singleton(existingTask), task, parentResult); - } - - private void authorizeTaskCollectionOperation(ModelAuthorizationAction action, Collection oids, Task task, OperationResult parentResult) throws SchemaException, ObjectNotFoundException, SecurityViolationException, ExpressionEvaluationException, CommunicationException, ConfigurationException { - if (securityEnforcer.isAuthorized(AuthorizationConstants.AUTZ_ALL_URL, null, AuthorizationParameters.EMPTY, null, task, parentResult)) { - return; - } - for (String oid : oids) { - PrismObject existingObject = cacheRepositoryService.getObject(TaskType.class, oid, null, parentResult); - securityEnforcer.authorize(action.getUrl(), null, AuthorizationParameters.Builder.buildObject(existingObject), null, task, parentResult); - } - } - - private void authorizeResolvedTaskCollectionOperation(ModelAuthorizationAction action, Collection> existingTasks, Task task, OperationResult parentResult) throws SchemaException, ObjectNotFoundException, SecurityViolationException, ExpressionEvaluationException, CommunicationException, ConfigurationException { - if (securityEnforcer.isAuthorized(AuthorizationConstants.AUTZ_ALL_URL, null, AuthorizationParameters.EMPTY, null, task, parentResult)) { - return; - } - for (PrismObject existingObject : existingTasks) { - securityEnforcer.authorize(action.getUrl(), null, AuthorizationParameters.Builder.buildObject(existingObject), null, task, parentResult); - } - } - - private void authorizeNodeCollectionOperation(ModelAuthorizationAction action, Collection identifiers, Task task, OperationResult parentResult) throws SchemaException, ObjectNotFoundException, SecurityViolationException, ExpressionEvaluationException, CommunicationException, ConfigurationException { - if (securityEnforcer.isAuthorized(AuthorizationConstants.AUTZ_ALL_URL, null, AuthorizationParameters.EMPTY, null, task, parentResult)) { - return; - } - for (String identifier : identifiers) { - PrismObject existingObject; - ObjectQuery q = ObjectQueryUtil.createNameQuery(NodeType.class, prismContext, identifier); - List> nodes = cacheRepositoryService.searchObjects(NodeType.class, q, null, parentResult); - if (nodes.isEmpty()) { - throw new ObjectNotFoundException("Node with identifier '" + identifier + "' couldn't be found."); - } else if (nodes.size() > 1) { - throw new SystemException("Multiple nodes with identifier '" + identifier + "'"); - } - existingObject = nodes.get(0); - securityEnforcer.authorize(action.getUrl(), null, AuthorizationParameters.Builder.buildObject(existingObject), null, task, parentResult); - } - } - - //endregion - - //region Workflow-related operations - @Override - public void completeWorkItem(WorkItemId workItemId, @NotNull AbstractWorkItemOutputType output, ObjectDelta additionalDelta, - Task task, OperationResult parentResult) - throws SecurityViolationException, SchemaException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException { - AbstractWorkItemOutputType outputToUse; - if (additionalDelta != null && ApprovalUtils.isApproved(output)) { - //noinspection unchecked - ObjectDeltaType additionalDeltaBean = DeltaConvertor.toObjectDeltaType(additionalDelta); - ObjectTreeDeltasType treeDeltas = new ObjectTreeDeltasType(); - treeDeltas.setFocusPrimaryDelta(additionalDeltaBean); - - WorkItemResultType newOutput = new WorkItemResultType(prismContext); - //noinspection unchecked - newOutput.asPrismContainerValue().mergeContent(output.asPrismContainerValue(), emptyList()); - newOutput.setAdditionalDeltas(treeDeltas); - outputToUse = newOutput; - } else { - outputToUse = output; - } - getWorkflowManagerChecked().completeWorkItem(workItemId, outputToUse, null, task, parentResult); - } - - @Override - public void completeWorkItem(@NotNull WorkItemId workItemId, @NotNull AbstractWorkItemOutputType output, @NotNull Task task, @NotNull OperationResult parentResult) - throws SecurityViolationException, SchemaException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException { - getWorkflowManagerChecked().completeWorkItem(workItemId, output, null, task, parentResult); - } - - @Override - public void cancelCase(String caseOid, Task task, OperationResult parentResult) throws SchemaException, - ObjectNotFoundException, SecurityViolationException, ExpressionEvaluationException, CommunicationException, - ConfigurationException, ObjectAlreadyExistsException { - getWorkflowManagerChecked().cancelCase(caseOid, task, parentResult); - } - - @Override - public void claimWorkItem(WorkItemId workItemId, Task task, OperationResult parentResult) - throws SecurityViolationException, ObjectNotFoundException, SchemaException, ObjectAlreadyExistsException, - CommunicationException, ConfigurationException, ExpressionEvaluationException { - getWorkflowManagerChecked().claimWorkItem(workItemId, task, parentResult); - } - - @Override - public void releaseWorkItem(WorkItemId workItemId, Task task, OperationResult parentResult) - throws ObjectNotFoundException, SecurityViolationException, SchemaException, ObjectAlreadyExistsException, - CommunicationException, ConfigurationException, ExpressionEvaluationException { - getWorkflowManagerChecked().releaseWorkItem(workItemId, task, parentResult); - } - - @Override - public void delegateWorkItem(WorkItemId workItemId, WorkItemDelegationRequestType delegationRequest, - Task task, OperationResult parentResult) throws ObjectNotFoundException, SecurityViolationException, SchemaException, - ExpressionEvaluationException, CommunicationException, ConfigurationException { - getWorkflowManagerChecked().delegateWorkItem(workItemId, delegationRequest, task, parentResult); - } - - //endregion - - //region Scripting (bulk actions) - @Deprecated - @Override - public void evaluateExpressionInBackground(QName objectType, ObjectFilter filter, String actionName, Task task, OperationResult parentResult) throws SchemaException, SecurityViolationException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException { - checkScriptingAuthorization(task, parentResult); - scriptingExpressionEvaluator.evaluateExpressionInBackground(objectType, filter, actionName, task, parentResult); - } - - @Override - public void evaluateExpressionInBackground(ScriptingExpressionType expression, Task task, OperationResult parentResult) throws SchemaException, SecurityViolationException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException { - checkScriptingAuthorization(task, parentResult); - scriptingExpressionEvaluator.evaluateExpressionInBackground(expression, task, parentResult); - } - - @Override - public void evaluateExpressionInBackground(ExecuteScriptType executeScriptCommand, Task task, OperationResult parentResult) throws SchemaException, SecurityViolationException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException { - checkScriptingAuthorization(task, parentResult); - scriptingExpressionEvaluator.evaluateExpressionInBackground(executeScriptCommand, task, parentResult); - } - - @Override - public void evaluateIterativeExpressionInBackground(ExecuteScriptType executeScriptCommand, Task task, OperationResult parentResult) throws SchemaException, SecurityViolationException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException { - checkScriptingAuthorization(task, parentResult); - scriptingExpressionEvaluator.evaluateIterativeExpressionInBackground(executeScriptCommand, task, parentResult); - } - - @Override - public ScriptExecutionResult evaluateExpression(ScriptingExpressionType expression, Task task, OperationResult result) throws ScriptExecutionException, SchemaException, SecurityViolationException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException { - checkScriptingAuthorization(task, result); - ExecutionContext executionContext = scriptingExpressionEvaluator.evaluateExpression(expression, task, result); - return executionContext.toExecutionResult(); - } - - @Override - public ScriptExecutionResult evaluateExpression(@NotNull ExecuteScriptType scriptExecutionCommand, - @NotNull VariablesMap initialVariables, boolean recordProgressAndIterationStatistics, @NotNull Task task, - @NotNull OperationResult result) - throws ScriptExecutionException, SchemaException, SecurityViolationException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException { - checkScriptingAuthorization(task, result); - ExecutionContext executionContext = scriptingExpressionEvaluator.evaluateExpression(scriptExecutionCommand, initialVariables, - recordProgressAndIterationStatistics, task, result); - return executionContext.toExecutionResult(); - } - - private void checkScriptingAuthorization(Task task, OperationResult parentResult) throws SchemaException, SecurityViolationException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException { - securityEnforcer.authorize(ModelAuthorizationAction.EXECUTE_SCRIPT.getUrl(), null, AuthorizationParameters.EMPTY, null, task, parentResult); - } - //endregion - - //region Certification - - @Override - public AccessCertificationCasesStatisticsType getCampaignStatistics(String campaignOid, boolean currentStageOnly, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, SecurityViolationException, ObjectAlreadyExistsException, ExpressionEvaluationException, CommunicationException, ConfigurationException { - return getCertificationManagerChecked().getCampaignStatistics(campaignOid, currentStageOnly, task, parentResult); - } - - @Override - public void cleanupCampaigns(@NotNull CleanupPolicyType policy, Task task, OperationResult result) { - getCertificationManagerChecked().cleanupCampaigns(policy, task, result); - } - - @Override - public void recordDecision(String campaignOid, long caseId, long workItemId, AccessCertificationResponseType response, String comment, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, SecurityViolationException, ObjectAlreadyExistsException, ExpressionEvaluationException, CommunicationException, ConfigurationException { - getCertificationManagerChecked().recordDecision(campaignOid, caseId, workItemId, response, comment, task, parentResult); - } - - @Deprecated - @Override - public List searchOpenWorkItems(ObjectQuery baseWorkItemsQuery, boolean notDecidedOnly, - boolean allItems, Collection> rawOptions, Task task, OperationResult parentResult) - throws ObjectNotFoundException, SchemaException, SecurityViolationException, ExpressionEvaluationException, CommunicationException, - ConfigurationException { - Collection> options = preProcessOptionsSecurity(rawOptions, task, parentResult); - return getCertificationManagerChecked().searchOpenWorkItems(baseWorkItemsQuery, notDecidedOnly, allItems, options, task, parentResult); - } - - @Deprecated - @Override - public int countOpenWorkItems(ObjectQuery baseWorkItemsQuery, boolean notDecidedOnly, boolean allItems, - Collection> rawOptions, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, SecurityViolationException, ExpressionEvaluationException, CommunicationException, ConfigurationException { - Collection> options = preProcessOptionsSecurity(rawOptions, task, parentResult); - return getCertificationManagerChecked().countOpenWorkItems(baseWorkItemsQuery, notDecidedOnly, allItems, options, task, parentResult); - } - - @Override - public void closeCampaign(String campaignOid, Task task, OperationResult result) throws ObjectNotFoundException, SchemaException, SecurityViolationException, ObjectAlreadyExistsException, ExpressionEvaluationException, CommunicationException, ConfigurationException { - getCertificationManagerChecked().closeCampaign(campaignOid, task, result); - } - - @Override - public void reiterateCampaign(String campaignOid, Task task, OperationResult result) throws ObjectNotFoundException, SchemaException, SecurityViolationException, ObjectAlreadyExistsException, ExpressionEvaluationException, CommunicationException, ConfigurationException { - getCertificationManagerChecked().reiterateCampaign(campaignOid, task, result); - } - - @Override - public void startRemediation(String campaignOid, Task task, OperationResult result) throws ObjectNotFoundException, SchemaException, SecurityViolationException, ObjectAlreadyExistsException, ExpressionEvaluationException, CommunicationException, ConfigurationException { - getCertificationManagerChecked().startRemediation(campaignOid, task, result); - } - - @Override - public void closeCurrentStage(String campaignOid, Task task, OperationResult parentResult) throws SchemaException, SecurityViolationException, ObjectNotFoundException, ObjectAlreadyExistsException, ExpressionEvaluationException, CommunicationException, ConfigurationException { - getCertificationManagerChecked().closeCurrentStage(campaignOid, task, parentResult); - } - - @Override - public void openNextStage(String campaignOid, Task task, OperationResult parentResult) throws SchemaException, SecurityViolationException, ObjectNotFoundException, ObjectAlreadyExistsException, ExpressionEvaluationException, CommunicationException, ConfigurationException { - getCertificationManagerChecked().openNextStage(campaignOid, task, parentResult); - } - - @Override - public AccessCertificationCampaignType createCampaign(String definitionOid, Task task, OperationResult parentResult) throws SchemaException, SecurityViolationException, ObjectNotFoundException, ObjectAlreadyExistsException, ExpressionEvaluationException, CommunicationException, ConfigurationException { - return getCertificationManagerChecked().createCampaign(definitionOid, task, parentResult); - } - //endregion - - @Override - public Collection> mergeObjects(Class type, - String leftOid, String rightOid, String mergeConfigurationName, Task task, OperationResult parentResult) - throws ObjectNotFoundException, SchemaException, ConfigurationException, ObjectAlreadyExistsException, ExpressionEvaluationException, CommunicationException, PolicyViolationException, SecurityViolationException { - - OperationResult result = parentResult.createSubresult(MERGE_OBJECTS); - result.addParam("leftOid", leftOid); - result.addParam("rightOid", rightOid); - result.addParam("class", type); - - enterModelMethod(); - - try { - - Collection> deltas = - objectMerger.mergeObjects(type, leftOid, rightOid, mergeConfigurationName, task, result); - - result.computeStatus(); - return deltas; - - } catch (ObjectNotFoundException | SchemaException | ConfigurationException | ObjectAlreadyExistsException | ExpressionEvaluationException | CommunicationException | PolicyViolationException | SecurityViolationException | RuntimeException | Error e) { - ModelImplUtils.recordFatalError(result, e); - throw e; - } finally { - QNameUtil.setTemporarilyTolerateUndeclaredPrefixes(false); - exitModelMethod(); - } - - } - - @NotNull - @Override - public PrismContext getPrismContext() { - return prismContext; - } - - private void enterModelMethod() { - clockworkMedic.enterModelMethod(true); - } - - private void enterModelMethodNoRepoCache() { - clockworkMedic.enterModelMethod(false); - } - - private void exitModelMethod() { - clockworkMedic.exitModelMethod(true); - } - - private void exitModelMethodNoRepoCache() { - clockworkMedic.exitModelMethod(false); - } - - //region Case Management - - @Override - public String getThreadsDump(@NotNull Task task, @NotNull OperationResult parentResult) - throws CommunicationException, ObjectNotFoundException, SchemaException, SecurityViolationException, - ConfigurationException, ExpressionEvaluationException { - securityEnforcer.authorize(ModelAuthorizationAction.READ_THREADS.getUrl(), null, AuthorizationParameters.EMPTY, null, task, parentResult); - return MiscUtil.takeThreadDump(null); - } - - @Override - public String getRunningTasksThreadsDump(@NotNull Task task, @NotNull OperationResult parentResult) - throws CommunicationException, ObjectNotFoundException, SchemaException, SecurityViolationException, - ConfigurationException, ExpressionEvaluationException { - securityEnforcer.authorize(ModelAuthorizationAction.READ_THREADS.getUrl(), null, AuthorizationParameters.EMPTY, null, task, parentResult); - return taskManager.getRunningTasksThreadsDump(parentResult); - } - - @Override - public String recordRunningTasksThreadsDump(String cause, @NotNull Task task, @NotNull OperationResult parentResult) - throws CommunicationException, ObjectNotFoundException, SchemaException, SecurityViolationException, - ConfigurationException, ExpressionEvaluationException, ObjectAlreadyExistsException { - securityEnforcer.authorize(ModelAuthorizationAction.READ_THREADS.getUrl(), null, AuthorizationParameters.EMPTY, null, task, parentResult); - return taskManager.recordRunningTasksThreadsDump(cause, parentResult); - } - - @Override - public String getTaskThreadsDump(@NotNull String taskOid, @NotNull Task task, @NotNull OperationResult parentResult) - throws CommunicationException, ObjectNotFoundException, SchemaException, SecurityViolationException, - ConfigurationException, ExpressionEvaluationException { - securityEnforcer.authorize(ModelAuthorizationAction.READ_THREADS.getUrl(), null, AuthorizationParameters.EMPTY, null, task, parentResult); - return taskManager.getTaskThreadsDump(taskOid, parentResult); - } - - //endregion - - public void notifyChange(ResourceObjectShadowChangeDescriptionType changeDescription, Task task, OperationResult parentResult) - throws SchemaException, CommunicationException, ConfigurationException, SecurityViolationException, - ObjectNotFoundException, ObjectAlreadyExistsException, ExpressionEvaluationException, PolicyViolationException { - - String oldShadowOid = changeDescription.getOldShadowOid(); - ResourceEventDescription eventDescription = new ResourceEventDescription(); - - PrismObject oldShadow; - LOGGER.trace("resolving old object"); - if (!StringUtils.isEmpty(oldShadowOid)) { - // FIXME we should not get object from resource here: it should be sufficient to retrieve object from the repository - // (and even that can be skipped, if identifiers are correctly set) ... MID-5834 - oldShadow = getObject(ShadowType.class, oldShadowOid, SelectorOptions.createCollection(GetOperationOptions.createDoNotDiscovery()), task, parentResult); - eventDescription.setOldRepoShadow(oldShadow); - LOGGER.trace("old object resolved to: {}", oldShadow.debugDumpLazily()); - } else { - LOGGER.trace("Old shadow null"); - } - - ShadowType currentResourceObjectBean = changeDescription.getCurrentShadow(); - if (currentResourceObjectBean != null) { - PrismObject currentResourceObject = currentResourceObjectBean.asPrismObject(); - prismContext.adopt(currentResourceObject); - LOGGER.trace("current resource object:\n{}", currentResourceObject.debugDumpLazily()); - eventDescription.setCurrentResourceObject(currentResourceObject); - } - - ObjectDeltaType deltaType = changeDescription.getObjectDelta(); - - if (deltaType != null) { - - PrismObject shadowToAdd; - ObjectDelta delta = prismContext.deltaFactory().object().createEmptyDelta(ShadowType.class, deltaType.getOid(), - ChangeType.toChangeType(deltaType.getChangeType())); - - if (delta.getChangeType() == ChangeType.ADD) { - if (deltaType.getObjectToAdd() == null) { - LOGGER.trace("No object to add specified. Check your delta. Add delta must contain object to add"); - throw new IllegalArgumentException("No object to add specified. Check your delta. Add delta must contain object to add"); - } - Object objToAdd = deltaType.getObjectToAdd(); - if (!(objToAdd instanceof ShadowType)) { - LOGGER.trace("Wrong object specified in change description. Expected on the the shadow type, but got " + objToAdd.getClass().getSimpleName()); - throw new IllegalArgumentException("Wrong object specified in change description. Expected on the the shadow type, but got " + objToAdd.getClass().getSimpleName()); - } - prismContext.adopt((ShadowType)objToAdd); - - shadowToAdd = ((ShadowType) objToAdd).asPrismObject(); - LOGGER.trace("object to add: {}", shadowToAdd.debugDump()); - delta.setObjectToAdd(shadowToAdd); - } else { - Collection modifications = DeltaConvertor.toModifications(deltaType.getItemDelta(), prismContext.getSchemaRegistry().findObjectDefinitionByCompileTimeClass(ShadowType.class)); - delta.addModifications(modifications); - } - ModelImplUtils.encrypt(Collections.singletonList(delta), protector, null, parentResult); - eventDescription.setDelta(delta); - } - - eventDescription.setSourceChannel(changeDescription.getChannel()); - - dispatcher.notifyEvent(eventDescription, task, parentResult); - parentResult.computeStatus(); - task.setResult(parentResult); - } - - private void computePolyStrings(Collection> deltas, ModelExecuteOptions options, - OperationResult result) { - for(ObjectDelta delta: deltas) { - delta.accept(this::computePolyStringVisit); - } - } - - private void computePolyStringVisit(Visitable visitable) { - if (!(visitable instanceof PrismProperty)) { - return; - } - PrismPropertyDefinition definition = ((PrismProperty)visitable).getDefinition(); - if (definition == null) { - return; - } - if (!QNameUtil.match(PolyStringType.COMPLEX_TYPE, definition.getTypeName())) { - return; - } - for (PrismPropertyValue pval : ((PrismProperty)visitable).getValues()) { - PolyString polyString = pval.getValue(); - if (polyString.getOrig() == null) { - String orig = localizationService.translate(polyString); - LOGGER.info("PPPP1: Filling out orig value of polyString {}: {}", polyString, orig); - polyString.setComputedOrig(orig); - polyString.recompute(prismContext.getDefaultPolyStringNormalizer()); - LOGGER.info("PPPP2: Resulting polyString: {}", polyString); - } - } - } -} +/* + * Copyright (c) 2010-2019 Evolveum and contributors + * + * This work is dual-licensed under the Apache License 2.0 + * and European Union Public License. See LICENSE file for details. + */ +package com.evolveum.midpoint.model.impl.controller; + +import com.evolveum.midpoint.audit.api.AuditEventRecord; +import com.evolveum.midpoint.audit.api.AuditEventStage; +import com.evolveum.midpoint.audit.api.AuditEventType; +import com.evolveum.midpoint.certification.api.CertificationManager; +import com.evolveum.midpoint.common.LocalizationService; +import com.evolveum.midpoint.model.api.*; +import com.evolveum.midpoint.model.api.authentication.GuiProfiledPrincipalManager; +import com.evolveum.midpoint.model.api.hooks.HookRegistry; +import com.evolveum.midpoint.model.api.hooks.ReadHook; +import com.evolveum.midpoint.model.common.SystemObjectCache; +import com.evolveum.midpoint.model.impl.ModelObjectResolver; +import com.evolveum.midpoint.model.impl.importer.ImportAccountsFromResourceTaskHandler; +import com.evolveum.midpoint.model.impl.importer.ObjectImporter; +import com.evolveum.midpoint.model.impl.lens.*; +import com.evolveum.midpoint.model.impl.scripting.ExecutionContext; +import com.evolveum.midpoint.model.impl.scripting.ScriptingExpressionEvaluator; +import com.evolveum.midpoint.model.impl.util.AuditHelper; +import com.evolveum.midpoint.model.impl.util.ModelImplUtils; +import com.evolveum.midpoint.prism.*; +import com.evolveum.midpoint.prism.crypto.Protector; +import com.evolveum.midpoint.prism.delta.*; +import com.evolveum.midpoint.prism.path.*; +import com.evolveum.midpoint.prism.polystring.PolyString; +import com.evolveum.midpoint.prism.query.*; +import com.evolveum.midpoint.prism.util.CloneUtil; +import com.evolveum.midpoint.provisioning.api.*; +import com.evolveum.midpoint.repo.api.PreconditionViolationException; +import com.evolveum.midpoint.repo.api.RepoAddOptions; +import com.evolveum.midpoint.repo.api.RepositoryService; +import com.evolveum.midpoint.repo.cache.RepositoryCache; +import com.evolveum.midpoint.schema.*; +import com.evolveum.midpoint.schema.constants.ObjectTypes; +import com.evolveum.midpoint.schema.constants.SchemaConstants; +import com.evolveum.midpoint.schema.expression.VariablesMap; +import com.evolveum.midpoint.schema.internals.InternalsConfig; +import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.schema.result.OperationResultRunner; +import com.evolveum.midpoint.schema.result.OperationResultStatus; +import com.evolveum.midpoint.schema.util.ObjectQueryUtil; +import com.evolveum.midpoint.schema.util.ObjectTypeUtil; +import com.evolveum.midpoint.schema.util.ShadowUtil; +import com.evolveum.midpoint.schema.util.WorkItemId; +import com.evolveum.midpoint.security.api.AuthorizationConstants; +import com.evolveum.midpoint.security.api.SecurityContextManager; +import com.evolveum.midpoint.security.enforcer.api.AuthorizationParameters; +import com.evolveum.midpoint.security.enforcer.api.SecurityEnforcer; +import com.evolveum.midpoint.task.api.Task; +import com.evolveum.midpoint.task.api.TaskManager; +import com.evolveum.midpoint.util.DebugUtil; +import com.evolveum.midpoint.util.MiscUtil; +import com.evolveum.midpoint.util.QNameUtil; +import com.evolveum.midpoint.util.exception.*; +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.wf.api.WorkflowManager; +import com.evolveum.midpoint.wf.util.ApprovalUtils; +import com.evolveum.midpoint.xml.ns._public.common.api_types_3.CompareResultType; +import com.evolveum.midpoint.xml.ns._public.common.api_types_3.ImportOptionsType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.*; +import com.evolveum.midpoint.xml.ns._public.model.scripting_3.ExecuteScriptType; +import com.evolveum.midpoint.xml.ns._public.model.scripting_3.ScriptingExpressionType; +import com.evolveum.prism.xml.ns._public.types_3.EvaluationTimeType; +import com.evolveum.prism.xml.ns._public.types_3.ObjectDeltaType; +import com.evolveum.prism.xml.ns._public.types_3.PolyStringType; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang.Validate; +import org.jetbrains.annotations.NotNull; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; + +import javax.xml.namespace.QName; +import java.io.*; +import java.util.*; + +import static java.util.Collections.emptyList; +import static java.util.Collections.singleton; + +/** + * This used to be an interface, but it was switched to class for simplicity. I + * don't expect that the implementation of the controller will be ever replaced. + * In extreme case the whole Model will be replaced by a different + * implementation, but not just the controller. + *

+ * However, the common way to extend the functionality will be the use of hooks + * that are implemented here. + *

+ * Great deal of code is copied from the old ModelControllerImpl. + * + * @author lazyman + * @author Radovan Semancik + * + * Note: don't autowire this bean by implementing class (ModelController), as it is proxied by Spring AOP. + * Use its interfaces instead. + */ +@Component +public class ModelController implements ModelService, TaskService, WorkflowService, ScriptingService, AccessCertificationService { + + // Constants for OperationResult + public static final String CLASS_NAME_WITH_DOT = ModelController.class.getName() + "."; + public static final String ADD_OBJECT_WITH_EXCLUSION = CLASS_NAME_WITH_DOT + "addObjectWithExclusion"; + public static final String MODIFY_OBJECT_WITH_EXCLUSION = CLASS_NAME_WITH_DOT + + "modifyObjectWithExclusion"; + public static final String CHANGE_ACCOUNT = CLASS_NAME_WITH_DOT + "changeAccount"; + + public static final String GET_SYSTEM_CONFIGURATION = CLASS_NAME_WITH_DOT + "getSystemConfiguration"; + public static final String RESOLVE_USER_ATTRIBUTES = CLASS_NAME_WITH_DOT + "resolveUserAttributes"; + public static final String RESOLVE_ACCOUNT_ATTRIBUTES = CLASS_NAME_WITH_DOT + "resolveAccountAttributes"; + public static final String CREATE_ACCOUNT = CLASS_NAME_WITH_DOT + "createAccount"; + public static final String UPDATE_ACCOUNT = CLASS_NAME_WITH_DOT + "updateAccount"; + public static final String PROCESS_USER_TEMPLATE = CLASS_NAME_WITH_DOT + "processUserTemplate"; + private static final String RESOLVE_REFERENCE = CLASS_NAME_WITH_DOT + "resolveReference"; + + private static final Trace LOGGER = TraceManager.getTrace(ModelController.class); + + private static final Trace OP_LOGGER = TraceManager.getTrace(ModelService.OPERATION_LOGGGER_NAME); + + @Autowired private Clockwork clockwork; + @Autowired private PrismContext prismContext; + @Autowired private ProvisioningService provisioning; + @Autowired private ModelObjectResolver objectResolver; + @Autowired private transient ImportAccountsFromResourceTaskHandler importAccountsFromResourceTaskHandler; + @Autowired private transient ObjectImporter objectImporter; + @Autowired private HookRegistry hookRegistry; + @Autowired private TaskManager taskManager; + @Autowired private ScriptingExpressionEvaluator scriptingExpressionEvaluator; + @Autowired private AuditHelper auditHelper; + @Autowired private SecurityEnforcer securityEnforcer; + @Autowired private SecurityContextManager securityContextManager; + @Autowired private GuiProfiledPrincipalManager focusProfileService; + @Autowired private Protector protector; + @Autowired private LocalizationService localizationService; + @Autowired private ContextFactory contextFactory; + @Autowired private SchemaTransformer schemaTransformer; + @Autowired private ObjectMerger objectMerger; + @Autowired private SystemObjectCache systemObjectCache; + @Autowired private ClockworkMedic clockworkMedic; + @Autowired private ChangeNotificationDispatcher dispatcher; + @Autowired + @Qualifier("cacheRepositoryService") + private transient RepositoryService cacheRepositoryService; + + @Autowired(required = false) // not required in all circumstances + private WorkflowManager workflowManager; + + @Autowired(required = false) // not required in all circumstances + private CertificationManager certificationManager; + + public ModelObjectResolver getObjectResolver() { + return objectResolver; + } + + private WorkflowManager getWorkflowManagerChecked() { + if (workflowManager == null) { + throw new SystemException("Workflow manager not present"); + } + return workflowManager; + } + + private CertificationManager getCertificationManagerChecked() { + if (certificationManager == null) { + throw new SystemException("Certification manager not present"); + } + return certificationManager; + } + + + @Override + public PrismObject getObject(Class clazz, String oid, + Collection> rawOptions, Task task, OperationResult parentResult) throws ObjectNotFoundException, + SchemaException, CommunicationException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { + Validate.notEmpty(oid, "Object oid must not be null or empty."); + Validate.notNull(parentResult, "Operation result must not be null."); + Validate.notNull(clazz, "Object class must not be null."); + enterModelMethod(); + + PrismObject object; + + OP_LOGGER.trace("MODEL OP enter getObject({},{},{})", clazz.getSimpleName(), oid, rawOptions); + + GetOperationOptions rootOptions = null; + + OperationResult result = parentResult.subresult(GET_OBJECT) + .setMinor() + .addParam("oid", oid) + .addArbitraryObjectCollectionAsParam("options", rawOptions) + .addParam("class", clazz) + .build(); + try { + Collection> options = preProcessOptionsSecurity(rawOptions, task, parentResult); + rootOptions = SelectorOptions.findRootOptions(options); + + if (GetOperationOptions.isRaw(rootOptions)) { // MID-2218 + QNameUtil.setTemporarilyTolerateUndeclaredPrefixes(true); + } + ObjectReferenceType ref = new ObjectReferenceType(); + ref.setOid(oid); + ref.setType(ObjectTypes.getObjectType(clazz).getTypeQName()); + ModelImplUtils.clearRequestee(task); + +// Special-purpose code to hunt down read-write resource fetch from GUI. +// Normally the code is not active. It is too brutal. Just for MID-3424. +// if (ResourceType.class == clazz && !GetOperationOptions.isRaw(rootOptions) && !GetOperationOptions.isReadOnly(rootOptions)) { +// LOGGER.info("READWRITE resource get: {} {}:\n{}", oid, options, +// LoggingUtils.dumpStackTrace()); +// } + + object = (PrismObject) objectResolver.getObject(clazz, oid, options, task, result).asPrismObject(); + + object = object.cloneIfImmutable(); + schemaTransformer.applySchemasAndSecurity(object, rootOptions, options, null, task, result); + executeResolveOptions(object.asObjectable(), options, task, result); + + } catch (SchemaException | CommunicationException | ConfigurationException | SecurityViolationException | ExpressionEvaluationException | RuntimeException | Error e) { + OP_LOGGER.debug("MODEL OP error getObject({},{},{}): {}: {}", clazz.getSimpleName(), oid, rawOptions, e.getClass().getSimpleName(), e.getMessage()); + ModelImplUtils.recordFatalError(result, e); + throw e; + } catch (ObjectNotFoundException e) { + OP_LOGGER.debug("MODEL OP error getObject({},{},{}): {}: {}", clazz.getSimpleName(), oid, rawOptions, e.getClass().getSimpleName(), e.getMessage()); + if (GetOperationOptions.isAllowNotFound(rootOptions)){ + result.getLastSubresult().setStatus(OperationResultStatus.HANDLED_ERROR); + } else { + ModelImplUtils.recordFatalError(result, e); + } + throw e; + } finally { + result.computeStatusIfUnknown(); + QNameUtil.setTemporarilyTolerateUndeclaredPrefixes(false); + exitModelMethod(); + } + + result.cleanupResult(); + + OP_LOGGER.debug("MODEL OP exit getObject({},{},{}): {}", clazz.getSimpleName(), oid, rawOptions, object); + if (OP_LOGGER.isTraceEnabled()) { + OP_LOGGER.trace("MODEL OP exit getObject({},{},{}):\n{}", clazz.getSimpleName(), oid, rawOptions, object.debugDump(1)); + } + return object; + } + + private void executeResolveOptions(@NotNull Containerable containerable, Collection> options, + Task task, OperationResult result) { + if (options == null) { + return; + } + for (SelectorOptions option: options) { + if (GetOperationOptions.isResolve(option.getOptions())) { + ObjectSelector selector = option.getSelector(); + if (selector != null) { + ItemPath path = selector.getPath(); + ItemPath.checkNoSpecialSymbolsExceptParent(path); + executeResolveOption(containerable, path, option, task, result); + } + } + } + } + + // TODO clean this mess + private void executeResolveOption(Containerable containerable, ItemPath path, + SelectorOptions option, Task task, OperationResult result) { + if (path == null || path.isEmpty()) { + return; + } + Object first = path.first(); + ItemPath rest = path.rest(); + PrismContainerValue containerValue = containerable.asPrismContainerValue(); + if (ItemPath.isName(first)) { + QName firstName = ItemPath.toName(first); + PrismReference reference = containerValue.findReferenceByCompositeObjectElementName(firstName); + if (reference == null) { + reference = containerValue.findReference(firstName); // alternatively look up by reference name (e.g. linkRef) + } + if (reference != null) { + for (PrismReferenceValue refVal : reference.getValues()) { + //noinspection unchecked + PrismObject refObject = refVal.getObject(); + if (refObject == null) { + refObject = resolveReferenceUsingOption(refVal, option, containerable, task, result); + } + if (!rest.isEmpty() && refObject != null) { + executeResolveOption(refObject.asObjectable(), rest, option, task, result); + } + } + return; + } + } + if (rest.isEmpty()) { + return; + } + if (ItemPath.isParent(first)) { + PrismContainerValue parent = containerValue.getParentContainerValue(); + if (parent != null) { + executeResolveOption(parent.asContainerable(), rest, option, task, result); + } + } else { + QName nextName = ItemPath.toName(first); + PrismContainer nextContainer = containerValue.findContainer(nextName); + if (nextContainer != null) { + for (PrismContainerValue pcv : nextContainer.getValues()) { + executeResolveOption(pcv.asContainerable(), rest, option, task, result); + } + } + } + } + + private PrismObject resolveReferenceUsingOption(@NotNull PrismReferenceValue refVal, + SelectorOptions option, Containerable containerable, Task task, OperationResult parentResult) { + OperationResult result = parentResult.createMinorSubresult(RESOLVE_REFERENCE); + try { + PrismObject refObject; + refObject = objectResolver.resolve(refVal, containerable.toString(), option.getOptions(), task, result); + if (refObject != null) { + refObject = refObject.cloneIfImmutable(); + schemaTransformer.applySchemasAndSecurity(refObject, option.getOptions(), + SelectorOptions.createCollection(option.getOptions()), null, task, result); + refVal.setObject(refObject); + } + return refObject; + } catch (CommonException e) { + result.recordWarning("Couldn't resolve reference to " + ObjectTypeUtil.toShortString(refVal) + ": " + e.getMessage(), e); + return null; + } finally { + result.computeStatusIfUnknown(); + } + } + + @Override + public Collection> executeChanges(final Collection> deltas, ModelExecuteOptions options, + Task task, OperationResult parentResult) throws ObjectAlreadyExistsException, ObjectNotFoundException, + SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException, + PolicyViolationException, SecurityViolationException { + return executeChanges(deltas, options, task, null, parentResult); + } + + /* (non-Javadoc) + * @see com.evolveum.midpoint.model.api.ModelService#executeChanges(java.util.Collection, com.evolveum.midpoint.task.api.Task, com.evolveum.midpoint.schema.result.OperationResult) + */ + @Override + public Collection> executeChanges(Collection> deltas, ModelExecuteOptions options, + Task task, Collection statusListeners, OperationResult parentResult) throws ObjectAlreadyExistsException, ObjectNotFoundException, + SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException, + PolicyViolationException, SecurityViolationException { + + enterModelMethod(); + + OperationResult result = parentResult.createSubresult(EXECUTE_CHANGES); + result.addArbitraryObjectAsParam(OperationResult.PARAM_OPTIONS, options); + + try { + + // Search filters treatment: if reevaluation is requested, we have to deal with three cases: + // 1) for ADD operation: filters contained in object-to-be-added -> these are treated here + // 2) for MODIFY operation: filters contained in existing object (not touched by deltas) -> these are treated after the modify operation + // 3) for MODIFY operation: filters contained in deltas -> these have to be treated here, because if OID is missing from such a delta, the change would be rejected by the repository + if (ModelExecuteOptions.isReevaluateSearchFilters(options)) { + for (ObjectDelta delta : deltas) { + ModelImplUtils.resolveReferences(delta, cacheRepositoryService, false, true, EvaluationTimeType.IMPORT, true, prismContext, result); + } + } else if (ModelExecuteOptions.isIsImport(options)) { + // if plain import is requested, we simply evaluate filters in ADD operation (and we do not force reevaluation if OID is already set) + for (ObjectDelta delta : deltas) { + if (delta.isAdd()) { + ModelImplUtils.resolveReferences(delta.getObjectToAdd(), cacheRepositoryService, false, false, EvaluationTimeType.IMPORT, true, prismContext, result); + } + } + } + // Make sure everything is encrypted as needed before logging anything. + // But before that we need to make sure that we have proper definition, otherwise we + // might miss some encryptable data in dynamic schemas + applyDefinitions(deltas, options, task, result); + ModelImplUtils.encrypt(deltas, protector, options, result); + computePolyStrings(deltas, options, result); + + LOGGER.trace("MODEL.executeChanges(\n deltas:\n{}\n options:{}", DebugUtil.debugDumpLazily(deltas, 2), options); + + if (InternalsConfig.consistencyChecks) { + OperationResultRunner.run(result, () -> { + for (ObjectDelta delta : deltas) { + delta.checkConsistence(); + } + }); + } + + if (ModelExecuteOptions.isRaw(options)) { + return executeChangesRaw(deltas, options, task, result); + } else { + return executeChangesNonRaw(deltas, options, task, statusListeners, result); + } + + // Note: caches are invalidated automatically via RepositoryCache.invalidateCacheEntries method + + } catch (RuntimeException e) { // just for sure (TODO split this method into two: raw and non-raw case) + ModelImplUtils.recordFatalError(result, e); + throw e; + } finally { + exitModelMethod(); + } + } + + private Collection> executeChangesNonRaw( + Collection> deltas, ModelExecuteOptions options, Task task, + Collection statusListeners, OperationResult result) + throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, + ExpressionEvaluationException, SecurityViolationException, PolicyViolationException, ObjectAlreadyExistsException { + try { + LensContext context = contextFactory.createContext(deltas, options, task, result); + + authorizePartialExecution(context, options, task, result); + + if (ModelExecuteOptions.isReevaluateSearchFilters(options)) { + String m = "ReevaluateSearchFilters option is not fully supported for non-raw operations yet. Filters already present in the object will not be touched."; + LOGGER.warn("{} Context = {}", m, context.debugDump()); + result.createSubresult(CLASS_NAME_WITH_DOT+"reevaluateSearchFilters").recordWarning(m); + } + + context.setProgressListeners(statusListeners); + // Note: Request authorization happens inside clockwork + + clockwork.run(context, task, result); + + // prepare return value + Collection> executedDeltas = new ArrayList<>(); + if (context.getFocusContext() != null) { + executedDeltas.addAll(context.getFocusContext().getExecutedDeltas()); + } + for (LensProjectionContext projectionContext : context.getProjectionContexts()) { + executedDeltas.addAll(projectionContext.getExecutedDeltas()); + } + + if (context.hasExplosiveProjection()) { + PrismObject focus = context.getFocusContext().getObjectAny(); + + LOGGER.debug("Recomputing {} because there was explosive projection", focus); + + LensContext recomputeContext = contextFactory.createRecomputeContext(focus, options, task, result); + recomputeContext.setDoReconciliationForAllProjections(true); + LOGGER.trace("Recomputing {}, context:\n{}", focus, recomputeContext.debugDumpLazily()); + clockwork.run(recomputeContext, task, result); + } + + cleanupOperationResult(result); + return executedDeltas; + + } catch (ObjectAlreadyExistsException | ObjectNotFoundException | SchemaException | ExpressionEvaluationException | + CommunicationException|ConfigurationException|PolicyViolationException|SecurityViolationException|RuntimeException e) { + ModelImplUtils.recordFatalError(result, e); + throw e; + + } catch (PreconditionViolationException e) { + ModelImplUtils.recordFatalError(result, e); + // TODO: Temporary fix for 3.6.1 + // We do not want to propagate PreconditionViolationException to model API as that might break compatiblity + // ... and we do not really need that in 3.6.1 + // TODO: expose PreconditionViolationException in 3.7 + throw new SystemException(e); + + } finally { + task.markObjectActionExecutedBoundary(); + } + } + + private Collection> executeChangesRaw(Collection> deltas, + ModelExecuteOptions options, Task task, OperationResult result) + throws ExpressionEvaluationException, PolicyViolationException, SecurityViolationException, SchemaException, + ObjectNotFoundException, CommunicationException, ConfigurationException, ObjectAlreadyExistsException { + + AuditEventRecord auditRecord = new AuditEventRecord(AuditEventType.EXECUTE_CHANGES_RAW, AuditEventStage.REQUEST); + String requestIdentifier = ModelImplUtils.generateRequestIdentifier(); + auditRecord.setRequestIdentifier(requestIdentifier); + auditRecord.addDeltas(ObjectDeltaOperation.cloneDeltaCollection(deltas)); + auditRecord.setTarget(ModelImplUtils.determineAuditTarget(deltas, prismContext)); + // we don't know auxiliary information (resource, objectName) at this moment -- so we do nothing + auditHelper.audit(auditRecord, null, task, result); + + Collection> executedDeltas = new ArrayList<>(); + try { + for (ObjectDelta delta : deltas) { + OperationResult result1 = result.createSubresult(EXECUTE_CHANGE); + + // MID-2486 + if (delta.getObjectTypeClass() == ShadowType.class || delta.getObjectTypeClass() == ResourceType.class) { + try { + provisioning.applyDefinition(delta, task, result1); + } catch (SchemaException | ObjectNotFoundException | CommunicationException | ConfigurationException | RuntimeException e) { + // we can tolerate this - if there's a real problem with definition, repo call below will fail + LoggingUtils.logExceptionAsWarning(LOGGER, "Couldn't apply definition on shadow/resource raw-mode delta {} -- continuing the operation.", e, delta); + result1.muteLastSubresultError(); + } + } + + final boolean preAuthorized = ModelExecuteOptions.isPreAuthorized(options); + PrismObject objectToDetermineDetailsForAudit = null; + try { + if (delta.isAdd()) { + RepoAddOptions repoOptions = new RepoAddOptions(); + if (ModelExecuteOptions.isNoCrypt(options)) { + repoOptions.setAllowUnencryptedValues(true); + } + if (ModelExecuteOptions.isOverwrite(options)) { + repoOptions.setOverwrite(true); + } + PrismObject objectToAdd = delta.getObjectToAdd(); + if (!preAuthorized) { + securityEnforcer.authorize(ModelAuthorizationAction.RAW_OPERATION.getUrl(), null, AuthorizationParameters.Builder.buildObjectAdd(objectToAdd), null, task, result1); + securityEnforcer.authorize(ModelAuthorizationAction.ADD.getUrl(), null, AuthorizationParameters.Builder.buildObjectAdd(objectToAdd), null, task, result1); + } + String oid; + try { + oid = cacheRepositoryService.addObject(objectToAdd, repoOptions, result1); + task.recordObjectActionExecuted(objectToAdd, null, oid, ChangeType.ADD, task.getChannel(), null); + } catch (Throwable t) { + task.recordObjectActionExecuted(objectToAdd, null, null, ChangeType.ADD, task.getChannel(), t); + throw t; + } + delta.setOid(oid); + objectToDetermineDetailsForAudit = objectToAdd; + } else if (delta.isDelete()) { + QNameUtil.setTemporarilyTolerateUndeclaredPrefixes(true); // MID-2218 + try { + PrismObject existingObject = null; + try { + existingObject = cacheRepositoryService.getObject(delta.getObjectTypeClass(), delta.getOid(), null, result1); + objectToDetermineDetailsForAudit = existingObject; + } catch (Throwable t) { + if (!securityEnforcer.isAuthorized(AuthorizationConstants.AUTZ_ALL_URL, null, AuthorizationParameters.EMPTY, null, task, result1)) { + throw t; + } else { + existingObject = prismContext.createObject(delta.getObjectTypeClass()); + existingObject.setOid(delta.getOid()); + existingObject.asObjectable().setName(PolyStringType.fromOrig("Unreadable object")); + // in case of administrator's request we continue - in order to allow deleting malformed (unreadable) objects + // creating "shadow" existing object for auditing needs. + } + } + if (!preAuthorized) { + securityEnforcer.authorize(ModelAuthorizationAction.RAW_OPERATION.getUrl(), null, AuthorizationParameters.Builder.buildObjectDelete(existingObject), null, task, result1); + securityEnforcer.authorize(ModelAuthorizationAction.DELETE.getUrl(), null, AuthorizationParameters.Builder.buildObjectDelete(existingObject), null, task, result1); + } + try { + if (ObjectTypes.isClassManagedByProvisioning(delta.getObjectTypeClass())) { + ModelImplUtils.clearRequestee(task); + provisioning.deleteObject(delta.getObjectTypeClass(), delta.getOid(), + ProvisioningOperationOptions.createRaw(), null, task, result1); + } else { + cacheRepositoryService.deleteObject(delta.getObjectTypeClass(), delta.getOid(), + result1); + } + task.recordObjectActionExecuted(objectToDetermineDetailsForAudit, delta.getObjectTypeClass(), delta.getOid(), ChangeType.DELETE, task.getChannel(), null); + } catch (Throwable t) { + task.recordObjectActionExecuted(objectToDetermineDetailsForAudit, delta.getObjectTypeClass(), delta.getOid(), ChangeType.DELETE, task.getChannel(), t); + throw t; + } + } finally { + QNameUtil.setTemporarilyTolerateUndeclaredPrefixes(false); + } + } else if (delta.isModify()) { + QNameUtil.setTemporarilyTolerateUndeclaredPrefixes(true); // MID-2218 + try { + PrismObject existingObject = cacheRepositoryService.getObject(delta.getObjectTypeClass(), delta.getOid(), null, result1); + objectToDetermineDetailsForAudit = existingObject; + if (!preAuthorized) { + AuthorizationParameters autzParams = AuthorizationParameters.Builder.buildObjectDelta(existingObject, delta); + securityEnforcer.authorize(ModelAuthorizationAction.RAW_OPERATION.getUrl(), null, autzParams, null, task, result1); + securityEnforcer.authorize(ModelAuthorizationAction.MODIFY.getUrl(), null, autzParams, null, task, result1); + } + try { + cacheRepositoryService.modifyObject(delta.getObjectTypeClass(), delta.getOid(), + delta.getModifications(), result1); + task.recordObjectActionExecuted(existingObject, ChangeType.MODIFY, null); + } catch (Throwable t) { + task.recordObjectActionExecuted(existingObject, ChangeType.MODIFY, t); + throw t; + } + } finally { + QNameUtil.setTemporarilyTolerateUndeclaredPrefixes(false); + } + if (ModelExecuteOptions.isReevaluateSearchFilters(options)) { // treat filters that already exist in the object (case #2 above) + reevaluateSearchFilters(delta.getObjectTypeClass(), delta.getOid(), task, result1); + } + } else { + throw new IllegalArgumentException("Wrong delta type " + delta.getChangeType() + " in " + delta); + } + } catch (ObjectAlreadyExistsException | SchemaException | ObjectNotFoundException | ConfigurationException | CommunicationException | SecurityViolationException | RuntimeException e) { + ModelImplUtils.recordFatalError(result1, e); + throw e; + } finally { // to have a record with the failed delta as well + result1.computeStatus(); + ObjectDeltaOperation odoToAudit = new ObjectDeltaOperation<>(delta, result1); + if (objectToDetermineDetailsForAudit != null) { + odoToAudit.setObjectName(objectToDetermineDetailsForAudit.getName()); + if (objectToDetermineDetailsForAudit.asObjectable() instanceof ShadowType) { + ShadowType shadow = (ShadowType) objectToDetermineDetailsForAudit.asObjectable(); + odoToAudit.setResourceOid(ShadowUtil.getResourceOid(shadow)); + odoToAudit.setResourceName(ShadowUtil.getResourceName(shadow)); + } + } + executedDeltas.add(odoToAudit); + } + } + return executedDeltas; + } finally { + cleanupOperationResult(result); + auditRecord.setTimestamp(System.currentTimeMillis()); + auditRecord.setOutcome(result.getStatus()); + auditRecord.setEventStage(AuditEventStage.EXECUTION); + auditRecord.getDeltas().clear(); + auditRecord.getDeltas().addAll(executedDeltas); + auditHelper.audit(auditRecord, null, task, result); + + task.markObjectActionExecutedBoundary(); + } + } + + private void authorizePartialExecution(LensContext context, ModelExecuteOptions options, Task task, OperationResult result) throws SecurityViolationException, SchemaException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException { + PartialProcessingOptionsType partialProcessing = ModelExecuteOptions.getPartialProcessing(options); + if (partialProcessing != null) { + PrismObject object = context.getFocusContext().getObjectAny(); + securityEnforcer.authorize(ModelAuthorizationAction.PARTIAL_EXECUTION.getUrl(), null, AuthorizationParameters.Builder.buildObject(object), null, task, result); + } + } + + protected void cleanupOperationResult(OperationResult result) { + // Clockwork.run sets "in-progress" flag just at the root level + // and result.computeStatus() would erase it. + // So we deal with it in a special way, in order to preserve this information for the user. + if (result.isInProgress()) { + result.computeStatus(); + if (result.isSuccess()) { + result.recordInProgress(); + } + } else { + result.computeStatus(); + } + + result.cleanupResult(); + } + + private void reevaluateSearchFilters(Class objectTypeClass, String oid, Task task, OperationResult parentResult) throws SchemaException, ObjectNotFoundException, ObjectAlreadyExistsException { + OperationResult result = parentResult.createSubresult(CLASS_NAME_WITH_DOT+"reevaluateSearchFilters"); + try { + PrismObject storedObject = cacheRepositoryService.getObject(objectTypeClass, oid, null, result); + PrismObject updatedObject = storedObject.clone(); + ModelImplUtils.resolveReferences(updatedObject, cacheRepositoryService, false, true, EvaluationTimeType.IMPORT, true, prismContext, result); + ObjectDelta delta = storedObject.diff(updatedObject); + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("reevaluateSearchFilters found delta: {}", delta.debugDump()); + } + if (!delta.isEmpty()) { + try { + cacheRepositoryService.modifyObject(objectTypeClass, oid, delta.getModifications(), result); + task.recordObjectActionExecuted(updatedObject, ChangeType.MODIFY, null); + } catch (Throwable t) { + task.recordObjectActionExecuted(updatedObject, ChangeType.MODIFY, t); + throw t; + } + } + result.recordSuccess(); + } catch (SchemaException|ObjectNotFoundException|ObjectAlreadyExistsException|RuntimeException e) { + result.recordFatalError("Couldn't reevaluate search filters: "+e.getMessage(), e); + throw e; + } + } + + @Override + public void recompute(Class type, String oid, Task task, OperationResult parentResult) throws SchemaException, PolicyViolationException, ExpressionEvaluationException, ObjectNotFoundException, ObjectAlreadyExistsException, CommunicationException, ConfigurationException, SecurityViolationException { + ModelExecuteOptions options = ModelExecuteOptions.createReconcile(); + recompute(type, oid, options, task, parentResult); + } + + @Override + public void recompute(Class type, String oid, ModelExecuteOptions options, Task task, OperationResult parentResult) throws SchemaException, PolicyViolationException, ExpressionEvaluationException, ObjectNotFoundException, ObjectAlreadyExistsException, CommunicationException, ConfigurationException, SecurityViolationException { + + OperationResult result = parentResult.createMinorSubresult(RECOMPUTE); + result.addParam(OperationResult.PARAM_OID, oid); + result.addParam(OperationResult.PARAM_TYPE, type); + + enterModelMethod(); + + try { + + ModelImplUtils.clearRequestee(task); + PrismObject focus = objectResolver.getObject(type, oid, null, task, result).asPrismContainer(); + + LOGGER.debug("Recomputing {}", focus); + + LensContext lensContext = contextFactory.createRecomputeContext(focus, options, task, result); + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("Recomputing {}, context:\n{}", focus, lensContext.debugDump()); + } + clockwork.run(lensContext, task, result); + + result.computeStatus(); + + LOGGER.trace("Recomputing of {}: {}", focus, result.getStatus()); + + result.cleanupResult(); + + } catch (ExpressionEvaluationException | SchemaException | PolicyViolationException | ObjectNotFoundException | + ObjectAlreadyExistsException | CommunicationException | ConfigurationException | SecurityViolationException | + RuntimeException | Error e) { + ModelImplUtils.recordFatalError(result, e); + throw e; + + } catch (PreconditionViolationException e) { + ModelImplUtils.recordFatalError(result, e); + // TODO: Temporary fix for 3.6.1 + // We do not want to propagate PreconditionViolationException to model API as that might break compatiblity + // ... and we do not really need that in 3.6.1 + // TODO: expose PreconditionViolationException in 3.7 + throw new SystemException(e); + + } finally { + exitModelMethod(); + } + } + + private void applyDefinitions(Collection> deltas, ModelExecuteOptions options, + Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, ExpressionEvaluationException { + for(ObjectDelta delta: deltas) { + Class type = delta.getObjectTypeClass(); + if (delta.hasCompleteDefinition()) { + continue; + } + if (type == ResourceType.class || ShadowType.class.isAssignableFrom(type)) { + try { + provisioning.applyDefinition(delta, task, result); + } catch (SchemaException | ObjectNotFoundException | CommunicationException | ConfigurationException | ExpressionEvaluationException e) { + if (ModelExecuteOptions.isRaw(options)) { + ModelImplUtils.recordPartialError(result, e); + // just go on, this is raw, we need to continue even without complete schema + } else { + ModelImplUtils.recordFatalError(result, e); + throw e; + } + } + } else { + PrismObjectDefinition objDef = prismContext.getSchemaRegistry().findObjectDefinitionByCompileTimeClass(delta.getObjectTypeClass()); + if (objDef == null) { + throw new SchemaException("No definition for delta object type class: " + delta.getObjectTypeClass()); + } + boolean tolerateNoDefinition = ModelExecuteOptions.isRaw(options); + delta.applyDefinitionIfPresent(objDef, tolerateNoDefinition); + } + } + } + + @Override + public SearchResultList> searchObjects(Class type, ObjectQuery query, + Collection> rawOptions, Task task, OperationResult parentResult) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { + + Validate.notNull(type, "Object type must not be null."); + Validate.notNull(parentResult, "Operation result must not be null."); + if (query != null) { + ModelImplUtils.validatePaging(query.getPaging()); + } + + OP_LOGGER.trace("MODEL OP enter searchObjects({},{},{})", type.getSimpleName(), query, rawOptions); + + OperationResult result = parentResult.createSubresult(SEARCH_OBJECTS); + result.addParam(OperationResult.PARAM_TYPE, type); + result.addParam(OperationResult.PARAM_QUERY, query); + + Collection> options = preProcessOptionsSecurity(rawOptions, task, result); + GetOperationOptions rootOptions = SelectorOptions.findRootOptions(options); + + ObjectTypes.ObjectManager searchProvider = ObjectTypes.getObjectManagerForClass(type); + if (searchProvider == null || searchProvider == ObjectTypes.ObjectManager.MODEL || GetOperationOptions.isRaw(rootOptions)) { + searchProvider = ObjectTypes.ObjectManager.REPOSITORY; + } + result.addArbitraryObjectAsParam("searchProvider", searchProvider); + + ObjectQuery processedQuery = preProcessQuerySecurity(type, query, rootOptions, task, result); + if (isFilterNone(processedQuery, result)) { + return new SearchResultList<>(new ArrayList<>()); + } + + enterModelMethod(); // outside try-catch because if this ends with an exception, cache is not entered yet + SearchResultList> list; + try { + logQuery(processedQuery); + + try { + if (GetOperationOptions.isRaw(rootOptions)) { // MID-2218 + QNameUtil.setTemporarilyTolerateUndeclaredPrefixes(true); + } + switch (searchProvider) { + case REPOSITORY: + list = cacheRepositoryService.searchObjects(type, processedQuery, options, result); + break; + case PROVISIONING: + list = provisioning.searchObjects(type, processedQuery, options, task, result); + break; + case TASK_MANAGER: + list = taskManager.searchObjects(type, processedQuery, options, result); + break; + default: + throw new AssertionError("Unexpected search provider: " + searchProvider); + } + result.computeStatus(); + result.cleanupResult(); + } catch (CommunicationException | ConfigurationException | SchemaException | SecurityViolationException | RuntimeException | ObjectNotFoundException e) { + processSearchException(e, rootOptions, searchProvider, result); + throw e; + } finally { + QNameUtil.setTemporarilyTolerateUndeclaredPrefixes(false); + if (LOGGER.isTraceEnabled()) { + LOGGER.trace(result.dump(false)); + } + } + + if (list == null) { + list = new SearchResultList<>(new ArrayList>()); + } + + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("Basic search returned {} results (before hooks, security, etc.)", list.size()); + } + + for (PrismObject object : list) { + if (hookRegistry != null) { + for (ReadHook hook : hookRegistry.getAllReadHooks()) { + hook.invoke(object, options, task, result); + } + } + executeResolveOptions(object.asObjectable(), options, task, result); + } + + // postprocessing objects that weren't handled by their correct provider (e.g. searching for ObjectType, and retrieving tasks, resources, shadows) + // currently only resources and shadows are handled in this way + // TODO generalize this approach somehow (something like "postprocess" in task/provisioning interface) + if (searchProvider == ObjectTypes.ObjectManager.REPOSITORY && !GetOperationOptions.isRaw(rootOptions)) { + for (PrismObject object : list) { + if (object.asObjectable() instanceof ResourceType || object.asObjectable() instanceof ShadowType) { + provisioning.applyDefinition(object, task, result); + } + } + } + // better to use cache here (MID-4059) + schemaTransformer.applySchemasAndSecurityToObjects(list, rootOptions, options, null, task, result); + + } finally { + exitModelMethod(); + } + + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("Final search returned {} results (after hooks, security and all other processing)", list.size()); + } + + // TODO: log errors + + if (OP_LOGGER.isDebugEnabled()) { + OP_LOGGER.debug("MODEL OP exit searchObjects({},{},{}): {}", type.getSimpleName(), query, rawOptions, list.shortDump()); + } + if (OP_LOGGER.isTraceEnabled()) { + OP_LOGGER.trace("MODEL OP exit searchObjects({},{},{}): {}\n{}", type.getSimpleName(), query, rawOptions, list.shortDump(), + DebugUtil.debugDump(list.getList(), 1)); + } + + return list; + } + + private class ContainerOperationContext { + final boolean isCertCase; + final boolean isCaseMgmtWorkItem; + final ObjectTypes.ObjectManager manager; + final ObjectQuery refinedQuery; + + // TODO: task and result here are ugly and probably wrong + ContainerOperationContext(Class type, ObjectQuery query, Task task, OperationResult result) throws SchemaException, SecurityViolationException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException { + isCertCase = AccessCertificationCaseType.class.equals(type); + isCaseMgmtWorkItem = CaseWorkItemType.class.equals(type); + + if (!isCertCase && !isCaseMgmtWorkItem) { + throw new UnsupportedOperationException("searchContainers/countContainers methods are currently supported only for AccessCertificationCaseType and CaseWorkItemType classes"); + } + + if (isCertCase) { + refinedQuery = preProcessSubobjectQuerySecurity(AccessCertificationCaseType.class, AccessCertificationCampaignType.class, query, task, result); + manager = ObjectTypes.ObjectManager.REPOSITORY; + } else //noinspection ConstantConditions + if (isCaseMgmtWorkItem) { + refinedQuery = query; // TODO + manager = ObjectTypes.ObjectManager.REPOSITORY; + } else { + throw new IllegalStateException(); + } + } + } + + @Override + public SearchResultList searchContainers( + Class type, ObjectQuery query, Collection> rawOptions, + Task task, OperationResult parentResult) throws SchemaException, SecurityViolationException, ConfigurationException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException { + + Validate.notNull(type, "Container value type must not be null."); + Validate.notNull(parentResult, "Result type must not be null."); + if (query != null) { + ModelImplUtils.validatePaging(query.getPaging()); + } + + final OperationResult result = parentResult.createSubresult(SEARCH_CONTAINERS); + result.addParam(OperationResult.PARAM_TYPE, type); + result.addParam(OperationResult.PARAM_QUERY, query); + + final ContainerOperationContext ctx = new ContainerOperationContext<>(type, query, task, result); + + Collection> options = preProcessOptionsSecurity(rawOptions, task, result); + final GetOperationOptions rootOptions = SelectorOptions.findRootOptions(options); + + query = ctx.refinedQuery; + + if (isFilterNone(query, result)) { + return new SearchResultList<>(new ArrayList<>()); + } + + enterModelMethod(); // outside try-catch because if this ends with an exception, cache is not entered yet + SearchResultList list; + try { + logQuery(query); + + try { + if (GetOperationOptions.isRaw(rootOptions)) { // MID-2218 + QNameUtil.setTemporarilyTolerateUndeclaredPrefixes(true); + } + //noinspection SwitchStatementWithTooFewBranches + switch (ctx.manager) { + case REPOSITORY: list = cacheRepositoryService.searchContainers(type, query, options, result); break; + default: throw new IllegalStateException(); + } + result.computeStatus(); + result.cleanupResult(); + } catch (SchemaException|RuntimeException e) { + processSearchException(e, rootOptions, ctx.manager, result); + throw e; + } finally { + QNameUtil.setTemporarilyTolerateUndeclaredPrefixes(false); + if (LOGGER.isTraceEnabled()) { + LOGGER.trace(result.dump(false)); + } + } + + if (list == null) { + list = new SearchResultList<>(new ArrayList<>()); + } + + for (T object : list) { + // TODO implement read hook, if necessary + executeResolveOptions(object, options, task, result); + } + } finally { + exitModelMethod(); + } + + if (ctx.isCertCase) { + list = schemaTransformer.applySchemasAndSecurityToContainers(list, AccessCertificationCampaignType.class, + AccessCertificationCampaignType.F_CASE, rootOptions, options, null, task, result); + } else if (ctx.isCaseMgmtWorkItem) { + // TODO implement security post processing for CaseWorkItems + } else { + throw new IllegalStateException(); + } + + return list; + } + + @Override + public Integer countContainers( + Class type, ObjectQuery query, Collection> rawOptions, + Task task, OperationResult parentResult) throws SchemaException, SecurityViolationException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException { + + Validate.notNull(type, "Container value type must not be null."); + Validate.notNull(parentResult, "Result type must not be null."); + + final OperationResult result = parentResult.createSubresult(COUNT_CONTAINERS); + result.addParam(OperationResult.PARAM_TYPE, type); + result.addParam(OperationResult.PARAM_QUERY, query); + + final ContainerOperationContext ctx = new ContainerOperationContext<>(type, query, task, result); + + final Collection> options = preProcessOptionsSecurity(rawOptions, task, result); + final GetOperationOptions rootOptions = SelectorOptions.findRootOptions(options); + + query = ctx.refinedQuery; + + if (isFilterNone(query, result)) { + return 0; + } + + enterModelMethod(); // outside try-catch because if this ends with an exception, cache is not entered yet + Integer count; + try { + + logQuery(query); + + try { + //noinspection SwitchStatementWithTooFewBranches + switch (ctx.manager) { + case REPOSITORY: count = cacheRepositoryService.countContainers(type, query, options, result); break; + default: throw new IllegalStateException(); + } + result.computeStatus(); + result.cleanupResult(); + } catch (RuntimeException e) { + processSearchException(e, rootOptions, ctx.manager, result); + throw e; + } finally { + if (LOGGER.isTraceEnabled()) { + LOGGER.trace(result.dump(false)); + } + } + } finally { + exitModelMethod(); + } + + return count; + } + +// // TODO - fix this temporary implementation (perhaps by storing 'groups' in user context on logon) +// // TODO: currently we check only the direct assignments, we need to implement more complex mechanism +// public List getGroupsForUser(UserType user) { +// List retval = new ArrayList<>(); +// for (AssignmentType assignmentType : user.getAssignmentNew()) { +// ObjectReferenceType ref = assignmentType.getTargetRef(); +// if (ref != null) { +// retval.add(ref.clone().asReferenceValue()); +// } +// } +// return retval; +// } + + private ObjectQuery preProcessWorkItemSecurity(ObjectQuery query) throws SchemaException, SecurityViolationException { + // TODO uncomment the following, after our "query interpreter" will be able to interpret OR-clauses + return query; + +// if (securityEnforcer.isAuthorized(ModelAuthorizationAction.READ_ALL_WORK_ITEMS.getUrl(), null, null, null, null, null)) { +// return query; +// } +// ObjectFilter filter = query != null ? query.getFilter() : null; +// UserType currentUser = securityEnforcer.getPrincipal().getUser(); +// +// ObjectFilter secFilter = QueryBuilder.queryFor(CaseWorkItemType.class, getPrismContext()) +// .item(CaseWorkItemType.F_CANDIDATE_ROLES_REF).ref(getGroupsForUser(currentUser)) +// .or().item(CaseWorkItemType.F_ASSIGNEE_REF).ref(ObjectTypeUtil.createObjectRef(currentUser).asReferenceValue()) +// .buildFilter(); +// +// return updateObjectQuery(query, +// filter != null ? AndFilter.createAnd(filter, secFilter) : secFilter); + } + + protected boolean isFilterNone(ObjectQuery query, OperationResult result) { + if (query != null && query.getFilter() != null && query.getFilter() instanceof NoneFilter) { + LOGGER.trace("Security denied the search"); + result.recordStatus(OperationResultStatus.NOT_APPLICABLE, "Denied"); + return true; + } + return false; + } + + protected void logQuery(ObjectQuery query) { + if (!LOGGER.isTraceEnabled()) { + return; + } + if (query != null) { + if (query.getPaging() == null) { + LOGGER.trace("Searching objects with null paging. Processed query:\n{}", query.debugDump(1)); + } else { + LOGGER.trace("Searching objects from {} to {} ordered {} by {}. Processed query:\n{}", + query.getPaging().getOffset(), query.getPaging().getMaxSize(), + query.getPaging().getDirection(), query.getPaging().getOrderBy(), + query.debugDump(1)); + } + } else { + LOGGER.trace("Searching objects with null paging and null (processed) query."); + } + } + + @Override + public SearchResultMetadata searchObjectsIterative(Class type, ObjectQuery query, + final ResultHandler handler, final Collection> rawOptions, + final Task task, OperationResult parentResult) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { + + Validate.notNull(type, "Object type must not be null."); + Validate.notNull(parentResult, "Result type must not be null."); + if (query != null) { + ModelImplUtils.validatePaging(query.getPaging()); + } + + OP_LOGGER.trace("MODEL OP enter searchObjectsIterative({},{},{})", type.getSimpleName(), query, rawOptions); + + final OperationResult result = parentResult.createSubresult(SEARCH_OBJECTS); + result.addParam(OperationResult.PARAM_QUERY, query); + + final Collection> options = preProcessOptionsSecurity(rawOptions, task, result); + final GetOperationOptions rootOptions = SelectorOptions.findRootOptions(options); + ObjectTypes.ObjectManager searchProvider = ObjectTypes.getObjectManagerForClass(type); + if (searchProvider == null || searchProvider == ObjectTypes.ObjectManager.MODEL || GetOperationOptions.isRaw(rootOptions)) { + searchProvider = ObjectTypes.ObjectManager.REPOSITORY; + } + result.addArbitraryObjectAsParam("searchProvider", searchProvider); + + ObjectQuery processedQuery = preProcessQuerySecurity(type, query, rootOptions, task, result); + if (isFilterNone(processedQuery, result)) { + LOGGER.trace("Skipping search because filter is NONE"); + return null; + } + + ResultHandler internalHandler = (object, parentResult1) -> { + try { + object = object.cloneIfImmutable(); + if (hookRegistry != null) { + for (ReadHook hook : hookRegistry.getAllReadHooks()) { + hook.invoke(object, options, task, result); // TODO result or parentResult??? [med] + } + } + executeResolveOptions(object.asObjectable(), options, task, result); + schemaTransformer.applySchemasAndSecurity(object, rootOptions, options, null, task, parentResult1); + } catch (SchemaException | ObjectNotFoundException | SecurityViolationException | ExpressionEvaluationException + | CommunicationException | ConfigurationException ex) { + parentResult1.recordFatalError(ex); + throw new SystemException(ex.getMessage(), ex); + } + + OP_LOGGER.debug("MODEL OP handle searchObjects({},{},{}): {}", type.getSimpleName(), query, rawOptions, object); + if (OP_LOGGER.isTraceEnabled()) { + OP_LOGGER.trace("MODEL OP handle searchObjects({},{},{}):\n{}", type.getSimpleName(), query, rawOptions, object.debugDump(1)); + } + + return handler.handle(object, parentResult1); + }; + + SearchResultMetadata metadata; + try { + enterModelMethodNoRepoCache(); // skip using cache to avoid potentially many objects there (MID-4615, MID-4959) + logQuery(processedQuery); + + try { + switch (searchProvider) { + case REPOSITORY: metadata = cacheRepositoryService.searchObjectsIterative(type, processedQuery, internalHandler, options, true, result); break; + case PROVISIONING: metadata = provisioning.searchObjectsIterative(type, processedQuery, options, internalHandler, task, result); break; + case TASK_MANAGER: metadata = taskManager.searchObjectsIterative(type, processedQuery, options, internalHandler, result); break; + default: throw new AssertionError("Unexpected search provider: " + searchProvider); + } + result.computeStatusIfUnknown(); + result.cleanupResult(); + } catch (CommunicationException | ConfigurationException | ObjectNotFoundException | SchemaException | SecurityViolationException | ExpressionEvaluationException | RuntimeException | Error e) { + processSearchException(e, rootOptions, searchProvider, result); + throw e; + } finally { + if (LOGGER.isTraceEnabled()) { + LOGGER.trace(result.dump(false)); + } + } + } finally { + exitModelMethodNoRepoCache(); + } + + // TODO: log errors + + if (OP_LOGGER.isDebugEnabled()) { + OP_LOGGER.debug("MODEL OP exit searchObjects({},{},{}): {}", type.getSimpleName(), query, rawOptions, metadata); + } + + return metadata; + } + + private void processSearchException(Throwable e, GetOperationOptions rootOptions, + ObjectTypes.ObjectManager searchProvider, OperationResult result) { + String message; + switch (searchProvider) { + case REPOSITORY: message = "Couldn't search objects in repository"; break; + case PROVISIONING: message = "Couldn't search objects in provisioning"; break; + case TASK_MANAGER: message = "Couldn't search objects in task manager"; break; + default: message = "Couldn't search objects"; break; // should not occur + } + LoggingUtils.logUnexpectedException(LOGGER, message, e); + result.recordFatalError(message, e); + result.cleanupResult(e); + } + + @Override + public Integer countObjects(Class type, ObjectQuery query, + Collection> rawOptions, Task task, OperationResult parentResult) + throws SchemaException, ObjectNotFoundException, ConfigurationException, SecurityViolationException, CommunicationException, ExpressionEvaluationException { + + OperationResult result = parentResult.createMinorSubresult(COUNT_OBJECTS); + result.addParam(OperationResult.PARAM_QUERY, query); + + enterModelMethod(); // outside try-catch because if this ends with an exception, cache is not entered yet + Integer count; + try { + + Collection> options = preProcessOptionsSecurity(rawOptions, task, result); + GetOperationOptions rootOptions = SelectorOptions.findRootOptions(options); + + ObjectQuery processedQuery = preProcessQuerySecurity(type, query, rootOptions, task, result); + if (isFilterNone(processedQuery, result)) { + LOGGER.trace("Skipping count because filter is NONE"); + return 0; + } + + ObjectTypes.ObjectManager objectManager = ObjectTypes.getObjectManagerForClass(type); + if (GetOperationOptions.isRaw(rootOptions) || objectManager == null || objectManager == ObjectTypes.ObjectManager.MODEL) { + objectManager = ObjectTypes.ObjectManager.REPOSITORY; + } + switch (objectManager) { + case PROVISIONING: + count = provisioning.countObjects(type, processedQuery, options, task, parentResult); + break; + case REPOSITORY: + count = cacheRepositoryService.countObjects(type, processedQuery, options, parentResult); + break; + case TASK_MANAGER: + count = taskManager.countObjects(type, processedQuery, parentResult); + break; + default: throw new AssertionError("Unexpected objectManager: " + objectManager); + } + } catch (ConfigurationException | SecurityViolationException | SchemaException | ObjectNotFoundException | CommunicationException | ExpressionEvaluationException | RuntimeException | Error e) { + ModelImplUtils.recordFatalError(result, e); + throw e; + } finally { + exitModelMethod(); + } + + result.computeStatus(); + result.cleanupResult(); + return count; + + } + + @Override + @Deprecated + public PrismObject findShadowOwner(String accountOid, Task task, OperationResult parentResult) + throws ObjectNotFoundException, SecurityViolationException, SchemaException, ConfigurationException, ExpressionEvaluationException, CommunicationException { + Validate.notEmpty(accountOid, "Account oid must not be null or empty."); + Validate.notNull(parentResult, "Result type must not be null."); + + enterModelMethod(); + + PrismObject user; + + LOGGER.trace("Listing account shadow owner for account with oid {}.", new Object[]{accountOid}); + + OperationResult result = parentResult.createSubresult(LIST_ACCOUNT_SHADOW_OWNER); + result.addParam("accountOid", accountOid); + + try { + + user = cacheRepositoryService.listAccountShadowOwner(accountOid, result); + result.recordSuccess(); + } catch (ObjectNotFoundException ex) { + LoggingUtils.logException(LOGGER, "Account with oid {} doesn't exists", ex, accountOid); + result.recordFatalError("Account with oid '" + accountOid + "' doesn't exists", ex); + throw ex; + } catch (RuntimeException | Error ex) { + LoggingUtils.logException(LOGGER, "Couldn't list account shadow owner from repository" + + " for account with oid {}", ex, accountOid); + result.recordFatalError("Couldn't list account shadow owner for account with oid '" + + accountOid + "'.", ex); + throw ex; + } finally { + if (LOGGER.isTraceEnabled()) { + LOGGER.trace(result.dump(false)); + } + exitModelMethod(); + result.cleanupResult(); + } + + if (user != null) { + try { + user = user.cloneIfImmutable(); + schemaTransformer.applySchemasAndSecurity(user, null, null,null, task, result); + } catch (SchemaException | SecurityViolationException | ConfigurationException | + ExpressionEvaluationException | ObjectNotFoundException | CommunicationException ex) { + LoggingUtils.logException(LOGGER, "Couldn't list account shadow owner from repository" + + " for account with oid {}", ex, accountOid); + result.recordFatalError("Couldn't list account shadow owner for account with oid '" + + accountOid + "'.", ex); + throw ex; + } + } + + return user; + } + + @Override + public PrismObject searchShadowOwner(String shadowOid, Collection> rawOptions, Task task, OperationResult parentResult) + throws ObjectNotFoundException, SecurityViolationException, SchemaException, ConfigurationException, ExpressionEvaluationException, CommunicationException { + Validate.notEmpty(shadowOid, "Account oid must not be null or empty."); + Validate.notNull(parentResult, "Result type must not be null."); + + enterModelMethod(); + + PrismObject focus; + + LOGGER.trace("Listing account shadow owner for account with oid {}.", new Object[]{shadowOid}); + + OperationResult result = parentResult.createSubresult(LIST_ACCOUNT_SHADOW_OWNER); + result.addParam("shadowOid", shadowOid); + + try { + Collection> options = preProcessOptionsSecurity(rawOptions, task, result); + focus = cacheRepositoryService.searchShadowOwner(shadowOid, options, result); + result.recordSuccess(); + } catch (RuntimeException | Error ex) { + LoggingUtils.logException(LOGGER, "Couldn't list account shadow owner from repository" + + " for account with oid {}", ex, shadowOid); + result.recordFatalError("Couldn't list account shadow owner for account with oid '" + + shadowOid + "'.", ex); + throw ex; + } finally { + if (LOGGER.isTraceEnabled()) { + LOGGER.trace(result.dump(false)); + } + exitModelMethod(); + result.cleanupResult(); + } + + if (focus != null) { + try { + focus = focus.cloneIfImmutable(); + schemaTransformer.applySchemasAndSecurity(focus, null, null, null, task, result); + } catch (SchemaException | SecurityViolationException | ConfigurationException + | ObjectNotFoundException | CommunicationException ex) { + LoggingUtils.logException(LOGGER, "Couldn't list account shadow owner from repository" + + " for account with oid {}", ex, shadowOid); + result.recordFatalError("Couldn't list account shadow owner for account with oid '" + + shadowOid + "'.", ex); + throw ex; + } + } + + return focus; + } + + @Deprecated + @Override + public List> listResourceObjects(String resourceOid, + QName objectClass, ObjectPaging paging, Task task, OperationResult parentResult) throws SchemaException, + ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { + Validate.notEmpty(resourceOid, "Resource oid must not be null or empty."); + Validate.notNull(objectClass, "Object type must not be null."); + Validate.notNull(paging, "Paging must not be null."); + Validate.notNull(parentResult, "Result type must not be null."); + ModelImplUtils.validatePaging(paging); + + enterModelMethod(); + + List> list; + + try { + LOGGER.trace( + "Listing resource objects {} from resource, oid {}, from {} to {} ordered {} by {}.", + objectClass, resourceOid, paging.getOffset(), paging.getMaxSize(), + paging.getOrderBy(), paging.getDirection()); + + OperationResult result = parentResult.createSubresult(LIST_RESOURCE_OBJECTS); + result.addParam("resourceOid", resourceOid); + result.addParam("objectType", objectClass); + + try { + + list = provisioning.listResourceObjects(resourceOid, objectClass, paging, task, result); + + } catch (SchemaException | CommunicationException | ConfigurationException | SecurityViolationException | ObjectNotFoundException | ExpressionEvaluationException | RuntimeException | Error ex) { + ModelImplUtils.recordFatalError(result, ex); + throw ex; + } + result.recordSuccess(); + result.cleanupResult(); + + if (list == null) { + list = new ArrayList<>(); + } + } finally { + exitModelMethod(); + } + return list; + } + + // This returns OperationResult instead of taking it as in/out argument. + // This is different + // from the other methods. The testResource method is not using + // OperationResult to track its own + // execution but rather to track the execution of resource tests (that in + // fact happen in provisioning). + @Override + public OperationResult testResource(String resourceOid, Task task) throws ObjectNotFoundException { + Validate.notEmpty(resourceOid, "Resource oid must not be null or empty."); + enterModelMethod(); + LOGGER.trace("Testing resource OID: {}", new Object[]{resourceOid}); + + OperationResult testResult; + try { + testResult = provisioning.testResource(resourceOid, task); + } catch (ObjectNotFoundException ex) { + LOGGER.error("Error testing resource OID: {}: Object not found: {} ", resourceOid, ex.getMessage(), ex); + RepositoryCache.exit(); + throw ex; + } catch (SystemException ex) { + LOGGER.error("Error testing resource OID: {}: {} ", resourceOid, ex.getMessage(), ex); + RepositoryCache.exit(); + throw ex; + } catch (Exception ex) { + LOGGER.error("Error testing resource OID: {}: {} ", resourceOid, ex.getMessage(), ex); + RepositoryCache.exit(); + throw new SystemException(ex.getMessage(), ex); + } finally { + exitModelMethod(); + } + + if (testResult != null) { + LOGGER.debug("Finished testing resource OID: {}, result: {} ", resourceOid, + testResult.getStatus()); + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("Test result:\n{}", testResult.dump(false)); + } + } else { + LOGGER.error("Test resource returned null result"); + } + return testResult; + } + + // Note: The result is in the task. No need to pass it explicitly + @Override + public void importFromResource(String resourceOid, QName objectClass, Task task, + OperationResult parentResult) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { + Validate.notEmpty(resourceOid, "Resource oid must not be null or empty."); + Validate.notNull(objectClass, "Object class must not be null."); + Validate.notNull(task, "Task must not be null."); + enterModelMethod(); + LOGGER.trace("Launching import from resource with oid {} for object class {}.", new Object[]{ + resourceOid, objectClass}); + + OperationResult result = parentResult.createSubresult(IMPORT_ACCOUNTS_FROM_RESOURCE); + result.addParam("resourceOid", resourceOid); + result.addParam("objectClass", objectClass); + result.addArbitraryObjectAsParam(OperationResult.PARAM_TASK, task); + // TODO: add context to the result + + // Fetch resource definition from the repo/provisioning + ResourceType resource; + try { + resource = getObject(ResourceType.class, resourceOid, null, task, result).asObjectable(); + + if (resource.getSynchronization() == null || resource.getSynchronization().getObjectSynchronization().isEmpty()) { + OperationResult subresult = result.createSubresult(IMPORT_ACCOUNTS_FROM_RESOURCE+".check"); + subresult.recordWarning("No synchronization settings in "+resource+", import will probably do nothing"); + LOGGER.warn("No synchronization settings in "+resource+", import will probably do nothing"); + } else { + ObjectSynchronizationType syncType = resource.getSynchronization().getObjectSynchronization().iterator().next(); + if (syncType.isEnabled() != null && !syncType.isEnabled()) { + OperationResult subresult = result.createSubresult(IMPORT_ACCOUNTS_FROM_RESOURCE+".check"); + subresult.recordWarning("Synchronization is disabled for "+resource+", import will probably do nothing"); + LOGGER.warn("Synchronization is disabled for "+resource+", import will probably do nothing"); + } + } + + result.recordStatus(OperationResultStatus.IN_PROGRESS, "Task running in background"); + + importAccountsFromResourceTaskHandler.launch(resource, objectClass, task, result); + + // The launch should switch task to asynchronous. It is in/out, so no + // other action is needed + + if (!task.isAsynchronous()) { + result.recordSuccess(); + } + + result.cleanupResult(); + + } catch (ObjectNotFoundException | CommunicationException | ConfigurationException | SecurityViolationException | ExpressionEvaluationException | RuntimeException | Error ex) { + ModelImplUtils.recordFatalError(result, ex); + throw ex; + } finally { + exitModelMethod(); + } + + } + + @Override + public void importFromResource(String shadowOid, Task task, OperationResult parentResult) + throws ObjectNotFoundException, SchemaException, CommunicationException, + ConfigurationException, SecurityViolationException, ExpressionEvaluationException { + Validate.notNull(shadowOid, "Shadow OID must not be null."); + Validate.notNull(task, "Task must not be null."); + enterModelMethod(); + LOGGER.trace("Launching importing shadow {} from resource.", shadowOid); + + OperationResult result = parentResult.createSubresult(IMPORT_ACCOUNTS_FROM_RESOURCE); + result.addParam(OperationResult.PARAM_OID, shadowOid); + result.addArbitraryObjectAsParam(OperationResult.PARAM_TASK, task); + // TODO: add context to the result + + try { + boolean wasOk = importAccountsFromResourceTaskHandler.importSingleShadow(shadowOid, task, result); + + if (wasOk) { + result.recordSuccess(); + } else { + // the error should be in the result already, compute should reveal that to the top-level + result.computeStatus(); + } + + + result.cleanupResult(); + + } catch (ObjectNotFoundException | CommunicationException | ConfigurationException | SecurityViolationException | ExpressionEvaluationException| RuntimeException | Error ex) { + ModelImplUtils.recordFatalError(result, ex); + throw ex; + } finally { + exitModelMethod(); + } + + } + + @Override + public void importObjectsFromFile(File input, ImportOptionsType options, Task task, + OperationResult parentResult) throws FileNotFoundException { + OperationResult result = parentResult.createSubresult(IMPORT_OBJECTS_FROM_FILE); + FileInputStream fis = null; + try { + fis = new FileInputStream(input); + } catch (FileNotFoundException e) { + IOUtils.closeQuietly(fis); + String msg = "Error reading from file " + input + ": " + e.getMessage(); + result.recordFatalError(msg, e); + throw e; + } + try { + importObjectsFromStream(fis, PrismContext.LANG_XML, options, task, parentResult); + } catch (RuntimeException e) { + result.recordFatalError(e); + throw e; + } finally { + try { + fis.close(); + } catch (IOException e) { + LOGGER.error("Error closing file " + input + ": " + e.getMessage(), e); + } + } + result.computeStatus(); + } + + @Override + public void importObjectsFromStream(InputStream input, String language, ImportOptionsType options, Task task, OperationResult parentResult) { + enterModelMethod(); + OperationResult result = parentResult.createSubresult(IMPORT_OBJECTS_FROM_STREAM); + result.addArbitraryObjectAsParam(OperationResult.PARAM_OPTIONS, options); + result.addParam(OperationResult.PARAM_LANGUAGE, language); + try { + objectImporter.importObjects(input, language, options, task, result); + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("Import result:\n{}", result.debugDump()); + } + // No need to compute status. The validator inside will do it. + // result.computeStatus("Couldn't import object from input stream."); + } catch (RuntimeException e) { + result.recordFatalError(e.getMessage(), e); // shouldn't really occur + } finally { + exitModelMethod(); + } + result.cleanupResult(); + } + + /* + * (non-Javadoc) + * + * @see + * com.evolveum.midpoint.model.api.ModelService#discoverConnectors(com.evolveum + * .midpoint.xml.ns._public.common.common_1.ConnectorHostType, + * com.evolveum.midpoint.common.result.OperationResult) + */ + @Override + public Set discoverConnectors(ConnectorHostType hostType, Task task, OperationResult parentResult) + throws CommunicationException, SecurityViolationException, SchemaException, ConfigurationException, ObjectNotFoundException, ExpressionEvaluationException { + enterModelMethod(); + OperationResult result = parentResult.createSubresult(DISCOVER_CONNECTORS); + Set discoverConnectors; + try { + discoverConnectors = provisioning.discoverConnectors(hostType, result); + } catch (CommunicationException | RuntimeException | Error e) { + result.recordFatalError(e.getMessage(), e); + exitModelMethod(); + throw e; + } + List connectorList = new ArrayList<>(discoverConnectors); + schemaTransformer.applySchemasAndSecurityToObjectTypes(connectorList, null, null,null, task, result); + result.computeStatus("Connector discovery failed"); + exitModelMethod(); + result.cleanupResult(); + return new HashSet<>(connectorList); + } + + + /* + * (non-Javadoc) + * + * @see + * com.evolveum.midpoint.model.api.ModelService#initialize(com.evolveum. + * midpoint.common.result.OperationResult) + */ + @Override + public void postInit(OperationResult parentResult) { + systemObjectCache.invalidateCaches(); // necessary for testing situations where we re-import different system configurations with the same version (on system init) + + enterModelMethod(); + OperationResult result = parentResult.createSubresult(POST_INIT); + result.addContext(OperationResult.CONTEXT_IMPLEMENTATION_CLASS, ModelController.class); + + try { + // Repository service itself might have been initialized. + // But there are situations (e.g. in tests or after factory reset) in which only this method is called. + // So let's be conservative and rather execute repository postInit twice than zero times. + cacheRepositoryService.postInit(result); + } catch (SchemaException e) { + result.recordFatalError(e); + throw new SystemException(e.getMessage(), e); + } + + securityContextManager.setUserProfileService(focusProfileService); + + taskManager.postInit(result); + + // Initialize provisioning + provisioning.postInit(result); + + if (result.isUnknown()) { + result.computeStatus(); + } + + exitModelMethod(); + result.cleanupResult(); + } + + @Override + public void shutdown() { + + enterModelMethod(); + + provisioning.shutdown(); + +// taskManager.shutdown(); + + exitModelMethod(); + } + + @Override + public CompareResultType compareObject(PrismObject provided, + Collection> rawReadOptions, ModelCompareOptions compareOptions, + @NotNull List ignoreItems, Task task, OperationResult parentResult) + throws SchemaException, ObjectNotFoundException, SecurityViolationException, CommunicationException, + ConfigurationException, ExpressionEvaluationException { + Validate.notNull(provided, "Object must not be null or empty."); + Validate.notNull(parentResult, "Operation result must not be null."); + + OperationResult result = parentResult.createMinorSubresult(COMPARE_OBJECT); + result.addParam(OperationResult.PARAM_OID, provided.getOid()); + result.addParam(OperationResult.PARAM_NAME, provided.getName()); + result.addArbitraryObjectCollectionAsParam("readOptions", rawReadOptions); + result.addArbitraryObjectAsParam("compareOptions", compareOptions); + result.addArbitraryObjectCollectionAsParam("ignoreItems", ignoreItems); + + Collection> readOptions = preProcessOptionsSecurity(rawReadOptions, task, result); + + CompareResultType rv = new CompareResultType(); + + try { + boolean c2p = ModelCompareOptions.isComputeCurrentToProvided(compareOptions); + boolean p2c = ModelCompareOptions.isComputeProvidedToCurrent(compareOptions); + boolean returnC = ModelCompareOptions.isReturnCurrent(compareOptions); + boolean returnP = ModelCompareOptions.isReturnNormalized(compareOptions); + boolean ignoreOperational = ModelCompareOptions.isIgnoreOperationalItems(compareOptions); + + if (!c2p && !p2c && !returnC && !returnP) { + return rv; + } + PrismObject current = null; + if (c2p || p2c || returnC) { + current = fetchCurrentObject(provided.getCompileTimeClass(), provided.getOid(), provided.getName(), readOptions, task, result); + removeIgnoredItems(current, ignoreItems); + if (ignoreOperational) { + removeOperationalItems(current); + } + } + removeIgnoredItems(provided, ignoreItems); + if (ignoreOperational) { + removeOperationalItems(provided); + } + + if (c2p) { + rv.setCurrentToProvided(DeltaConvertor.toObjectDeltaType(DiffUtil.diff(current, provided))); + } + if (p2c) { + rv.setProvidedToCurrent(DeltaConvertor.toObjectDeltaType(DiffUtil.diff(provided, current))); + } + if (returnC && current != null) { + rv.setCurrentObject(current.asObjectable()); + } + if (returnP) { + rv.setNormalizedObject(provided.asObjectable()); + } + } finally { + result.computeStatus(); + result.cleanupResult(); + } + return rv; + } + + private void removeIgnoredItems(PrismObject object, List ignoreItems) { + if (object != null) { + object.getValue().removeItems(ignoreItems); + } + } + + private void removeOperationalItems(PrismObject object) { + if (object != null) { + object.getValue().removeOperationalItems(); + } + } + + private PrismObject fetchCurrentObject(Class type, String oid, PolyString name, + Collection> readOptions, Task task, + OperationResult result) + throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, + SecurityViolationException, ExpressionEvaluationException { + + if (readOptions == null) { + readOptions = new ArrayList<>(); + } + GetOperationOptions root = SelectorOptions.findRootOptions(readOptions); + if (root == null) { + readOptions.add(SelectorOptions.create(GetOperationOptions.createAllowNotFound())); + } else { + root.setAllowNotFound(true); + } + + if (oid != null) { + try { + return getObject(type, oid, readOptions, task, result); + } catch (ObjectNotFoundException e) { + return null; + } + } + if (name == null || name.getOrig() == null) { + throw new IllegalArgumentException("Neither OID nor name of the object is known."); + } + ObjectQuery nameQuery = prismContext.queryFor(type) + .item(ObjectType.F_NAME).eqPoly(name.getOrig()) + .build(); + List> objects = searchObjects(type, nameQuery, readOptions, task, result); + if (objects.isEmpty()) { + return null; + } else if (objects.size() == 1) { + return objects.get(0); + } else { + throw new SchemaException("More than 1 object of type " + type + " with the name of " + name + ": There are " + objects.size() + " of them."); + } + } + + private Collection> preProcessOptionsSecurity(Collection> options, Task task, OperationResult result) + throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException, SecurityViolationException { + GetOperationOptions rootOptions = SelectorOptions.findRootOptions(options); + if (GetOperationOptions.isAttachDiagData(rootOptions) && + !securityEnforcer.isAuthorized(AuthorizationConstants.AUTZ_ALL_URL, null, AuthorizationParameters.EMPTY, null, task, result)) { + Collection> reducedOptions = CloneUtil.cloneCollectionMembers(options); + SelectorOptions.findRootOptions(reducedOptions).setAttachDiagData(false); + return reducedOptions; + } else { + return options; + } + } + + private ObjectQuery preProcessQuerySecurity(Class objectType, ObjectQuery origQuery, GetOperationOptions rootOptions, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException, SecurityViolationException { + ObjectFilter origFilter = null; + if (origQuery != null) { + origFilter = origQuery.getFilter(); + } + AuthorizationPhaseType phase = null; + if (GetOperationOptions.isExecutionPhase(rootOptions)) { + phase = AuthorizationPhaseType.EXECUTION; + } + ObjectFilter secFilter = securityEnforcer.preProcessObjectFilter(ModelAuthorizationAction.AUTZ_ACTIONS_URLS_SEARCH, phase, objectType, null, origFilter, null, null, task, result); + return updateObjectQuery(origQuery, secFilter); + } + + // we expect that objectType is a direct parent of containerType + private ObjectQuery preProcessSubobjectQuerySecurity(Class containerType, Class objectType, ObjectQuery origQuery, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException, SecurityViolationException { + // Search containers is an operation on one object. Therefore even if it works with a search filter, it requires GET authorizations + ObjectFilter secParentFilter = securityEnforcer.preProcessObjectFilter(ModelAuthorizationAction.AUTZ_ACTIONS_URLS_GET, null, objectType, null, null, null, null, task, result); + if (secParentFilter == null || secParentFilter instanceof AllFilter) { + return origQuery; // no need to update the query + } + ObjectFilter secChildFilter; + if (secParentFilter instanceof NoneFilter) { + secChildFilter = FilterCreationUtil.createNone(prismContext); + } else { + ObjectFilter origChildFilter = origQuery != null ? origQuery.getFilter() : null; + ObjectFilter secChildFilterParentPart = prismContext.queryFactory().createExists(ItemName.fromQName(PrismConstants.T_PARENT), // fixme + containerType, prismContext, secParentFilter); + if (origChildFilter == null) { + secChildFilter = secChildFilterParentPart; + } else { + secChildFilter = prismContext.queryFactory().createAnd(origChildFilter, secChildFilterParentPart); + } + } + return updateObjectQuery(origQuery, secChildFilter); + } + + private ObjectQuery updateObjectQuery(ObjectQuery origQuery, ObjectFilter updatedFilter) { + if (origQuery != null) { + origQuery.setFilter(updatedFilter); + return origQuery; + } else if (updatedFilter == null) { + return null; + } else { + return getPrismContext().queryFactory().createQuery(updatedFilter); + } + } + + //region Task-related operations + + @Override + public boolean suspendTasks(Collection taskOids, long waitForStop, Task operationTask, OperationResult parentResult) throws SecurityViolationException, ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException { + authorizeTaskCollectionOperation(ModelAuthorizationAction.SUSPEND_TASK, taskOids, operationTask, parentResult); + return taskManager.suspendTasks(taskOids, waitForStop, parentResult); + } + + @Override + public boolean suspendTask(String taskOid, long waitForStop, Task operationTask, OperationResult parentResult) throws SecurityViolationException, ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException { + authorizeTaskOperation(ModelAuthorizationAction.SUSPEND_TASK, taskOid, operationTask, parentResult); + return taskManager.suspendTask(taskOid, waitForStop, parentResult); + } + + @Override + public boolean suspendTaskTree(String taskOid, long waitForStop, Task operationTask, OperationResult parentResult) throws SecurityViolationException, ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException { + authorizeTaskCollectionOperation(ModelAuthorizationAction.SUSPEND_TASK, singleton(taskOid), operationTask, parentResult); + return taskManager.suspendTaskTree(taskOid, waitForStop, parentResult); + } + + @Override + public void suspendAndDeleteTasks(Collection taskOids, long waitForStop, boolean alsoSubtasks, Task operationTask, OperationResult parentResult) throws SecurityViolationException, ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException { + List> taskRefs = new ArrayList<>(taskOids.size()); + + for (String taskOid : taskOids) { + PrismObject task = cacheRepositoryService.getObject(TaskType.class, taskOid, SelectorOptions.createCollection(GetOperationOptions.createRaw()), parentResult); + taskRefs.add(task); + } + + authorizeTaskCollectionOperation(ModelAuthorizationAction.DELETE, taskOids, operationTask, parentResult); + + for (PrismObject taskRef : taskRefs) { + auditTaskOperation(ObjectTypeUtil.createObjectRef(taskRef, SchemaConstants.ORG_DEFAULT).asReferenceValue(), AuditEventStage.REQUEST, operationTask, parentResult); + } + taskManager.suspendAndDeleteTasks(taskOids, waitForStop, alsoSubtasks, parentResult); + parentResult.computeStatusIfUnknown(); + for (PrismObject taskRef : taskRefs) { + auditTaskOperation(ObjectTypeUtil.createObjectRef(taskRef, SchemaConstants.ORG_DEFAULT).asReferenceValue(), AuditEventStage.EXECUTION, operationTask, parentResult); + } + } + + @Override + public void suspendAndDeleteTask(String taskOid, long waitForStop, boolean alsoSubtasks, Task operationTask, OperationResult parentResult) throws SecurityViolationException, ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException { + PrismObject task = cacheRepositoryService.getObject(TaskType.class, taskOid, SelectorOptions.createCollection(GetOperationOptions.createRaw()), parentResult); + authorizeTaskOperation(ModelAuthorizationAction.DELETE, task, operationTask, parentResult); + PrismReferenceValue taskRef = ObjectTypeUtil.createObjectRef(task, SchemaConstants.ORG_DEFAULT).asReferenceValue(); + auditTaskOperation(taskRef, AuditEventStage.REQUEST, operationTask, parentResult); + taskManager.suspendAndDeleteTask(taskOid, waitForStop, alsoSubtasks, parentResult); + auditTaskOperation(taskRef, AuditEventStage.EXECUTION, operationTask, parentResult); + } + + private void auditTaskOperation(PrismReferenceValue taskRef, AuditEventStage stage, Task operationTask, OperationResult parentResult) { + AuditEventRecord auditRecord = new AuditEventRecord(AuditEventType.DELETE_OBJECT, stage); + String requestIdentifier = ModelImplUtils.generateRequestIdentifier(); + auditRecord.setRequestIdentifier(requestIdentifier); + auditRecord.setTarget(taskRef); + ObjectDelta delta = prismContext.deltaFactory().object().createDeleteDelta(TaskType.class, taskRef.getOid()); + ObjectDeltaOperation odo = new ObjectDeltaOperation<>(delta, parentResult); + auditRecord.getDeltas().add(odo); + if (AuditEventStage.EXECUTION == stage) { + auditRecord.setOutcome(parentResult.getStatus()); + + } + auditHelper.audit(auditRecord, null, operationTask, parentResult); + } + + @Override + public void resumeTasks(Collection taskOids, Task operationTask, OperationResult parentResult) throws SecurityViolationException, ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException { + authorizeTaskCollectionOperation(ModelAuthorizationAction.RESUME_TASK, taskOids, operationTask, parentResult); + taskManager.resumeTasks(taskOids, parentResult); + } + + @Override + public void resumeTask(String taskOid, Task operationTask, OperationResult parentResult) throws SecurityViolationException, ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException { + authorizeTaskOperation(ModelAuthorizationAction.RESUME_TASK, taskOid, operationTask, parentResult); + taskManager.resumeTask(taskOid, parentResult); + } + + @Override + public void resumeTaskTree(String coordinatorOid, Task operationTask, OperationResult parentResult) throws SecurityViolationException, ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException { + authorizeTaskOperation(ModelAuthorizationAction.RESUME_TASK, coordinatorOid, operationTask, parentResult); + taskManager.resumeTaskTree(coordinatorOid, parentResult); + } + + @Override + public void scheduleTasksNow(Collection taskOids, Task operationTask, OperationResult parentResult) throws SecurityViolationException, ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException { + authorizeTaskCollectionOperation(ModelAuthorizationAction.RUN_TASK_IMMEDIATELY, taskOids, operationTask, parentResult); + taskManager.scheduleTasksNow(taskOids, parentResult); + } + + @Override + public void scheduleTaskNow(String taskOid, Task operationTask, OperationResult parentResult) throws SecurityViolationException, ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException { + authorizeTaskOperation(ModelAuthorizationAction.RUN_TASK_IMMEDIATELY, taskOid, operationTask, parentResult); + taskManager.scheduleTaskNow(taskOid, parentResult); + } + + @Override + public PrismObject getTaskByIdentifier(String identifier, Collection> rawOptions, Task operationTask, OperationResult parentResult) throws SchemaException, ObjectNotFoundException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException, CommunicationException { + Collection> options = preProcessOptionsSecurity(rawOptions, operationTask, parentResult); + PrismObject task = taskManager.getTaskTypeByIdentifier(identifier, options, parentResult); + GetOperationOptions rootOptions = SelectorOptions.findRootOptions(options); + task = task.cloneIfImmutable(); + schemaTransformer.applySchemasAndSecurity(task, rootOptions, options,null, null, parentResult); + return task; + } + + @Override + public boolean deactivateServiceThreads(long timeToWait, Task operationTask, OperationResult parentResult) throws SchemaException, SecurityViolationException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException { + securityEnforcer.authorize(ModelAuthorizationAction.STOP_SERVICE_THREADS.getUrl(), null, AuthorizationParameters.EMPTY, null, operationTask, parentResult); + return taskManager.deactivateServiceThreads(timeToWait, parentResult); + } + + @Override + public void reactivateServiceThreads(Task operationTask, OperationResult parentResult) throws SchemaException, SecurityViolationException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException { + securityEnforcer.authorize(ModelAuthorizationAction.START_SERVICE_THREADS.getUrl(), null, AuthorizationParameters.EMPTY, null, operationTask, parentResult); + taskManager.reactivateServiceThreads(parentResult); + } + + @Override + public boolean getServiceThreadsActivationState() { + return taskManager.getServiceThreadsActivationState(); + } + + @Override + public void stopSchedulers(Collection nodeIdentifiers, Task operationTask, OperationResult parentResult) throws SecurityViolationException, ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException { + authorizeNodeCollectionOperation(ModelAuthorizationAction.STOP_TASK_SCHEDULER, nodeIdentifiers, operationTask, parentResult); + taskManager.stopSchedulers(nodeIdentifiers, parentResult); + } + + @Override + public boolean stopSchedulersAndTasks(Collection nodeIdentifiers, long waitTime, Task operationTask, OperationResult parentResult) throws SecurityViolationException, ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException { + authorizeNodeCollectionOperation(ModelAuthorizationAction.STOP_TASK_SCHEDULER, nodeIdentifiers, operationTask, parentResult); + return taskManager.stopSchedulersAndTasks(nodeIdentifiers, waitTime, parentResult); + } + + @Override + public void startSchedulers(Collection nodeIdentifiers, Task operationTask, OperationResult parentResult) throws SecurityViolationException, ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException { + authorizeNodeCollectionOperation(ModelAuthorizationAction.START_TASK_SCHEDULER, nodeIdentifiers, operationTask, parentResult); + taskManager.startSchedulers(nodeIdentifiers, parentResult); + } + + @Override + public void synchronizeTasks(Task operationTask, OperationResult parentResult) throws SchemaException, SecurityViolationException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException { + securityEnforcer.authorize(ModelAuthorizationAction.SYNCHRONIZE_TASKS.getUrl(), null, AuthorizationParameters.EMPTY, null, operationTask, parentResult); + taskManager.synchronizeTasks(parentResult); + } + + @Override + public void reconcileWorkers(String oid, Task opTask, OperationResult result) + throws CommunicationException, ObjectNotFoundException, SchemaException, SecurityViolationException, + ConfigurationException, ExpressionEvaluationException, ObjectAlreadyExistsException { + securityEnforcer.authorize(AuthorizationConstants.AUTZ_ALL_URL, null, AuthorizationParameters.EMPTY, null, opTask, result); + taskManager.reconcileWorkers(oid, null, result); + } + + @Override + public void deleteWorkersAndWorkState(String rootTaskOid, boolean deleteWorkers, long subtasksWaitTime, Task operationTask, + OperationResult parentResult) + throws SecurityViolationException, ObjectNotFoundException, SchemaException, ExpressionEvaluationException, + CommunicationException, ConfigurationException { + securityEnforcer.authorize(AuthorizationConstants.AUTZ_ALL_URL, null, AuthorizationParameters.EMPTY, null, operationTask, parentResult); + taskManager.deleteWorkersAndWorkState(rootTaskOid, deleteWorkers, subtasksWaitTime, parentResult); + } + + @Override + public List getAllTaskCategories() { + return taskManager.getAllTaskCategories(); + } + + @Override + public String getHandlerUriForCategory(String category) { + return taskManager.getHandlerUriForCategory(category); + } + + private void authorizeTaskOperation(ModelAuthorizationAction action, String oid, Task task, OperationResult parentResult) throws SchemaException, ObjectNotFoundException, SecurityViolationException, ExpressionEvaluationException, CommunicationException, ConfigurationException { + authorizeTaskCollectionOperation(action, singleton(oid), task, parentResult); + } + + private void authorizeTaskOperation(ModelAuthorizationAction action, PrismObject existingTask, Task task, OperationResult parentResult) throws SchemaException, ObjectNotFoundException, SecurityViolationException, ExpressionEvaluationException, CommunicationException, ConfigurationException { + authorizeResolvedTaskCollectionOperation(action, singleton(existingTask), task, parentResult); + } + + private void authorizeTaskCollectionOperation(ModelAuthorizationAction action, Collection oids, Task task, OperationResult parentResult) throws SchemaException, ObjectNotFoundException, SecurityViolationException, ExpressionEvaluationException, CommunicationException, ConfigurationException { + if (securityEnforcer.isAuthorized(AuthorizationConstants.AUTZ_ALL_URL, null, AuthorizationParameters.EMPTY, null, task, parentResult)) { + return; + } + for (String oid : oids) { + PrismObject existingObject = cacheRepositoryService.getObject(TaskType.class, oid, null, parentResult); + securityEnforcer.authorize(action.getUrl(), null, AuthorizationParameters.Builder.buildObject(existingObject), null, task, parentResult); + } + } + + private void authorizeResolvedTaskCollectionOperation(ModelAuthorizationAction action, Collection> existingTasks, Task task, OperationResult parentResult) throws SchemaException, ObjectNotFoundException, SecurityViolationException, ExpressionEvaluationException, CommunicationException, ConfigurationException { + if (securityEnforcer.isAuthorized(AuthorizationConstants.AUTZ_ALL_URL, null, AuthorizationParameters.EMPTY, null, task, parentResult)) { + return; + } + for (PrismObject existingObject : existingTasks) { + securityEnforcer.authorize(action.getUrl(), null, AuthorizationParameters.Builder.buildObject(existingObject), null, task, parentResult); + } + } + + private void authorizeNodeCollectionOperation(ModelAuthorizationAction action, Collection identifiers, Task task, OperationResult parentResult) throws SchemaException, ObjectNotFoundException, SecurityViolationException, ExpressionEvaluationException, CommunicationException, ConfigurationException { + if (securityEnforcer.isAuthorized(AuthorizationConstants.AUTZ_ALL_URL, null, AuthorizationParameters.EMPTY, null, task, parentResult)) { + return; + } + for (String identifier : identifiers) { + PrismObject existingObject; + ObjectQuery q = ObjectQueryUtil.createNameQuery(NodeType.class, prismContext, identifier); + List> nodes = cacheRepositoryService.searchObjects(NodeType.class, q, null, parentResult); + if (nodes.isEmpty()) { + throw new ObjectNotFoundException("Node with identifier '" + identifier + "' couldn't be found."); + } else if (nodes.size() > 1) { + throw new SystemException("Multiple nodes with identifier '" + identifier + "'"); + } + existingObject = nodes.get(0); + securityEnforcer.authorize(action.getUrl(), null, AuthorizationParameters.Builder.buildObject(existingObject), null, task, parentResult); + } + } + + //endregion + + //region Workflow-related operations + @Override + public void completeWorkItem(WorkItemId workItemId, @NotNull AbstractWorkItemOutputType output, ObjectDelta additionalDelta, + Task task, OperationResult parentResult) + throws SecurityViolationException, SchemaException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException { + AbstractWorkItemOutputType outputToUse; + if (additionalDelta != null && ApprovalUtils.isApproved(output)) { + //noinspection unchecked + ObjectDeltaType additionalDeltaBean = DeltaConvertor.toObjectDeltaType(additionalDelta); + ObjectTreeDeltasType treeDeltas = new ObjectTreeDeltasType(); + treeDeltas.setFocusPrimaryDelta(additionalDeltaBean); + + WorkItemResultType newOutput = new WorkItemResultType(prismContext); + //noinspection unchecked + newOutput.asPrismContainerValue().mergeContent(output.asPrismContainerValue(), emptyList()); + newOutput.setAdditionalDeltas(treeDeltas); + outputToUse = newOutput; + } else { + outputToUse = output; + } + getWorkflowManagerChecked().completeWorkItem(workItemId, outputToUse, null, task, parentResult); + } + + @Override + public void completeWorkItem(@NotNull WorkItemId workItemId, @NotNull AbstractWorkItemOutputType output, @NotNull Task task, @NotNull OperationResult parentResult) + throws SecurityViolationException, SchemaException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException { + getWorkflowManagerChecked().completeWorkItem(workItemId, output, null, task, parentResult); + } + + @Override + public void cancelCase(String caseOid, Task task, OperationResult parentResult) throws SchemaException, + ObjectNotFoundException, SecurityViolationException, ExpressionEvaluationException, CommunicationException, + ConfigurationException, ObjectAlreadyExistsException { + getWorkflowManagerChecked().cancelCase(caseOid, task, parentResult); + } + + @Override + public void claimWorkItem(WorkItemId workItemId, Task task, OperationResult parentResult) + throws SecurityViolationException, ObjectNotFoundException, SchemaException, ObjectAlreadyExistsException, + CommunicationException, ConfigurationException, ExpressionEvaluationException { + getWorkflowManagerChecked().claimWorkItem(workItemId, task, parentResult); + } + + @Override + public void releaseWorkItem(WorkItemId workItemId, Task task, OperationResult parentResult) + throws ObjectNotFoundException, SecurityViolationException, SchemaException, ObjectAlreadyExistsException, + CommunicationException, ConfigurationException, ExpressionEvaluationException { + getWorkflowManagerChecked().releaseWorkItem(workItemId, task, parentResult); + } + + @Override + public void delegateWorkItem(WorkItemId workItemId, WorkItemDelegationRequestType delegationRequest, + Task task, OperationResult parentResult) throws ObjectNotFoundException, SecurityViolationException, SchemaException, + ExpressionEvaluationException, CommunicationException, ConfigurationException { + getWorkflowManagerChecked().delegateWorkItem(workItemId, delegationRequest, task, parentResult); + } + + //endregion + + //region Scripting (bulk actions) + @Deprecated + @Override + public void evaluateExpressionInBackground(QName objectType, ObjectFilter filter, String actionName, Task task, OperationResult parentResult) throws SchemaException, SecurityViolationException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException { + checkScriptingAuthorization(task, parentResult); + scriptingExpressionEvaluator.evaluateExpressionInBackground(objectType, filter, actionName, task, parentResult); + } + + @Override + public void evaluateExpressionInBackground(ScriptingExpressionType expression, Task task, OperationResult parentResult) throws SchemaException, SecurityViolationException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException { + checkScriptingAuthorization(task, parentResult); + scriptingExpressionEvaluator.evaluateExpressionInBackground(expression, task, parentResult); + } + + @Override + public void evaluateExpressionInBackground(ExecuteScriptType executeScriptCommand, Task task, OperationResult parentResult) throws SchemaException, SecurityViolationException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException { + checkScriptingAuthorization(task, parentResult); + scriptingExpressionEvaluator.evaluateExpressionInBackground(executeScriptCommand, task, parentResult); + } + + @Override + public void evaluateIterativeExpressionInBackground(ExecuteScriptType executeScriptCommand, Task task, OperationResult parentResult) throws SchemaException, SecurityViolationException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException { + checkScriptingAuthorization(task, parentResult); + scriptingExpressionEvaluator.evaluateIterativeExpressionInBackground(executeScriptCommand, task, parentResult); + } + + @Override + public ScriptExecutionResult evaluateExpression(ScriptingExpressionType expression, Task task, OperationResult result) throws ScriptExecutionException, SchemaException, SecurityViolationException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException { + checkScriptingAuthorization(task, result); + ExecutionContext executionContext = scriptingExpressionEvaluator.evaluateExpression(expression, task, result); + return executionContext.toExecutionResult(); + } + + @Override + public ScriptExecutionResult evaluateExpression(@NotNull ExecuteScriptType scriptExecutionCommand, + @NotNull VariablesMap initialVariables, boolean recordProgressAndIterationStatistics, @NotNull Task task, + @NotNull OperationResult result) + throws ScriptExecutionException, SchemaException, SecurityViolationException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException { + checkScriptingAuthorization(task, result); + ExecutionContext executionContext = scriptingExpressionEvaluator.evaluateExpression(scriptExecutionCommand, initialVariables, + recordProgressAndIterationStatistics, task, result); + return executionContext.toExecutionResult(); + } + + private void checkScriptingAuthorization(Task task, OperationResult parentResult) throws SchemaException, SecurityViolationException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException { + securityEnforcer.authorize(ModelAuthorizationAction.EXECUTE_SCRIPT.getUrl(), null, AuthorizationParameters.EMPTY, null, task, parentResult); + } + //endregion + + //region Certification + + @Override + public AccessCertificationCasesStatisticsType getCampaignStatistics(String campaignOid, boolean currentStageOnly, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, SecurityViolationException, ObjectAlreadyExistsException, ExpressionEvaluationException, CommunicationException, ConfigurationException { + return getCertificationManagerChecked().getCampaignStatistics(campaignOid, currentStageOnly, task, parentResult); + } + + @Override + public void cleanupCampaigns(@NotNull CleanupPolicyType policy, Task task, OperationResult result) { + getCertificationManagerChecked().cleanupCampaigns(policy, task, result); + } + + @Override + public void recordDecision(String campaignOid, long caseId, long workItemId, AccessCertificationResponseType response, String comment, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, SecurityViolationException, ObjectAlreadyExistsException, ExpressionEvaluationException, CommunicationException, ConfigurationException { + getCertificationManagerChecked().recordDecision(campaignOid, caseId, workItemId, response, comment, task, parentResult); + } + + @Deprecated + @Override + public List searchOpenWorkItems(ObjectQuery baseWorkItemsQuery, boolean notDecidedOnly, + boolean allItems, Collection> rawOptions, Task task, OperationResult parentResult) + throws ObjectNotFoundException, SchemaException, SecurityViolationException, ExpressionEvaluationException, CommunicationException, + ConfigurationException { + Collection> options = preProcessOptionsSecurity(rawOptions, task, parentResult); + return getCertificationManagerChecked().searchOpenWorkItems(baseWorkItemsQuery, notDecidedOnly, allItems, options, task, parentResult); + } + + @Deprecated + @Override + public int countOpenWorkItems(ObjectQuery baseWorkItemsQuery, boolean notDecidedOnly, boolean allItems, + Collection> rawOptions, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, SecurityViolationException, ExpressionEvaluationException, CommunicationException, ConfigurationException { + Collection> options = preProcessOptionsSecurity(rawOptions, task, parentResult); + return getCertificationManagerChecked().countOpenWorkItems(baseWorkItemsQuery, notDecidedOnly, allItems, options, task, parentResult); + } + + @Override + public void closeCampaign(String campaignOid, Task task, OperationResult result) throws ObjectNotFoundException, SchemaException, SecurityViolationException, ObjectAlreadyExistsException, ExpressionEvaluationException, CommunicationException, ConfigurationException { + getCertificationManagerChecked().closeCampaign(campaignOid, task, result); + } + + @Override + public void reiterateCampaign(String campaignOid, Task task, OperationResult result) throws ObjectNotFoundException, SchemaException, SecurityViolationException, ObjectAlreadyExistsException, ExpressionEvaluationException, CommunicationException, ConfigurationException { + getCertificationManagerChecked().reiterateCampaign(campaignOid, task, result); + } + + @Override + public void startRemediation(String campaignOid, Task task, OperationResult result) throws ObjectNotFoundException, SchemaException, SecurityViolationException, ObjectAlreadyExistsException, ExpressionEvaluationException, CommunicationException, ConfigurationException { + getCertificationManagerChecked().startRemediation(campaignOid, task, result); + } + + @Override + public void closeCurrentStage(String campaignOid, Task task, OperationResult parentResult) throws SchemaException, SecurityViolationException, ObjectNotFoundException, ObjectAlreadyExistsException, ExpressionEvaluationException, CommunicationException, ConfigurationException { + getCertificationManagerChecked().closeCurrentStage(campaignOid, task, parentResult); + } + + @Override + public void openNextStage(String campaignOid, Task task, OperationResult parentResult) throws SchemaException, SecurityViolationException, ObjectNotFoundException, ObjectAlreadyExistsException, ExpressionEvaluationException, CommunicationException, ConfigurationException { + getCertificationManagerChecked().openNextStage(campaignOid, task, parentResult); + } + + @Override + public AccessCertificationCampaignType createCampaign(String definitionOid, Task task, OperationResult parentResult) throws SchemaException, SecurityViolationException, ObjectNotFoundException, ObjectAlreadyExistsException, ExpressionEvaluationException, CommunicationException, ConfigurationException { + return getCertificationManagerChecked().createCampaign(definitionOid, task, parentResult); + } + //endregion + + @Override + public Collection> mergeObjects(Class type, + String leftOid, String rightOid, String mergeConfigurationName, Task task, OperationResult parentResult) + throws ObjectNotFoundException, SchemaException, ConfigurationException, ObjectAlreadyExistsException, ExpressionEvaluationException, CommunicationException, PolicyViolationException, SecurityViolationException { + + OperationResult result = parentResult.createSubresult(MERGE_OBJECTS); + result.addParam("leftOid", leftOid); + result.addParam("rightOid", rightOid); + result.addParam("class", type); + + enterModelMethod(); + + try { + + Collection> deltas = + objectMerger.mergeObjects(type, leftOid, rightOid, mergeConfigurationName, task, result); + + result.computeStatus(); + return deltas; + + } catch (ObjectNotFoundException | SchemaException | ConfigurationException | ObjectAlreadyExistsException | ExpressionEvaluationException | CommunicationException | PolicyViolationException | SecurityViolationException | RuntimeException | Error e) { + ModelImplUtils.recordFatalError(result, e); + throw e; + } finally { + QNameUtil.setTemporarilyTolerateUndeclaredPrefixes(false); + exitModelMethod(); + } + + } + + @NotNull + @Override + public PrismContext getPrismContext() { + return prismContext; + } + + private void enterModelMethod() { + clockworkMedic.enterModelMethod(true); + } + + private void enterModelMethodNoRepoCache() { + clockworkMedic.enterModelMethod(false); + } + + private void exitModelMethod() { + clockworkMedic.exitModelMethod(true); + } + + private void exitModelMethodNoRepoCache() { + clockworkMedic.exitModelMethod(false); + } + + //region Case Management + + @Override + public String getThreadsDump(@NotNull Task task, @NotNull OperationResult parentResult) + throws CommunicationException, ObjectNotFoundException, SchemaException, SecurityViolationException, + ConfigurationException, ExpressionEvaluationException { + securityEnforcer.authorize(ModelAuthorizationAction.READ_THREADS.getUrl(), null, AuthorizationParameters.EMPTY, null, task, parentResult); + return MiscUtil.takeThreadDump(null); + } + + @Override + public String getRunningTasksThreadsDump(@NotNull Task task, @NotNull OperationResult parentResult) + throws CommunicationException, ObjectNotFoundException, SchemaException, SecurityViolationException, + ConfigurationException, ExpressionEvaluationException { + securityEnforcer.authorize(ModelAuthorizationAction.READ_THREADS.getUrl(), null, AuthorizationParameters.EMPTY, null, task, parentResult); + return taskManager.getRunningTasksThreadsDump(parentResult); + } + + @Override + public String recordRunningTasksThreadsDump(String cause, @NotNull Task task, @NotNull OperationResult parentResult) + throws CommunicationException, ObjectNotFoundException, SchemaException, SecurityViolationException, + ConfigurationException, ExpressionEvaluationException, ObjectAlreadyExistsException { + securityEnforcer.authorize(ModelAuthorizationAction.READ_THREADS.getUrl(), null, AuthorizationParameters.EMPTY, null, task, parentResult); + return taskManager.recordRunningTasksThreadsDump(cause, parentResult); + } + + @Override + public String getTaskThreadsDump(@NotNull String taskOid, @NotNull Task task, @NotNull OperationResult parentResult) + throws CommunicationException, ObjectNotFoundException, SchemaException, SecurityViolationException, + ConfigurationException, ExpressionEvaluationException { + securityEnforcer.authorize(ModelAuthorizationAction.READ_THREADS.getUrl(), null, AuthorizationParameters.EMPTY, null, task, parentResult); + return taskManager.getTaskThreadsDump(taskOid, parentResult); + } + + //endregion + + public void notifyChange(ResourceObjectShadowChangeDescriptionType changeDescription, Task task, OperationResult parentResult) + throws SchemaException, CommunicationException, ConfigurationException, SecurityViolationException, + ObjectNotFoundException, ObjectAlreadyExistsException, ExpressionEvaluationException, PolicyViolationException { + + String oldShadowOid = changeDescription.getOldShadowOid(); + ResourceEventDescription eventDescription = new ResourceEventDescription(); + + PrismObject oldShadow; + LOGGER.trace("resolving old object"); + if (!StringUtils.isEmpty(oldShadowOid)) { + // FIXME we should not get object from resource here: it should be sufficient to retrieve object from the repository + // (and even that can be skipped, if identifiers are correctly set) ... MID-5834 + oldShadow = getObject(ShadowType.class, oldShadowOid, SelectorOptions.createCollection(GetOperationOptions.createDoNotDiscovery()), task, parentResult); + eventDescription.setOldRepoShadow(oldShadow); + LOGGER.trace("old object resolved to: {}", oldShadow.debugDumpLazily()); + } else { + LOGGER.trace("Old shadow null"); + } + + ShadowType currentResourceObjectBean = changeDescription.getCurrentShadow(); + if (currentResourceObjectBean != null) { + PrismObject currentResourceObject = currentResourceObjectBean.asPrismObject(); + prismContext.adopt(currentResourceObject); + LOGGER.trace("current resource object:\n{}", currentResourceObject.debugDumpLazily()); + eventDescription.setCurrentResourceObject(currentResourceObject); + } + + ObjectDeltaType deltaType = changeDescription.getObjectDelta(); + + if (deltaType != null) { + + PrismObject shadowToAdd; + ObjectDelta delta = prismContext.deltaFactory().object().createEmptyDelta(ShadowType.class, deltaType.getOid(), + ChangeType.toChangeType(deltaType.getChangeType())); + + if (delta.getChangeType() == ChangeType.ADD) { + if (deltaType.getObjectToAdd() == null) { + LOGGER.trace("No object to add specified. Check your delta. Add delta must contain object to add"); + throw new IllegalArgumentException("No object to add specified. Check your delta. Add delta must contain object to add"); + } + Object objToAdd = deltaType.getObjectToAdd(); + if (!(objToAdd instanceof ShadowType)) { + LOGGER.trace("Wrong object specified in change description. Expected on the the shadow type, but got " + objToAdd.getClass().getSimpleName()); + throw new IllegalArgumentException("Wrong object specified in change description. Expected on the the shadow type, but got " + objToAdd.getClass().getSimpleName()); + } + prismContext.adopt((ShadowType)objToAdd); + + shadowToAdd = ((ShadowType) objToAdd).asPrismObject(); + LOGGER.trace("object to add: {}", shadowToAdd.debugDump()); + delta.setObjectToAdd(shadowToAdd); + } else { + Collection modifications = DeltaConvertor.toModifications(deltaType.getItemDelta(), prismContext.getSchemaRegistry().findObjectDefinitionByCompileTimeClass(ShadowType.class)); + delta.addModifications(modifications); + } + ModelImplUtils.encrypt(Collections.singletonList(delta), protector, null, parentResult); + eventDescription.setDelta(delta); + } + + eventDescription.setSourceChannel(changeDescription.getChannel()); + + dispatcher.notifyEvent(eventDescription, task, parentResult); + parentResult.computeStatus(); + task.setResult(parentResult); + } + + private void computePolyStrings(Collection> deltas, ModelExecuteOptions options, + OperationResult result) { + for(ObjectDelta delta: deltas) { + delta.accept(this::computePolyStringVisit); + } + } + + private void computePolyStringVisit(Visitable visitable) { + if (!(visitable instanceof PrismProperty)) { + return; + } + PrismPropertyDefinition definition = ((PrismProperty)visitable).getDefinition(); + if (definition == null) { + return; + } + if (!QNameUtil.match(PolyStringType.COMPLEX_TYPE, definition.getTypeName())) { + return; + } + for (PrismPropertyValue pval : ((PrismProperty)visitable).getValues()) { + PolyString polyString = pval.getValue(); + if (polyString.getOrig() == null) { + String orig = localizationService.translate(polyString); + LOGGER.info("PPPP1: Filling out orig value of polyString {}: {}", polyString, orig); + polyString.setComputedOrig(orig); + polyString.recompute(prismContext.getDefaultPolyStringNormalizer()); + LOGGER.info("PPPP2: Resulting polyString: {}", polyString); + } + } + } +} From e911c7ae681f52c7286d499ec885b57fa66117df Mon Sep 17 00:00:00 2001 From: Katarina Valalikova Date: Mon, 16 Mar 2020 18:29:54 +0100 Subject: [PATCH 11/21] fix fo MID-6009 - ITSM Manual connector shadow conflict --- .../provisioning/impl/ShadowCache.java | 6368 +++++++++-------- .../impl/builtin/ManualConnectorInstance.java | 816 +-- 2 files changed, 3599 insertions(+), 3585 deletions(-) diff --git a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ShadowCache.java b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ShadowCache.java index ec4ed5154ba..5fbffa81806 100644 --- a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ShadowCache.java +++ b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ShadowCache.java @@ -1,3178 +1,3190 @@ -/* - * Copyright (c) 2010-2019 Evolveum and contributors - * - * This work is dual-licensed under the Apache License 2.0 - * and European Union Public License. See LICENSE file for details. - */ -package com.evolveum.midpoint.provisioning.impl; - -import com.evolveum.midpoint.common.Clock; -import com.evolveum.midpoint.common.crypto.CryptoUtil; -import com.evolveum.midpoint.common.refinery.RefinedAssociationDefinition; -import com.evolveum.midpoint.common.refinery.RefinedObjectClassDefinition; -import com.evolveum.midpoint.common.refinery.ShadowDiscriminatorObjectDelta; -import com.evolveum.midpoint.prism.*; -import com.evolveum.midpoint.prism.crypto.EncryptionException; -import com.evolveum.midpoint.prism.crypto.Protector; -import com.evolveum.midpoint.prism.delta.*; -import com.evolveum.midpoint.prism.match.MatchingRuleRegistry; -import com.evolveum.midpoint.prism.path.*; -import com.evolveum.midpoint.prism.polystring.PolyString; -import com.evolveum.midpoint.prism.query.*; -import com.evolveum.midpoint.prism.xml.XmlTypeConverter; -import com.evolveum.midpoint.provisioning.api.*; -import com.evolveum.midpoint.provisioning.impl.errorhandling.ErrorHandler; -import com.evolveum.midpoint.provisioning.impl.errorhandling.ErrorHandlerLocator; -import com.evolveum.midpoint.provisioning.impl.shadowmanager.ShadowManager; -import com.evolveum.midpoint.provisioning.ucf.api.*; -import com.evolveum.midpoint.provisioning.util.ProvisioningUtil; -import com.evolveum.midpoint.repo.api.RepositoryService; -import com.evolveum.midpoint.schema.*; -import com.evolveum.midpoint.schema.cache.CacheConfigurationManager; -import com.evolveum.midpoint.schema.constants.SchemaConstants; -import com.evolveum.midpoint.schema.internals.InternalCounters; -import com.evolveum.midpoint.schema.internals.InternalMonitor; -import com.evolveum.midpoint.schema.internals.InternalsConfig; -import com.evolveum.midpoint.schema.processor.*; -import com.evolveum.midpoint.schema.processor.ObjectFactory; -import com.evolveum.midpoint.schema.result.AsynchronousOperationResult; -import com.evolveum.midpoint.schema.result.AsynchronousOperationReturnValue; -import com.evolveum.midpoint.schema.result.OperationResult; -import com.evolveum.midpoint.schema.result.OperationResultStatus; -import com.evolveum.midpoint.schema.util.ObjectQueryUtil; -import com.evolveum.midpoint.schema.util.ObjectTypeUtil; -import com.evolveum.midpoint.schema.util.ResourceTypeUtil; -import com.evolveum.midpoint.schema.util.ShadowUtil; -import com.evolveum.midpoint.task.api.Task; -import com.evolveum.midpoint.task.api.TaskManager; -import com.evolveum.midpoint.util.DebugUtil; -import com.evolveum.midpoint.util.Holder; -import com.evolveum.midpoint.util.QNameUtil; -import com.evolveum.midpoint.util.exception.*; -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.resource.capabilities_3.*; -import com.evolveum.prism.xml.ns._public.types_3.ChangeTypeType; -import com.evolveum.prism.xml.ns._public.types_3.ObjectDeltaType; -import com.evolveum.prism.xml.ns._public.types_3.PolyStringType; -import com.evolveum.prism.xml.ns._public.types_3.ProtectedStringType; - -import org.apache.commons.lang.StringUtils; -import org.apache.commons.lang.Validate; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -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.Duration; -import javax.xml.datatype.XMLGregorianCalendar; -import javax.xml.namespace.QName; - - -import java.util.*; - -/** - * Shadow cache is a facade that covers all the operations with shadows. It - * takes care of splitting the operations between repository and resource, - * merging the data back, handling the errors and generally controlling the - * process. - * - * The two principal classes that do the operations are: - * ResourceObjectConvertor: executes operations on resource - * ShadowManager: executes operations in the repository - * - * @author Radovan Semancik - * @author Katarina Valalikova - * - */ -@Component -public class ShadowCache { - - private static final String OP_DELAYED_OPERATION = ShadowCache.class.getName() + ".delayedOperation"; - private static final String OP_OPERATION_RETRY = ShadowCache.class.getName() + ".operationRetry"; - private static final String OP_RESOURCE_OPERATION = ShadowCache.class.getName() + ".resourceOperation"; - private static final String OP_REFRESH_RETRY = ShadowCache.class.getName() + ".refreshRetry"; - - @Autowired - @Qualifier("cacheRepositoryService") - private RepositoryService repositoryService; - - @Autowired private ErrorHandlerLocator errorHandlerLocator; - @Autowired private ResourceManager resourceManager; - @Autowired private Clock clock; - @Autowired private PrismContext prismContext; - @Autowired private SchemaHelper schemaHelper; - @Autowired private ResourceObjectConverter resourceObjectConverter; - @Autowired private ShadowCaretaker shadowCaretaker; - @Autowired private MatchingRuleRegistry matchingRuleRegistry; - @Autowired private RelationRegistry relationRegistry; - @Autowired protected ShadowManager shadowManager; - @Autowired private ChangeNotificationDispatcher operationListener; - @Autowired private AccessChecker accessChecker; - @Autowired private TaskManager taskManager; - @Autowired private ChangeNotificationDispatcher changeNotificationDispatcher; - @Autowired private ProvisioningContextFactory ctxFactory; - @Autowired private Protector protector; - @Autowired private CacheConfigurationManager cacheConfigurationManager; - - private static final Trace LOGGER = TraceManager.getTrace(ShadowCache.class); - - /** - * Get the value of repositoryService. - * - * DO NOT USE. Only ShadowManager should access repository - * - * @return the value of repositoryService - */ - @Deprecated - public RepositoryService getRepositoryService() { - return repositoryService; - } - - public PrismContext getPrismContext() { - return prismContext; - } - - public PrismObject getShadow(String oid, PrismObject repositoryShadow, - Collection> identifiersOverride, Collection> options, - Task task, OperationResult parentResult) - throws ObjectNotFoundException, CommunicationException, SchemaException, - ConfigurationException, SecurityViolationException, ExpressionEvaluationException, EncryptionException { - - Validate.notNull(oid, "Object id must not be null."); - - if (repositoryShadow == null) { - LOGGER.trace("Start getting object with oid {}; identifiers override = {}", oid, identifiersOverride); - } else { - LOGGER.trace("Start getting object {}; identifiers override = {}", repositoryShadow, identifiersOverride); - } - - GetOperationOptions rootOptions = SelectorOptions.findRootOptions(options); - - // We are using parent result directly, not creating subresult. - // We want to hide the existence of shadow cache from the user. - - // Get the shadow from repository. There are identifiers that we need - // for accessing the object by UCF.Later, the repository object may - // have a fully cached object from the resource. - if (repositoryShadow == null) { - repositoryShadow = repositoryService.getObject(ShadowType.class, oid, null, parentResult); - LOGGER.trace("Got repository shadow object:\n{}", repositoryShadow.debugDumpLazily()); - } - - // Sanity check - if (!oid.equals(repositoryShadow.getOid())) { - parentResult.recordFatalError("Provided OID is not equal to OID of repository shadow"); - throw new IllegalArgumentException("Provided OID is not equal to OID of repository shadow"); - } - - ProvisioningContext ctx = ctxFactory.create(repositoryShadow, task, parentResult); - ctx.setGetOperationOptions(options); - ctx.assertDefinition(); - shadowCaretaker.applyAttributesDefinition(ctx, repositoryShadow); - - ResourceType resource = ctx.getResource(); - XMLGregorianCalendar now = clock.currentTimeXMLGregorianCalendar(); - - if (GetOperationOptions.isNoFetch(rootOptions) || GetOperationOptions.isRaw(rootOptions)) { - return processNoFetchGet(ctx, repositoryShadow, options, now, task, parentResult); - } - - if (!ResourceTypeUtil.isReadCapabilityEnabled(resource)) { - UnsupportedOperationException e = new UnsupportedOperationException("Resource does not support 'read' operation"); - parentResult.recordFatalError(e); - throw e; - } - - if (shouldRefreshOnRead(resource, rootOptions)) { - LOGGER.trace("Refreshing {} before reading", repositoryShadow); - ProvisioningOperationOptions refreshOpts = toProvisioningOperationOptions(rootOptions); - RefreshShadowOperation refreshShadowOperation = refreshShadow(repositoryShadow, refreshOpts, task, parentResult); - if (refreshShadowOperation != null) { - repositoryShadow = refreshShadowOperation.getRefreshedShadow(); - } - LOGGER.trace("Refreshed repository shadow:\n{}", DebugUtil.debugDumpLazily(repositoryShadow, 1)); - } - if (repositoryShadow == null) { - // Dead shadow was just removed - // TODO: is this OK? What about re-appeared objects - LOGGER.warn("DEAD shadow {} DEAD?", oid); - ObjectNotFoundException e = new ObjectNotFoundException("Resource object does not exist"); - parentResult.recordFatalError(e); - throw e; - } - - ShadowState shadowState = shadowCaretaker.determineShadowState(ctx, repositoryShadow, now); - LOGGER.trace("State of shadow {}: {}", repositoryShadow, shadowState); - - if (canImmediatelyReturnCached(options, repositoryShadow, shadowState, resource)) { - LOGGER.trace("Returning cached (repository) version of shadow {}", repositoryShadow); - PrismObject resultShadow = futurizeShadow(ctx, repositoryShadow, null, options, now); - shadowCaretaker.applyAttributesDefinition(ctx, resultShadow); - validateShadow(resultShadow, true); - return resultShadow; - } - - PrismObject resourceObject; - - if (identifiersOverride == null) { - Collection> primaryIdentifiers = ShadowUtil.getPrimaryIdentifiers(repositoryShadow); - if (primaryIdentifiers == null || primaryIdentifiers.isEmpty()) { - if (ProvisioningUtil.hasPendingAddOperation(repositoryShadow) || ShadowUtil - .isDead(repositoryShadow.asObjectable())) { - if (ProvisioningUtil.isFuturePointInTime(options)) { - // Get of uncreated or dead shadow, we want to see future state (how the shadow WILL look like). - // We cannot even try fetch operation here. We do not have the identifiers. - // But we have quite a good idea how the shadow is going to look like. Therefore we can return it. - PrismObject resultShadow = futurizeShadow(ctx, repositoryShadow, null, options, now); - shadowCaretaker.applyAttributesDefinition(ctx, resultShadow); - validateShadow(resultShadow, true); - // NOTE: do NOT re-try add operation here. It will be retried in separate task. - // re-trying the operation here would not provide big benefits and it will complicate the code. - return resultShadow; - } else { - // Get of uncreated shadow, but we want current state. Therefore we have to throw an error because - // the object does not exist yet - to our best knowledge. But we cannot really throw ObjectNotFound here. - // ObjectNotFound is a positive indication that the object does not exist. - // We do not know that for sure because resource is unavailable. The object might have been created in the meantime. - throw new GenericConnectorException( - "Unable to get object from the resource. Probably it has not been created yet because of previous unavailability of the resource."); - } - } - - // No identifiers found - SchemaException ex = new SchemaException("No primary identifiers found in the repository shadow " - + repositoryShadow + " with respect to " + resource); - parentResult.recordFatalError("No primary identifiers found in the repository shadow " + repositoryShadow, ex); - throw ex; - } - } - - Collection> identifiers = identifiersOverride != null ? identifiersOverride : - ShadowUtil.getAllIdentifiers(repositoryShadow); - try { - - try { - - resourceObject = resourceObjectConverter.getResourceObject(ctx, identifiers, true, parentResult); - - } catch (ObjectNotFoundException e) { - // This may be OK, e.g. for connectors that have running async add operation. - if (shadowState == ShadowState.CONCEPTION || shadowState == ShadowState.GESTATION) { - LOGGER.trace("{} was not found, but we can return cached shadow because it is in {} state", repositoryShadow, shadowState); - parentResult.deleteLastSubresultIfError(); // we don't want to see 'warning-like' orange boxes in GUI (TODO reconsider this) - parentResult.recordSuccess(); - - PrismObject resultShadow = futurizeShadow(ctx, repositoryShadow, null, options, now); - shadowCaretaker.applyAttributesDefinition(ctx, resultShadow); - LOGGER.trace("Returning futurized shadow:\n{}", DebugUtil.debugDumpLazily(resultShadow)); - validateShadow(resultShadow, true); - return resultShadow; - - } else { - LOGGER.trace("{} was not found, following normal error processing because shadow is in {} state", repositoryShadow, shadowState); - // This is live shadow that was not found on resource. Just re-throw the exception. It will - // be caught later and the usual error handlers will bury the shadow. - throw e; - } - } - - LOGGER.trace("Shadow returned by ResourceObjectConverter:\n{}", resourceObject.debugDumpLazily(1)); - - // Resource shadow may have different auxiliary object classes than - // the original repo shadow. Make sure we have the definition that - // applies to resource shadow. We will fix repo shadow later. - // BUT we need also information about kind/intent and these information is only - // in repo shadow, therefore the following 2 lines.. - resourceObject.asObjectable().setKind(repositoryShadow.asObjectable().getKind()); - resourceObject.asObjectable().setIntent(repositoryShadow.asObjectable().getIntent()); - ProvisioningContext shadowCtx = ctx.spawn(resourceObject); - - String operationCtx = "getting " + repositoryShadow + " was successfull."; - - resourceManager.modifyResourceAvailabilityStatus(resource.getOid(), AvailabilityStatusType.UP, operationCtx, task, parentResult, false); - - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Shadow from repository:\n{}", repositoryShadow.debugDump(1)); - LOGGER.trace("Resource object fetched from resource:\n{}", resourceObject.debugDump(1)); - } - - repositoryShadow = shadowManager.updateShadow(shadowCtx, resourceObject, null, repositoryShadow, shadowState, parentResult); - LOGGER.trace("Repository shadow after update:\n{}", repositoryShadow.debugDumpLazily(1)); - - // Complete the shadow by adding attributes from the resource object - // This also completes the associations by adding shadowRefs - PrismObject assembledShadow = completeShadow(shadowCtx, resourceObject, repositoryShadow, false, parentResult); - LOGGER.trace("Shadow when assembled:\n{}", assembledShadow.debugDumpLazily(1)); - - PrismObject resultShadow = futurizeShadow(ctx, repositoryShadow, assembledShadow, options, now); - LOGGER.trace("Futurized assembled shadow:\n{}", resultShadow.debugDumpLazily(1)); - - parentResult.recordSuccess(); - validateShadow(resultShadow, true); - return resultShadow; - - } catch (Exception ex) { - try { - PrismObject handledShadow = handleGetError(ctx, repositoryShadow, rootOptions, ex, task, parentResult); - if (handledShadow == null) { - throw ex; - } - if (parentResult.getStatus() == OperationResultStatus.FATAL_ERROR) { - // We are going to return an object. Therefore this cannot - // be fatal error, as at least some information - // is returned - parentResult.setStatus(OperationResultStatus.PARTIAL_ERROR); - } - PrismObject futurizedShadow = futurizeShadow(ctx, handledShadow, null, options, now); - validateShadow(futurizedShadow, true); - return futurizedShadow; - - } catch (GenericFrameworkException | ObjectAlreadyExistsException | PolicyViolationException e) { - throw new SystemException(e.getMessage(), e); - } - } finally { - // We need to record the fetch down here. Now it is certain that we - // are going to fetch from resource (we do not have raw/noFetch option) - InternalMonitor.recordCount(InternalCounters.SHADOW_FETCH_OPERATION_COUNT); - } - } - - private ProvisioningOperationOptions toProvisioningOperationOptions(GetOperationOptions getOpts) { - if (getOpts == null) { - return null; - } - - ProvisioningOperationOptions provisioningOpts = new ProvisioningOperationOptions(); - // for now, we are interested in forceRetry option. In the future, there can be more. - provisioningOpts.setForceRetry(getOpts.getForceRetry()); - return provisioningOpts; - } - - private boolean shouldRefreshOnRead(ResourceType resource, GetOperationOptions rootOptions) { - return GetOperationOptions.isForceRefresh(rootOptions) || GetOperationOptions.isForceRetry(rootOptions) || ResourceTypeUtil.isRefreshOnRead(resource); - } - - private PrismObject processNoFetchGet(ProvisioningContext ctx, - PrismObject repositoryShadow, Collection> options, - XMLGregorianCalendar now, Task task, OperationResult parentResult) - throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException, EncryptionException { - LOGGER.trace("Processing noFetch get for {}", repositoryShadow); - - GetOperationOptions rootOptions = SelectorOptions.findRootOptions(options); - if (!GetOperationOptions.isRaw(rootOptions)) { - // Even with noFetch we still want to delete expired pending operations. And even delete - // the shadow if needed. - repositoryShadow = refreshShadowQuick(ctx, repositoryShadow, now, task, parentResult); - } - - if (repositoryShadow == null) { - ObjectNotFoundException e = new ObjectNotFoundException("Resource object not found"); - parentResult.recordFatalError(e); - throw e; - } - - PrismObject resultShadow = futurizeShadow(ctx, repositoryShadow, null, options, now); - shadowCaretaker.applyAttributesDefinition(ctx, resultShadow); - - return resultShadow; - } - - private PrismObject futurizeShadow(ProvisioningContext ctx, PrismObject repoShadow, PrismObject resourceShadow, - Collection> options, XMLGregorianCalendar now) throws SchemaException, ConfigurationException, ObjectNotFoundException, CommunicationException, ExpressionEvaluationException { - if (!ProvisioningUtil.isFuturePointInTime(options)) { - if (resourceShadow == null) { - return repoShadow; - } else { - return resourceShadow; - } - } - return shadowCaretaker.applyPendingOperations(ctx, repoShadow, resourceShadow, false, now); - } - - private boolean canReturnCachedAfterObjectNotFound(Collection> options, - PrismObject repositoryShadow, ResourceType resource) { - if (repositoryShadow.asObjectable().getPendingOperation().isEmpty()) { - return false; - } - // TODO: which case is this exactly? - // Explicitly check the capability of the resource (primary connector), not capabilities of additional connectors - return ProvisioningUtil.isPrimaryCachingOnly(resource); - } - - private boolean canImmediatelyReturnCached(Collection> options, PrismObject repositoryShadow, ShadowState shadowState, ResourceType resource) throws ConfigurationException { - if (ProvisioningUtil.resourceReadIsCachingOnly(resource)) { - return true; - } - if (shadowState == ShadowState.TOMBSTONE) { - // Once shadow is buried it stays nine feet under. Therefore there is no point in trying to access the resource. - // NOTE: this is just for tombstone! Schroedinger's shadows (corpse) will still work as if they were alive. - return true; - } - long stalenessOption = GetOperationOptions.getStaleness(SelectorOptions.findRootOptions(options)); - PointInTimeType pit = GetOperationOptions.getPointInTimeType(SelectorOptions.findRootOptions(options)); - if (pit == null) { - if (stalenessOption > 0) { - pit = PointInTimeType.CACHED; - } else { - pit = PointInTimeType.CURRENT; - } - } - switch (pit) { - case CURRENT: - // We need current reliable state. Never return cached data. - return false; - case CACHED: - return isCachedShadowValid(options, repositoryShadow, resource); - case FUTURE: - // We could, e.g. if there is a pending create operation. But let's try real get operation first. - return false; - default: - throw new IllegalArgumentException("Unknown point in time: "+pit); - } - } - - private boolean isCachedShadowValid(Collection> options, PrismObject repositoryShadow, ResourceType resource) throws ConfigurationException { - long stalenessOption = GetOperationOptions.getStaleness(SelectorOptions.findRootOptions(options)); - if (stalenessOption == 0L) { - return false; - } - CachingMetadataType cachingMetadata = repositoryShadow.asObjectable().getCachingMetadata(); - if (cachingMetadata == null) { - if (stalenessOption == Long.MAX_VALUE) { - // We must return cached version but there is no cached version. - throw new ConfigurationException("Cached version of "+repositoryShadow+" requested, but there is no cached value"); - } - return false; - } - if (stalenessOption == Long.MAX_VALUE) { - return true; - } - - XMLGregorianCalendar retrievalTimestamp = cachingMetadata.getRetrievalTimestamp(); - if (retrievalTimestamp == null) { - return false; - } - long retrievalTimestampMillis = XmlTypeConverter.toMillis(retrievalTimestamp); - return (clock.currentTimeMillis() - retrievalTimestampMillis < stalenessOption); - } - - private boolean isCompensate(GetOperationOptions rootOptions) { - return !GetOperationOptions.isDoNotDiscovery(rootOptions); - } - - public String addShadow(PrismObject shadowToAdd, OperationProvisioningScriptsType scripts, - ResourceType resource, ProvisioningOperationOptions options, Task task, - OperationResult parentResult) throws CommunicationException, GenericFrameworkException, - ObjectAlreadyExistsException, SchemaException, ObjectNotFoundException, - ConfigurationException, SecurityViolationException, PolicyViolationException, ExpressionEvaluationException, EncryptionException { - Validate.notNull(shadowToAdd, "Object to add must not be null."); - - InternalMonitor.recordCount(InternalCounters.SHADOW_CHANGE_OPERATION_COUNT); - - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Start adding shadow object{}:\n{}", getAdditionalOperationDesc(scripts, options), shadowToAdd.debugDump(1)); - } - - ProvisioningContext ctx = ctxFactory.create(shadowToAdd, task, parentResult); - try { - ctx.assertDefinition(); - } catch (SchemaException e) { - parentResult.recordFatalError(e); - ResourceOperationDescription operationDescription = ProvisioningUtil.createResourceFailureDescription( - shadowToAdd, ctx.getResource(), shadowToAdd.createAddDelta(), parentResult); - operationListener.notifyFailure(operationDescription, task, parentResult); - throw e; - } - - ProvisioningOperationState>> opState = new ProvisioningOperationState<>(); - - return addShadowAttempt(ctx, shadowToAdd, scripts, opState, options, task, parentResult); - } - - private String addShadowAttempt(ProvisioningContext ctx, - PrismObject shadowToAdd, - OperationProvisioningScriptsType scripts, - ProvisioningOperationState>> opState, - ProvisioningOperationOptions options, - Task task, - OperationResult parentResult) - throws CommunicationException, GenericFrameworkException, - ObjectAlreadyExistsException, SchemaException, ObjectNotFoundException, - ConfigurationException, SecurityViolationException, PolicyViolationException, ExpressionEvaluationException, EncryptionException { - - PrismContainer attributesContainer = shadowToAdd.findContainer(ShadowType.F_ATTRIBUTES); - if (attributesContainer == null || attributesContainer.isEmpty()) { - SchemaException e = new SchemaException("Attempt to add shadow without any attributes: " + shadowToAdd); - parentResult.recordFatalError(e); - ResourceOperationDescription operationDescription = ProvisioningUtil.createResourceFailureDescription( - shadowToAdd, ctx.getResource(), shadowToAdd.createAddDelta(), parentResult); - operationListener.notifyFailure(operationDescription, task, parentResult); - throw e; - } - if (!(attributesContainer instanceof ResourceAttributeContainer)) { - shadowCaretaker.applyAttributesDefinition(ctx, shadowToAdd); - attributesContainer = shadowToAdd.findContainer(ShadowType.F_ATTRIBUTES); - } - -// if (opState.getRepoShadow() != null) { -// // HACK HACK HACK, not really right solution. -// // We need this for reliable uniqueness check in preAddChecks() and addResourceObject() -// // Maybe the right solution would be to pass opState as a parameter to addResourceObject()? -// // Or maybe addResourceObject() should not check uniqueness and we should check it here? -// shadowToAdd.setOid(opState.getRepoShadow().getOid()); -// } - - preAddChecks(ctx, shadowToAdd, opState, task, parentResult); - - shadowManager.addNewProposedShadow(ctx, shadowToAdd, opState, task, parentResult); - - preprocessEntitlements(ctx, shadowToAdd, parentResult); - - shadowCaretaker.applyAttributesDefinition(ctx, shadowToAdd); - shadowManager.setKindIfNecessary(shadowToAdd.asObjectable(), ctx.getObjectClassDefinition()); - accessChecker.checkAdd(ctx, shadowToAdd, parentResult); - PrismObject addedShadow = null; - OperationResultStatus finalOperationStatus = null; - - if (shouldExecuteResourceOperationDirectly(ctx)) { - - ConnectorOperationOptions connOptions = createConnectorOperationOptions(ctx, options, parentResult); - - LOGGER.trace("ADD {}: resource operation, execution starting", shadowToAdd); - - try { - - // RESOURCE OPERATION: add - AsynchronousOperationReturnValue> asyncReturnValue = - resourceObjectConverter.addResourceObject(ctx, shadowToAdd, scripts, connOptions, false, parentResult); - opState.processAsyncResult(asyncReturnValue); - addedShadow = asyncReturnValue.getReturnValue(); - - } catch (ObjectAlreadyExistsException e) { - - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Object already exists error when trying to add {}, exploring the situation", ShadowUtil.shortDumpShadow(shadowToAdd)); - } - - // This exception may still be OK in some cases. Such as: - // We are trying to add a shadow to a semi-manual connector. - // But the resource object was recently deleted. The object is - // still in the backing store (CSV file) because of a grace - // period. Obviously, attempt to add such object would fail. - // So, we need to handle this case specially. (MID-4414) - - OperationResult failedOperationResult = parentResult.getLastSubresult(); - - if (hasDeadShadowWithDeleteOperation(ctx, shadowToAdd, parentResult)) { - - if (failedOperationResult.isError()) { - failedOperationResult.setStatus(OperationResultStatus.HANDLED_ERROR); - } - - // Try again, this time without explicit uniqueness check - try { - - LOGGER.trace("ADD {}: retrying resource operation without uniqueness check (previous dead shadow found), execution starting", shadowToAdd); - AsynchronousOperationReturnValue> asyncReturnValue = - resourceObjectConverter - .addResourceObject(ctx, shadowToAdd, scripts, connOptions, true, parentResult); - opState.processAsyncResult(asyncReturnValue); - addedShadow = asyncReturnValue.getReturnValue(); - - } catch (ObjectAlreadyExistsException innerException) { - // Mark shadow dead before we handle the error. ADD operation obviously failed. Therefore this particular - // shadow was not created as resource object. It is dead on the spot. Make sure that error handler won't confuse - // this shadow with the conflicting shadow that it is going to discover. - // This may also be a gestation quantum state collapsing to tombstone - shadowManager.markShadowTombstone(opState.getRepoShadow(), parentResult); - finalOperationStatus = handleAddError(ctx, shadowToAdd, options, opState, innerException, failedOperationResult, task, parentResult); - } catch (Exception innerException) { - finalOperationStatus = handleAddError(ctx, shadowToAdd, options, opState, innerException, parentResult.getLastSubresult(), task, parentResult); - } - - } else { - // Mark shadow dead before we handle the error. ADD operation obviously failed. Therefore this particular - // shadow was not created as resource object. It is dead on the spot. Make sure that error handler won't confuse - // this shadow with the conflicting shadow that it is going to discover. - // This may also be a gestation quantum state collapsing to tombstone - shadowManager.markShadowTombstone(opState.getRepoShadow(), parentResult); - finalOperationStatus = handleAddError(ctx, shadowToAdd, options, opState, e, failedOperationResult, task, parentResult); - } - - } catch (Exception e) { - finalOperationStatus = handleAddError(ctx, shadowToAdd, options, opState, e, parentResult.getLastSubresult(), task, parentResult); - } - - LOGGER.debug("ADD {}: resource operation executed, operation state: {}", shadowToAdd, opState.shortDumpLazily()); - - } else { - opState.setExecutionStatus(PendingOperationExecutionStatusType.EXECUTION_PENDING); - // Create dummy subresult with IN_PROGRESS state. - // This will force the entire result (parent) to be IN_PROGRESS rather than SUCCESS. - OperationResult delayedSubresult = parentResult.createSubresult(OP_DELAYED_OPERATION); - delayedSubresult.setStatus(OperationResultStatus.IN_PROGRESS); - LOGGER.debug("ADD {}: resource operation NOT executed, execution pending", shadowToAdd); - } - - // REPO OPERATION: add - // This is where the repo shadow is created or updated (if needed) - shadowManager.recordAddResult(ctx, shadowToAdd, opState, parentResult); - - if (addedShadow == null) { - addedShadow = shadowToAdd; - } - addedShadow.setOid(opState.getRepoShadow().getOid()); - - notifyAfterAdd(ctx, addedShadow, opState, task, parentResult); - - setParentOperationStatus(parentResult, opState, finalOperationStatus); - - return opState.getRepoShadow().getOid(); - } - - private void setParentOperationStatus(OperationResult parentResult, - ProvisioningOperationState opState, - OperationResultStatus finalOperationStatus) { - if (finalOperationStatus != null) { - parentResult.setStatus(finalOperationStatus); - } else { - if (opState.isCompleted()) { - parentResult.computeStatus(); - } else { - parentResult.recordInProgress(); - } - } - parentResult.setAsynchronousOperationReference(opState.getAsynchronousOperationReference()); - } - - private boolean hasDeadShadowWithDeleteOperation(ProvisioningContext ctx, - PrismObject shadowToAdd, - OperationResult parentResult) - throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, ExpressionEvaluationException { - - - Collection> previousDeadShadows = shadowManager.lookForPreviousDeadShadows(ctx, shadowToAdd, parentResult); - if (previousDeadShadows.isEmpty()) { - return false; - } - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Previous dead shadows:\n{}", DebugUtil.debugDump(previousDeadShadows, 1)); - } - - XMLGregorianCalendar now = clock.currentTimeXMLGregorianCalendar(); - for (PrismObject previousDeadShadow : previousDeadShadows) { - if (shadowCaretaker.findPreviousPendingLifecycleOperationInGracePeriod(ctx, previousDeadShadow, now) == ChangeTypeType.DELETE) { - return true; - } - } - return false; - } - - private PrismObject handleGetError(ProvisioningContext ctx, - PrismObject repositoryShadow, - GetOperationOptions rootOptions, - Exception cause, - Task task, - OperationResult parentResult) throws SchemaException, GenericFrameworkException, CommunicationException, ObjectNotFoundException, ObjectAlreadyExistsException, ConfigurationException, SecurityViolationException, PolicyViolationException, ExpressionEvaluationException { - ErrorHandler handler = errorHandlerLocator.locateErrorHandler(cause); - if (handler == null) { - parentResult.recordFatalError("Error without a handler: " + cause.getMessage(), cause); - throw new SystemException(cause.getMessage(), cause); - } - LOGGER.debug("Handling provisioning GET exception {}: {}", cause.getClass(), cause.getMessage()); - return handler.handleGetError(ctx, repositoryShadow, rootOptions, cause, task, parentResult); - } - - private OperationResultStatus handleAddError(ProvisioningContext ctx, - PrismObject shadowToAdd, - ProvisioningOperationOptions options, - ProvisioningOperationState>> opState, - Exception cause, - OperationResult failedOperationResult, - Task task, - OperationResult parentResult) - throws SchemaException, GenericFrameworkException, CommunicationException, ObjectNotFoundException, ObjectAlreadyExistsException, ConfigurationException, SecurityViolationException, PolicyViolationException, ExpressionEvaluationException { - - // TODO: record operationExecution - - ErrorHandler handler = errorHandlerLocator.locateErrorHandler(cause); - if (handler == null) { - parentResult.recordFatalError("Error without a handler: " + cause.getMessage(), cause); - throw new SystemException(cause.getMessage(), cause); - } - LOGGER.debug("Handling provisioning ADD exception {}: {}", cause.getClass(), cause.getMessage()); - try { - - OperationResultStatus finalStatus = handler.handleAddError(ctx, shadowToAdd, options, opState, cause, failedOperationResult, task, parentResult); - LOGGER.debug("Handled provisioning ADD exception, final status: {}, operation state: {}", finalStatus, opState.shortDumpLazily()); - return finalStatus; - - } catch (CommonException e) { - LOGGER.debug("Handled provisioning ADD exception, final exception: {}, operation state: {}", e, opState.shortDumpLazily()); - ObjectDelta delta = shadowToAdd.createAddDelta(); - handleErrorHandlerException(ctx, opState, delta, task, parentResult); - throw e; - } - - } - - private void handleErrorHandlerException(ProvisioningContext ctx, - ProvisioningOperationState opState, - ObjectDelta delta, - Task task, OperationResult parentResult) throws SchemaException, ConfigurationException, ObjectNotFoundException, CommunicationException, ObjectAlreadyExistsException, ExpressionEvaluationException { - // Error handler had re-thrown the exception. We will throw the exception later. But first we need to record changes in opState. - shadowManager.recordOperationException(ctx, opState, delta, parentResult); - - PrismObject shadow = opState.getRepoShadow(); - if (delta.isAdd()) { - // This is more precise. Besides, there is no repo shadow in some cases (e.g. adding protected shadow). - shadow = delta.getObjectToAdd(); - } - ResourceOperationDescription operationDescription = ProvisioningUtil.createResourceFailureDescription(shadow, ctx.getResource(), delta, parentResult); - operationListener.notifyFailure(operationDescription, task, parentResult); - } - - private OperationResultStatus handleModifyError(ProvisioningContext ctx, - PrismObject repoShadow, - Collection modifications, - ProvisioningOperationOptions options, - ProvisioningOperationState>>> opState, - Exception cause, - OperationResult failedOperationResult, - Task task, - OperationResult parentResult) - throws SchemaException, GenericFrameworkException, CommunicationException, ObjectNotFoundException, ObjectAlreadyExistsException, ConfigurationException, SecurityViolationException, PolicyViolationException, ExpressionEvaluationException { - - // TODO: record operationExecution - - ErrorHandler handler = errorHandlerLocator.locateErrorHandler(cause); - if (handler == null) { - parentResult.recordFatalError("Error without a handler: " + cause.getMessage(), cause); - throw new SystemException(cause.getMessage(), cause); - } - LOGGER.debug("Handling provisioning MODIFY exception {}: {}", cause.getClass(), cause.getMessage()); - try { - - OperationResultStatus finalStatus = handler.handleModifyError(ctx, repoShadow, modifications, options, opState, cause, failedOperationResult, task, parentResult); - LOGGER.debug("Handled provisioning MODIFY exception, final status: {}, operation state: {}", finalStatus, opState.shortDumpLazily()); - return finalStatus; - - } catch (CommonException e) { - LOGGER.debug("Handled provisioning MODIFY exception, final exception: {}, operation state: {}", e, opState.shortDumpLazily()); - ObjectDelta delta = repoShadow.createModifyDelta(); - delta.addModifications(modifications); - handleErrorHandlerException(ctx, opState, delta, task, parentResult); - throw e; - } - } - - private OperationResultStatus handleDeleteError(ProvisioningContext ctx, - PrismObject repoShadow, - ProvisioningOperationOptions options, - ProvisioningOperationState opState, - Exception cause, - OperationResult failedOperationResult, - Task task, - OperationResult parentResult) - throws SchemaException, GenericFrameworkException, CommunicationException, ObjectNotFoundException, ObjectAlreadyExistsException, ConfigurationException, SecurityViolationException, PolicyViolationException, ExpressionEvaluationException { - - ErrorHandler handler = errorHandlerLocator.locateErrorHandler(cause); - if (handler == null) { - parentResult.recordFatalError("Error without a handler: " + cause.getMessage(), cause); - throw new SystemException(cause.getMessage(), cause); - } - LOGGER.debug("Handling provisioning DELETE exception {}: {}", cause.getClass(), cause.getMessage()); - try { - - OperationResultStatus finalStatus = handler.handleDeleteError(ctx, repoShadow, options, opState, cause, failedOperationResult, task, parentResult); - LOGGER.debug("Handled provisioning DELETE exception, final status: {}, operation state: {}", finalStatus, opState.shortDumpLazily()); - return finalStatus; - - } catch (CommonException e) { - LOGGER.debug("Handled provisioning DELETE exception, final exception: {}, operation state: {}", e, opState.shortDumpLazily()); - ObjectDelta delta = repoShadow.createDeleteDelta(); - handleErrorHandlerException(ctx, opState, delta, task, parentResult); - throw e; - } - - } - - private void notifyAfterAdd( - ProvisioningContext ctx, - PrismObject addedShadow, - ProvisioningOperationState>> opState, - Task task, - OperationResult parentResult) - throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException { - ObjectDelta delta = DeltaFactory.Object.createAddDelta(addedShadow); - ResourceOperationDescription operationDescription = createSuccessOperationDescription(ctx, addedShadow, - delta, parentResult); - - if (opState.isExecuting()) { - operationListener.notifyInProgress(operationDescription, task, parentResult); - } else if (opState.isCompleted()) { - operationListener.notifySuccess(operationDescription, task, parentResult); - } - } - - private void preAddChecks(ProvisioningContext ctx, PrismObject shadow, ProvisioningOperationState>> opState, Task task, OperationResult result) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException, ObjectAlreadyExistsException, SecurityViolationException { - checkConstraints(ctx, shadow, opState, task, result); - validateSchema(ctx, shadow, task, result); - } - - private void checkConstraints(ProvisioningContext ctx, PrismObject shadow, ProvisioningOperationState>> opState, Task task, OperationResult result) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException, ObjectAlreadyExistsException, SecurityViolationException { - ShadowCheckType shadowConstraintsCheck = ResourceTypeUtil.getShadowConstraintsCheck(ctx.getResource()); - if (shadowConstraintsCheck == ShadowCheckType.NONE) { - return; - } - - String shadowOid = shadow.getOid(); - if (opState.getRepoShadow() != null) { - shadowOid = opState.getRepoShadow().getOid(); - } - - ConstraintsChecker checker = new ConstraintsChecker(); - checker.setRepositoryService(repositoryService); - checker.setCacheConfigurationManager(cacheConfigurationManager); - checker.setShadowCache(this); - checker.setPrismContext(prismContext); - checker.setProvisioningContext(ctx); - checker.setShadowObject(shadow); - checker.setShadowOid(shadowOid); - checker.setConstraintViolationConfirmer(conflictingShadowCandidate -> !Boolean.TRUE.equals(conflictingShadowCandidate.asObjectable().isDead()) ); - checker.setUseCache(false); - - ConstraintsCheckingResult retval = checker.check(task, result); - - LOGGER.trace("Checked {} constraints, result={}", shadow.debugDump(), retval.isSatisfiesConstraints()); - if (!retval.isSatisfiesConstraints()) { - throw new ObjectAlreadyExistsException("Conflicting shadow already exists on "+ctx.getResource()); - } - } - - private void validateSchema(ProvisioningContext ctx, PrismObject shadow, Task task, OperationResult result) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException { - if (ResourceTypeUtil.isValidateSchema(ctx.getResource())) { - ShadowUtil.validateAttributeSchema(shadow, ctx.getObjectClassDefinition()); - } - } - - private boolean shouldExecuteResourceOperationDirectly(ProvisioningContext ctx) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException { - if (ctx.isPropagation()) { - return true; - } - ResourceConsistencyType consistency = ctx.getResource().getConsistency(); - if (consistency == null) { - return true; - } - Duration operationGroupingInterval = consistency.getOperationGroupingInterval(); - if (operationGroupingInterval == null) { - return true; - } - return false; - } - - private ResourceOperationDescription createSuccessOperationDescription(ProvisioningContext ctx, - PrismObject shadowType, ObjectDelta delta, OperationResult parentResult) - throws ObjectNotFoundException, SchemaException, CommunicationException, - ConfigurationException, ExpressionEvaluationException { - ResourceOperationDescription operationDescription = new ResourceOperationDescription(); - operationDescription.setCurrentShadow(shadowType); - operationDescription.setResource(ctx.getResource().asPrismObject()); - if (ctx.getTask() != null) { - operationDescription.setSourceChannel(ctx.getTask().getChannel()); - } - operationDescription.setObjectDelta(delta); - operationDescription.setResult(parentResult); - return operationDescription; - } - - public String modifyShadow(PrismObject repoShadow, - Collection modifications, OperationProvisioningScriptsType scripts, - ProvisioningOperationOptions options, Task task, OperationResult parentResult) - throws CommunicationException, GenericFrameworkException, ObjectNotFoundException, - SchemaException, ConfigurationException, SecurityViolationException, PolicyViolationException, ExpressionEvaluationException, EncryptionException, ObjectAlreadyExistsException { - - Validate.notNull(repoShadow, "Object to modify must not be null."); - Validate.notNull(modifications, "Object modification must not be null."); - - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Start modifying {}{}:\n{}", repoShadow, getAdditionalOperationDesc(scripts, options), - DebugUtil.debugDump(modifications, 1)); - } - - InternalMonitor.recordCount(InternalCounters.SHADOW_CHANGE_OPERATION_COUNT); - - Collection additionalAuxiliaryObjectClassQNames = new ArrayList<>(); - for (ItemDelta modification : modifications) { - if (ShadowType.F_AUXILIARY_OBJECT_CLASS.equivalent(modification.getPath())) { - PropertyDelta auxDelta = (PropertyDelta) modification; - for (PrismPropertyValue pval : auxDelta.getValues(QName.class)) { - additionalAuxiliaryObjectClassQNames.add(pval.getValue()); - } - } - } - - ProvisioningContext ctx = ctxFactory.create(repoShadow, additionalAuxiliaryObjectClassQNames, task, parentResult); - ctx.assertDefinition(); - - ProvisioningOperationState>>> opState = new ProvisioningOperationState<>(); - opState.setRepoShadow(repoShadow); - - // if not explicitly we want to force retry operations during modify - // it is quite cheap and probably more safe then not do it - if (options == null) { - options = ProvisioningOperationOptions.createForceRetry(Boolean.TRUE); - } else if (options.getForceRetry() == null) { - options.setForceRetry(Boolean.TRUE); - } - - return modifyShadowAttempt(ctx, modifications, scripts, options, opState, task, parentResult); - } - - private String modifyShadowAttempt(ProvisioningContext ctx, - Collection modifications, - OperationProvisioningScriptsType scripts, - ProvisioningOperationOptions options, - ProvisioningOperationState>>> opState, - Task task, OperationResult parentResult) - throws CommunicationException, GenericFrameworkException, ObjectNotFoundException, - SchemaException, ConfigurationException, SecurityViolationException, PolicyViolationException, ExpressionEvaluationException, EncryptionException, ObjectAlreadyExistsException { - - PrismObject repoShadow = opState.getRepoShadow(); - - XMLGregorianCalendar now = clock.currentTimeXMLGregorianCalendar(); - - PendingOperationType duplicateOperation = shadowManager.checkAndRecordPendingModifyOperationBeforeExecution(ctx, repoShadow, modifications, opState, task, parentResult); - if (duplicateOperation != null) { - parentResult.recordInProgress(); - return repoShadow.getOid(); - } - - shadowCaretaker.applyAttributesDefinition(ctx, repoShadow); - - accessChecker.checkModify(ctx, repoShadow, modifications, parentResult); - - preprocessEntitlements(ctx, modifications, "delta for shadow " + repoShadow.getOid(), parentResult); - - OperationResultStatus finalOperationStatus = null; - - if (shadowManager.isRepositoryOnlyModification(modifications)) { - opState.setExecutionStatus(PendingOperationExecutionStatusType.COMPLETED); - LOGGER.debug("MODIFY {}: repository-only modification", repoShadow); - } else { - if (shouldExecuteResourceOperationDirectly(ctx)) { - LOGGER.trace("MODIFY {}: resource modification, execution starting\n{}", repoShadow, DebugUtil.debugDumpLazily(modifications)); - - RefreshShadowOperation refreshShadowOperation = null; - if (shouldRefresh(repoShadow)) { - refreshShadowOperation = refreshShadow(repoShadow, options, task, parentResult); - } - - if (refreshShadowOperation != null) { - repoShadow = refreshShadowOperation.getRefreshedShadow(); - } - - if (repoShadow == null) { - LOGGER.trace("Shadow is gone. Nothing more to do"); - parentResult.recordPartialError("Shadow disappeared during modify."); - throw new ObjectNotFoundException("Shadow is gone."); - } - - ConnectorOperationOptions connOptions = createConnectorOperationOptions(ctx, options, parentResult); - - try { - - - if (!shouldExecuteModify(refreshShadowOperation)) { - ProvisioningUtil.postponeModify(ctx, repoShadow, modifications, opState, refreshShadowOperation.getRefreshResult(), parentResult); - shadowManager.recordModifyResult(ctx, repoShadow, modifications, opState, now, parentResult); - return repoShadow.getOid(); - } else { - LOGGER.trace("Shadow exists: {}", repoShadow.debugDump()); - } - - AsynchronousOperationReturnValue>> asyncReturnValue = - resourceObjectConverter - .modifyResourceObject(ctx, repoShadow, scripts, connOptions, modifications, now, parentResult); - opState.processAsyncResult(asyncReturnValue); - - Collection> sideEffectChanges = asyncReturnValue.getReturnValue(); - if (sideEffectChanges != null) { - ItemDeltaCollectionsUtil.addAll(modifications, sideEffectChanges); - } - - } catch (Exception ex) { - LOGGER.debug("Provisioning exception: {}:{}, attempting to handle it", - ex.getClass(), ex.getMessage(), ex); - finalOperationStatus = handleModifyError(ctx, repoShadow, modifications, options, opState, ex, parentResult.getLastSubresult(), task, parentResult); - } - - LOGGER.debug("MODIFY {}: resource operation executed, operation state: {}", repoShadow, opState.shortDumpLazily()); - - } else { - opState.setExecutionStatus(PendingOperationExecutionStatusType.EXECUTION_PENDING); - // Create dummy subresult with IN_PROGRESS state. - // This will force the entire result (parent) to be IN_PROGRESS rather than SUCCESS. - OperationResult delayedSubresult = parentResult.createSubresult(OP_DELAYED_OPERATION); - delayedSubresult.setStatus(OperationResultStatus.IN_PROGRESS); - LOGGER.debug("MODIFY {}: Resource operation NOT executed, execution pending", repoShadow); - } - } - - shadowManager.recordModifyResult(ctx, repoShadow, modifications, opState, now, parentResult); - - notifyAfterModify(ctx, repoShadow, modifications, opState, task, parentResult); - - setParentOperationStatus(parentResult, opState, finalOperationStatus); - - return repoShadow.getOid(); - } - - private boolean shouldExecuteModify(RefreshShadowOperation refreshShadowOperation) { - if (refreshShadowOperation == null) { - LOGGER.trace("Nothing refreshed, modify can continue."); - return true; - } - - if (refreshShadowOperation.getExecutedDeltas() == null || refreshShadowOperation.getExecutedDeltas().isEmpty()) { - LOGGER.trace("No executed deltas after refresh. Continue with modify operation."); - return true; - } - - if (refreshShadowOperation.getRefreshedShadow() == null) { - LOGGER.trace("Shadow is gone. Probably it was deleted during refresh. Finishing modify operation now."); - return false; - } - - Collection> objectDeltaOperations = refreshShadowOperation.getExecutedDeltas(); - for (ObjectDeltaOperation shadowDelta : objectDeltaOperations) { - if (!shadowDelta.getExecutionResult().isSuccess()) { - LOGGER.trace("Refresh operation not successful. Finishing modify operation now."); - return false; - } - } - - return true; - } - - private boolean shouldRefresh(PrismObject repoShadow) { - if (repoShadow == null) { - return false; - } - - List pendingOperations = repoShadow.asObjectable().getPendingOperation(); - if (pendingOperations == null || pendingOperations.isEmpty()) { - return false; - } - - for (PendingOperationType pendingOperationType : pendingOperations) { - if (needsRetry(pendingOperationType)) { - return true; - } - } - - return false; - } - - private void notifyAfterModify( - ProvisioningContext ctx, - PrismObject repoShadow, - Collection modifications, - ProvisioningOperationState>>> opState, - Task task, - OperationResult parentResult) - throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException { - - ObjectDelta delta = prismContext.deltaFactory().object().createModifyDelta(repoShadow.getOid(), modifications, - repoShadow.getCompileTimeClass()); - ResourceOperationDescription operationDescription = createSuccessOperationDescription(ctx, repoShadow, - delta, parentResult); - - if (opState.isExecuting()) { - operationListener.notifyInProgress(operationDescription, task, parentResult); - } else { - operationListener.notifySuccess(operationDescription, task, parentResult); - } - } - - /** - * Used to execute delayed operations. - * Mostly copy&paste from modifyShadow(). But as consistency (handleError()) branch expects to return immediately - * I could not find a more elegant way to structure this without complicating the code too much. - */ - private ProvisioningOperationState>>> executeResourceModify( - ProvisioningContext ctx, - PrismObject repoShadow, - Collection modifications, - OperationProvisioningScriptsType scripts, - ProvisioningOperationOptions options, - XMLGregorianCalendar now, - Task task, - OperationResult parentResult) - throws SchemaException, GenericFrameworkException, CommunicationException, ObjectNotFoundException, - ConfigurationException, SecurityViolationException, PolicyViolationException, ExpressionEvaluationException { - ProvisioningOperationState>>> opState = new ProvisioningOperationState<>(); - opState.setRepoShadow(repoShadow); - - ConnectorOperationOptions connOptions = createConnectorOperationOptions(ctx, options, parentResult); - - try { - - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Applying change: {}", DebugUtil.debugDump(modifications)); - } - - AsynchronousOperationReturnValue>> asyncReturnValue = - resourceObjectConverter - .modifyResourceObject(ctx, repoShadow, scripts, connOptions, modifications, now, parentResult); - opState.processAsyncResult(asyncReturnValue); - - Collection> sideEffectChanges = asyncReturnValue.getReturnValue(); - if (sideEffectChanges != null) { - ItemDeltaCollectionsUtil.addAll(modifications, sideEffectChanges); - } - - } catch (Exception ex) { - LOGGER.debug("Provisioning exception: {}:{}, attempting to handle it", - ex.getClass(), ex.getMessage(), ex); - try { - handleModifyError(ctx, repoShadow, modifications, options, opState, ex, parentResult.getLastSubresult(), task, parentResult); - parentResult.computeStatus(); - } catch (ObjectAlreadyExistsException e) { - parentResult.recordFatalError( - "While compensating communication problem for modify operation got: " - + ex.getMessage(), - ex); - throw new SystemException(e); - } - - } - - return opState; - } - - public PrismObject deleteShadow(PrismObject repoShadow, ProvisioningOperationOptions options, - OperationProvisioningScriptsType scripts, Task task, OperationResult parentResult) - throws CommunicationException, GenericFrameworkException, ObjectNotFoundException, - SchemaException, ConfigurationException, SecurityViolationException, PolicyViolationException, ExpressionEvaluationException { - - Validate.notNull(repoShadow, "Object to delete must not be null."); - Validate.notNull(parentResult, "Operation result must not be null."); - - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Start deleting {}{}", repoShadow, getAdditionalOperationDesc(scripts, options)); - } - - InternalMonitor.recordCount(InternalCounters.SHADOW_CHANGE_OPERATION_COUNT); - - ProvisioningContext ctx = ctxFactory.create(repoShadow, task, parentResult); - try { - ctx.assertDefinition(); - } catch (ObjectNotFoundException ex) { - // if the force option is set, delete shadow from the repo - // although the resource does not exists.. - if (ProvisioningOperationOptions.isForce(options)) { - parentResult.muteLastSubresultError(); - shadowManager.deleteShadow(ctx, repoShadow, parentResult); - parentResult.recordHandledError( - "Resource defined in shadow does not exists. Shadow was deleted from the repository."); - return null; - } else { - throw ex; - } - } - - repoShadow = cancelAllPendingOperations(ctx, repoShadow, task, parentResult); - - ProvisioningOperationState opState = new ProvisioningOperationState<>(); - opState.setRepoShadow(repoShadow); - - return deleteShadowAttempt(ctx, options, scripts, opState, task, parentResult); - } - - - private PrismObject deleteShadowAttempt(ProvisioningContext ctx, - ProvisioningOperationOptions options, - OperationProvisioningScriptsType scripts, - ProvisioningOperationState opState, - Task task, - OperationResult parentResult) - throws CommunicationException, GenericFrameworkException, ObjectNotFoundException, - SchemaException, ConfigurationException, SecurityViolationException, PolicyViolationException, ExpressionEvaluationException { - - PrismObject repoShadow = opState.getRepoShadow(); - shadowCaretaker.applyAttributesDefinition(ctx, repoShadow); - - PendingOperationType duplicateOperation = shadowManager.checkAndRecordPendingDeleteOperationBeforeExecution(ctx, repoShadow, opState, task, parentResult); - if (duplicateOperation != null) { - parentResult.recordInProgress(); - return repoShadow; - } - - XMLGregorianCalendar now = clock.currentTimeXMLGregorianCalendar(); - ShadowState shadowState = shadowCaretaker.determineShadowState(ctx, repoShadow, now); - - LOGGER.trace("Deleting object {} from {}, options={}, shadowState={}", repoShadow, ctx.getResource(), options, shadowState); - OperationResultStatus finalOperationStatus = null; - - if (shouldExecuteResourceOperationDirectly(ctx)) { - - if (shadowState == ShadowState.TOMBSTONE) { - - // Do not even try to delete resource object for tombstone shadows. - // There may be dead shadow and live shadow for the resource object with the same identifiers. - // If we try to delete dead shadow then we might delete existing object by mistake - LOGGER.trace("DELETE {}: skipping resource deletion on tombstone shadow", repoShadow); - - opState.setExecutionStatus(PendingOperationExecutionStatusType.COMPLETED); - OperationResult delayedSubresult = parentResult.createSubresult(OP_RESOURCE_OPERATION); - delayedSubresult.setStatus(OperationResultStatus.NOT_APPLICABLE); - - } else { - - ConnectorOperationOptions connOptions = createConnectorOperationOptions(ctx, options, parentResult); - - LOGGER.trace("DELETE {}: resource deletion, execution starting", repoShadow); - - try { - - AsynchronousOperationResult asyncReturnValue = resourceObjectConverter - .deleteResourceObject(ctx, repoShadow, scripts, connOptions, parentResult); - opState.processAsyncResult(asyncReturnValue); - - String operationCtx = "deleting " + repoShadow + " finished successfully."; - resourceManager.modifyResourceAvailabilityStatus(ctx.getResourceOid(), AvailabilityStatusType.UP, operationCtx, task, parentResult, false); - - } catch (Exception ex) { - try { - finalOperationStatus = handleDeleteError(ctx, repoShadow, options, opState, ex, parentResult.getLastSubresult(), task, parentResult); - } catch (ObjectAlreadyExistsException e) { - parentResult.recordFatalError(e); - throw new SystemException(e.getMessage(), e); - } - } - - LOGGER.debug("DELETE {}: resource operation executed, operation state: {}", repoShadow, opState.shortDumpLazily()); - } - - } else { - opState.setExecutionStatus(PendingOperationExecutionStatusType.EXECUTION_PENDING); - // Create dummy subresult with IN_PROGRESS state. - // This will force the entire result (parent) to be IN_PROGRESS rather than SUCCESS. - OperationResult delayedSubresult = parentResult.createSubresult(OP_DELAYED_OPERATION); - delayedSubresult.setStatus(OperationResultStatus.IN_PROGRESS); - LOGGER.debug("DELETE {}: resource operation NOT executed, execution pending", repoShadow); - } - - now = clock.currentTimeXMLGregorianCalendar(); - - PrismObject resultShadow; - try { - resultShadow = shadowManager.recordDeleteResult(ctx, repoShadow, opState, options, now, parentResult); - } catch (ObjectNotFoundException ex) { - parentResult.recordFatalError("Can't delete object " + repoShadow + ". Reason: " + ex.getMessage(), - ex); - throw new ObjectNotFoundException("An error occured while deleting resource object " + repoShadow - + "whith identifiers " + repoShadow + ": " + ex.getMessage(), ex); - } catch (EncryptionException e) { - throw new SystemException(e.getMessage(), e); - } - - notifyAfterDelete(ctx, repoShadow, opState, task, parentResult); - - setParentOperationStatus(parentResult, opState, finalOperationStatus); - - LOGGER.trace("Delete operation for {} finished, result shadow: {}", repoShadow, resultShadow); - return resultShadow; - } - - private ProvisioningOperationState executeResourceDelete( - ProvisioningContext ctx, - PrismObject shadow, - OperationProvisioningScriptsType scripts, - ProvisioningOperationOptions options, - Task task, - OperationResult parentResult) throws SchemaException, GenericFrameworkException, CommunicationException, ObjectNotFoundException, ConfigurationException, SecurityViolationException, PolicyViolationException, ExpressionEvaluationException { - ProvisioningOperationState opState = new ProvisioningOperationState<>(); - opState.setRepoShadow(shadow); - ConnectorOperationOptions connOptions = createConnectorOperationOptions(ctx, options, parentResult); - try { - - AsynchronousOperationResult asyncReturnValue = resourceObjectConverter - .deleteResourceObject(ctx, shadow, scripts, connOptions , parentResult); - opState.processAsyncResult(asyncReturnValue); - - } catch (Exception ex) { - try { - handleDeleteError(ctx, shadow, options, opState, ex, parentResult.getLastSubresult(), task, parentResult); - } catch (ObjectAlreadyExistsException e) { - parentResult.recordFatalError(e); - throw new SystemException(e.getMessage(), e); - } - } - - return opState; - } - - private void notifyAfterDelete( - ProvisioningContext ctx, - PrismObject shadow, - ProvisioningOperationState opState, - Task task, - OperationResult parentResult) - throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException { - ObjectDelta delta = prismContext.deltaFactory().object().createDeleteDelta(shadow.getCompileTimeClass(), - shadow.getOid()); - ResourceOperationDescription operationDescription = createSuccessOperationDescription(ctx, shadow, - delta, parentResult); - - if (opState.isExecuting()) { - operationListener.notifyInProgress(operationDescription, task, parentResult); - } else { - operationListener.notifySuccess(operationDescription, task, parentResult); - } - } - - - @Nullable - public RefreshShadowOperation refreshShadow(PrismObject repoShadow, ProvisioningOperationOptions options, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException, EncryptionException { - LOGGER.trace("Refreshing {}", repoShadow); - ProvisioningContext ctx = ctxFactory.create(repoShadow, task, parentResult); - ctx.assertDefinition(); - shadowCaretaker.applyAttributesDefinition(ctx, repoShadow); - - repoShadow = shadowManager.refreshProvisioningIndexes(ctx, repoShadow, task, parentResult); - - RefreshShadowOperation refreshShadowOperation = refreshShadowPendingOperations(ctx, repoShadow, options, task, parentResult); - - XMLGregorianCalendar now = clock.currentTimeXMLGregorianCalendar(); - repoShadow = cleanUpDeadShadow(ctx, repoShadow, now, task, parentResult); - if (repoShadow == null) { - refreshShadowOperation.setRefreshedShadow(null); - } - - return refreshShadowOperation; - } - - - - private RefreshShadowOperation refreshShadowPendingOperations(ProvisioningContext ctx, PrismObject repoShadow, ProvisioningOperationOptions options, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException, EncryptionException { - ShadowType shadowType = repoShadow.asObjectable(); - List pendingOperations = shadowType.getPendingOperation(); - boolean isDead = ShadowUtil.isDead(shadowType); - if (!isDead && pendingOperations.isEmpty()) { - LOGGER.trace("Skipping refresh of {} pending operations because shadow is not dead and there are no pending operations", repoShadow); - RefreshShadowOperation rso = new RefreshShadowOperation(); - rso.setRefreshedShadow(repoShadow); - return rso; - } - - LOGGER.trace("Pending operations refresh of {}, dead={}, {} pending operations", repoShadow, isDead, pendingOperations.size()); - - ctx.assertDefinition(); - List sortedOperations = shadowCaretaker.sortPendingOperations(shadowType.getPendingOperation()); - - repoShadow = refreshShadowAsyncStatus(ctx, repoShadow, sortedOperations, task, parentResult); - - RefreshShadowOperation refreshShadowOperation = refreshShadowRetryOperations(ctx, repoShadow, sortedOperations, options, task, parentResult); - - return refreshShadowOperation; - } - - /** - * Used to quickly and efficiently refresh shadow before GET operations. - */ - private PrismObject refreshShadowQuick(ProvisioningContext ctx, - PrismObject repoShadow, - XMLGregorianCalendar now, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException, EncryptionException { - - ObjectDelta shadowDelta = repoShadow.createModifyDelta(); - expirePendingOperations(ctx, repoShadow, shadowDelta, now, parentResult); - - if (!shadowDelta.isEmpty()) { - shadowManager.modifyShadowAttributes(ctx, repoShadow, shadowDelta.getModifications(), parentResult); - shadowDelta.applyTo(repoShadow); - } - - repoShadow = cleanUpDeadShadow(ctx, repoShadow, now, task, parentResult); - - return repoShadow; - } - - /** - * Refresh status of asynchronous operation, e.g. status of manual connector ticket. - * This method will get new status from resouceObjectConverter and it will process the - * status in case that it has changed. - */ - private PrismObject refreshShadowAsyncStatus(ProvisioningContext ctx, PrismObject repoShadow, List sortedOperations, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException, EncryptionException { - Duration gracePeriod = ProvisioningUtil.getGracePeriod(ctx); - - List> notificationDeltas = new ArrayList<>(); - - boolean shadowInception = false; - ObjectDelta shadowDelta = repoShadow.createModifyDelta(); - for (PendingOperationType pendingOperation: sortedOperations) { - - if (!needsRefresh(pendingOperation)) { - continue; - } - - ItemPath containerPath = pendingOperation.asPrismContainerValue().getPath(); - - String asyncRef = pendingOperation.getAsynchronousOperationReference(); - if (asyncRef == null) { - continue; - } - - AsynchronousOperationResult refreshAsyncResult; - try { - refreshAsyncResult = resourceObjectConverter.refreshOperationStatus(ctx, repoShadow, asyncRef, parentResult); - } catch (CommunicationException e) { - LOGGER.debug("Communication error while trying to refresh pending operation of {}. Skipping refresh of this operation.", repoShadow, e); - parentResult.recordPartialError(e); - continue; - } - OperationResultStatus newStatus = refreshAsyncResult.getOperationResult().getStatus(); - - if (newStatus == null) { - continue; - } - OperationResultStatusType newStatusType = newStatus.createStatusType(); - if (newStatusType.equals(pendingOperation.getResultStatus())) { - continue; - } - - - boolean operationCompleted = ProvisioningUtil.isCompleted(newStatusType) && pendingOperation.getCompletionTimestamp() == null; - - if (operationCompleted && gracePeriod == null) { - LOGGER.trace("Deleting pending operation because it is completed (no grace): {}", pendingOperation); - shadowDelta.addModificationDeleteContainer(ShadowType.F_PENDING_OPERATION, pendingOperation.clone()); - continue; - - } else { - PropertyDelta resultStatusDelta = shadowDelta.createPropertyModification(containerPath.append(PendingOperationType.F_RESULT_STATUS)); - resultStatusDelta.setRealValuesToReplace(newStatusType); - shadowDelta.addModification(resultStatusDelta); - } - - if (operationCompleted) { - // Operation completed - - PropertyDelta executionStatusDelta = shadowDelta.createPropertyModification(containerPath.append(PendingOperationType.F_EXECUTION_STATUS)); - executionStatusDelta.setRealValuesToReplace(PendingOperationExecutionStatusType.COMPLETED); - shadowDelta.addModification(executionStatusDelta); - - PropertyDelta completionTimestampDelta = shadowDelta.createPropertyModification(containerPath.append(PendingOperationType.F_COMPLETION_TIMESTAMP)); - completionTimestampDelta.setRealValuesToReplace(clock.currentTimeXMLGregorianCalendar()); - shadowDelta.addModification(completionTimestampDelta); - - ObjectDeltaType pendingDeltaType = pendingOperation.getDelta(); - ObjectDelta pendingDelta = DeltaConvertor.createObjectDelta(pendingDeltaType, prismContext); - - if (pendingDelta.isAdd()) { - shadowInception = true; - } - - if (pendingDelta.isModify()) { - - // Apply shadow naming attribute modification - PrismContainer shadowAttributesContainer = repoShadow.findContainer(ItemPath.create(ShadowType.F_ATTRIBUTES)); - ResourceAttributeContainer resourceAttributeContainer = ResourceAttributeContainer.convertFromContainer(shadowAttributesContainer, ctx.getObjectClassDefinition()); - ResourceAttributeContainerDefinition resourceAttrDefinition = resourceAttributeContainer.getDefinition(); - if(resourceAttrDefinition != null) { - - // If naming attribute is present in delta... - ResourceAttributeDefinition namingAttribute = resourceAttrDefinition.getNamingAttribute(); - if (namingAttribute != null) { - if (pendingDelta.hasItemDelta(ItemPath.create(ShadowType.F_ATTRIBUTES, namingAttribute.getItemName()))) { - - // Retrieve a possible changed name per the defined naming attribute for the resource - ItemDelta namingAttributeDelta = pendingDelta.findItemDelta(ItemPath.create(ShadowType.F_ATTRIBUTES, namingAttribute.getItemName())); - Collection valuesToReplace = namingAttributeDelta.getValuesToReplace(); - Optional valueToReplace = valuesToReplace.stream().findFirst(); - - if (valueToReplace.isPresent()){ - Object valueToReplaceObj = ((PrismPropertyValue)valueToReplace.get()).getValue(); - if (valueToReplaceObj instanceof String) { - - // Apply the new naming attribute value to the shadow name by adding the change to the modification set for shadow delta - PropertyDelta nameDelta = shadowDelta.createPropertyModification(ItemPath.create(ShadowType.F_NAME)); - Collection modificationSet = new ArrayList<>(); - PolyString nameAttributeReplacement = new PolyString((String) valueToReplaceObj); - modificationSet.add(nameAttributeReplacement); - nameDelta.setValuesToReplace(PrismValueCollectionsUtil.createCollection(prismContext, modificationSet)); - shadowDelta.addModification(nameDelta); - } - } - } - } - } - - // Apply shadow attribute modifications - for (ItemDelta pendingModification: pendingDelta.getModifications()) { - shadowDelta.addModification(pendingModification.clone()); - } - } - - if (pendingDelta.isDelete()) { - shadowInception = false; - shadowManager.addDeadShadowDeltas(repoShadow, refreshAsyncResult, (List)shadowDelta.getModifications()); - } - - notificationDeltas.add(pendingDelta); - } - - } - - if (shadowInception) { - // We do not need to care about attributes in add deltas here. The add operation is already applied to - // attributes. We need this to "allocate" the identifiers, so iteration mechanism in the - // model can find unique values while taking pending create operations into consideration. - PropertyDelta existsDelta = shadowDelta.createPropertyModification(ShadowType.F_EXISTS); - existsDelta.setRealValuesToReplace(true); - shadowDelta.addModification(existsDelta); - } - - XMLGregorianCalendar now = clock.currentTimeXMLGregorianCalendar(); - expirePendingOperations(ctx, repoShadow, shadowDelta, now, parentResult); - - if (!shadowDelta.isEmpty()) { - shadowCaretaker.applyAttributesDefinition(ctx, shadowDelta); - shadowManager.modifyShadowAttributes(ctx, repoShadow, shadowDelta.getModifications(), parentResult); - } - - for (ObjectDelta notificationDelta: notificationDeltas) { - ResourceOperationDescription operationDescription = createSuccessOperationDescription(ctx, repoShadow, - notificationDelta, parentResult); - operationListener.notifySuccess(operationDescription, task, parentResult); - } - - if (shadowDelta.isEmpty()) { - return repoShadow; - } - shadowDelta.applyTo(repoShadow); - return repoShadow; - } - - private boolean needsRefresh(PendingOperationType pendingOperation) { - PendingOperationExecutionStatusType executionStatus = pendingOperation.getExecutionStatus(); - if (executionStatus == null) { - // LEGACY: 3.7 and earlier - return OperationResultStatusType.IN_PROGRESS.equals(pendingOperation.getResultStatus()); - } else { - return PendingOperationExecutionStatusType.EXECUTING.equals(executionStatus); - } - } - - - private RefreshShadowOperation refreshShadowRetryOperations(ProvisioningContext ctx, - PrismObject repoShadow, List sortedOperations, - ProvisioningOperationOptions options, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException, EncryptionException { - ShadowType shadowType = repoShadow.asObjectable(); - OperationResult retryResult = new OperationResult(OP_REFRESH_RETRY); - if (ShadowUtil.isDead(shadowType)) { - RefreshShadowOperation rso = new RefreshShadowOperation(); - retryResult.recordSuccess(); - rso.setRefreshedShadow(repoShadow); - rso.setRefreshResult(retryResult); - return rso; - } - - Duration retryPeriod = ProvisioningUtil.getRetryPeriod(ctx); - - List> notificationDeltas = new ArrayList<>(); - - Collection> executedDeltas = new ArrayList<>(); - for (PendingOperationType pendingOperation: sortedOperations) { - - if (!needsRetry(pendingOperation)) { - continue; - } - // We really want to get "now" here. Retrying operation may take some time. We want good timestamps that do not lie. - XMLGregorianCalendar now = clock.currentTimeXMLGregorianCalendar(); - if (!isAfterRetryPeriod(ctx, pendingOperation, retryPeriod, now)) { - if (PendingOperationTypeType.RETRY != pendingOperation.getType()) { - continue; - } - if (!ProvisioningOperationOptions.isForceRetry(options)) { - continue; - } - } - - LOGGER.trace("Going to retry operation {} on {}", pendingOperation, repoShadow); - - // Record attempt number and timestamp before the operation - // TODO: later use this as an optimistic lock to make sure that two threads won't retry the operation at the same time - - // TODO: move to a better place - ObjectDelta shadowDelta = repoShadow.createModifyDelta(); - ItemPath containerPath = pendingOperation.asPrismContainerValue().getPath(); - - int attemptNumber = pendingOperation.getAttemptNumber() + 1; - PropertyDelta attemptNumberDelta = shadowDelta.createPropertyModification(containerPath.append(PendingOperationType.F_ATTEMPT_NUMBER)); - attemptNumberDelta.setRealValuesToReplace(attemptNumber); - shadowDelta.addModification(attemptNumberDelta); - - PropertyDelta lastAttemptTimestampDelta = shadowDelta.createPropertyModification(containerPath.append(PendingOperationType.F_LAST_ATTEMPT_TIMESTAMP)); - lastAttemptTimestampDelta.setRealValuesToReplace(now); - shadowDelta.addModification(lastAttemptTimestampDelta); - - PropertyDelta resultStatusDelta = shadowDelta.createPropertyModification(containerPath.append(PendingOperationType.F_RESULT_STATUS)); - resultStatusDelta.setRealValuesToReplace(OperationResultStatusType.IN_PROGRESS); - shadowDelta.addModification(resultStatusDelta); - - shadowManager.modifyShadowAttributes(ctx, repoShadow, shadowDelta.getModifications(), parentResult); - shadowDelta.applyTo(repoShadow); - - ObjectDeltaType pendingDeltaType = pendingOperation.getDelta(); - ObjectDelta pendingDelta = DeltaConvertor.createObjectDelta(pendingDeltaType, prismContext); - - ProvisioningOperationState opState = - ProvisioningOperationState.fromPendingOperation(repoShadow, pendingOperation); - - LOGGER.debug("Retrying operation {} on {}, attempt #{}", pendingDelta, repoShadow, attemptNumber); - - OperationResult result = parentResult.createSubresult(OP_OPERATION_RETRY); - ObjectDeltaOperation objectDeltaOperation = new ObjectDeltaOperation<>(pendingDelta); - try { - retryOperation(ctx, pendingDelta, opState, task, result); - repoShadow = opState.getRepoShadow(); - result.computeStatus(); - if (result.isError()) { - retryResult.setStatus(result.getStatus()); - } - //TODO maybe add whole "result" as subresult to the retryResult? - result.muteError(); - } catch (CommunicationException | GenericFrameworkException | ObjectAlreadyExistsException | SchemaException | ObjectNotFoundException | ConfigurationException | SecurityViolationException e) { - // This is final failure: the error is not handled. - // Therefore the operation is now completed - finished with an error. - // But we do not want to stop the task. Just log the error. - LOGGER.error("Operation {} on {} ended up with an error after {} retries: {}", - pendingDelta, repoShadow, attemptNumber, e.getMessage(), e); - // The retry itself was a success. Operation that was retried might have failed. - // And that is recorded in the shadow. But we have successfully retried the operation. - result.recordHandledError(e); - retryResult.recordFatalError("Operation " + pendingDelta + " on " + repoShadow + " ended with an error after " + attemptNumber + " retries: " + e.getMessage()); - } catch (Throwable e) { - // This is unexpected error during retry. This means that there was other - // failure that we did not expected. This is likely to be bug - or maybe wrong - // error handling. This means that the retry was a failure. - result.recordFatalError(e); - retryResult.recordFatalError(e); - } - - objectDeltaOperation.setExecutionResult(result); - executedDeltas.add(objectDeltaOperation); - } - - RefreshShadowOperation rso = new RefreshShadowOperation(); - rso.setExecutedDeltas(executedDeltas); - rso.setRefreshedShadow(repoShadow); - parentResult.computeStatus(); - - rso.setRefreshResult(retryResult); - - LOGGER.trace("refreshshadowOperaton {}", rso.debugDump()); - return rso; - } - - private void retryOperation(ProvisioningContext ctx, - ObjectDelta pendingDelta, - ProvisioningOperationState opState, - Task task, - OperationResult result) - throws CommunicationException, GenericFrameworkException, ObjectAlreadyExistsException, SchemaException, ObjectNotFoundException, ConfigurationException, SecurityViolationException, PolicyViolationException, ExpressionEvaluationException, EncryptionException { - - ProvisioningOperationOptions options = ProvisioningOperationOptions.createForceRetry(false); - OperationProvisioningScriptsType scripts = null; // TODO - if (pendingDelta.isAdd()) { - PrismObject shadowToAdd = pendingDelta.getObjectToAdd(); - addShadowAttempt(ctx, shadowToAdd, scripts, - (ProvisioningOperationState>>) opState, - options, task, result); - opState.setRepoShadow(shadowToAdd); - } - - if (pendingDelta.isModify()) { - modifyShadowAttempt(ctx, pendingDelta.getModifications(), scripts, options, - (ProvisioningOperationState>>>) opState, - task, result); - } - - if (pendingDelta.isDelete()) { - deleteShadowAttempt(ctx, options, scripts, - (ProvisioningOperationState) opState, - task, result); - } - } - - private boolean needsRetry(PendingOperationType pendingOperation) { - return PendingOperationExecutionStatusType.EXECUTING.equals(pendingOperation.getExecutionStatus()) && - pendingOperation.getAttemptNumber() != null; - } - - private boolean isAfterRetryPeriod(ProvisioningContext ctx, PendingOperationType pendingOperation, Duration retryPeriod, XMLGregorianCalendar now) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException { - XMLGregorianCalendar lastAttemptTimestamp = pendingOperation.getLastAttemptTimestamp(); - XMLGregorianCalendar scheduledRetryTimestamp = XmlTypeConverter.addDuration(lastAttemptTimestamp, retryPeriod); - return XmlTypeConverter.compare(now, scheduledRetryTimestamp) == DatatypeConstants.GREATER; - } - - // This is very simple code that essentially works only for postponed operations (retries). - // TODO: better support for async and manual operations - private PrismObject cancelAllPendingOperations(ProvisioningContext ctx, - PrismObject repoShadow, Task task, OperationResult parentResult) throws SchemaException, ObjectNotFoundException, ConfigurationException, CommunicationException, ExpressionEvaluationException { - List pendingOperations = repoShadow.asObjectable().getPendingOperation(); - if (pendingOperations.isEmpty()) { - return repoShadow; - } - XMLGregorianCalendar now = clock.currentTimeXMLGregorianCalendar(); - ObjectDelta shadowDelta = repoShadow.createModifyDelta(); - for (PendingOperationType pendingOperation: pendingOperations) { - if (pendingOperation.getExecutionStatus() == PendingOperationExecutionStatusType.COMPLETED) { - continue; - } - if (pendingOperation.getType() != PendingOperationTypeType.RETRY) { - // Other operations are not cancellable now - continue; - } - ItemPath containerPath = pendingOperation.asPrismContainerValue().getPath(); - PropertyDelta executionStatusDelta = shadowDelta.createPropertyModification(containerPath.append(PendingOperationType.F_EXECUTION_STATUS)); - executionStatusDelta.setRealValuesToReplace(PendingOperationExecutionStatusType.COMPLETED); - shadowDelta.addModification(executionStatusDelta); - PropertyDelta completionTimestampDelta = shadowDelta.createPropertyModification(containerPath.append(PendingOperationType.F_COMPLETION_TIMESTAMP)); - completionTimestampDelta.setRealValuesToReplace(now); - shadowDelta.addModification(completionTimestampDelta); - PropertyDelta resultStatusDelta = shadowDelta.createPropertyModification(containerPath.append(PendingOperationType.F_RESULT_STATUS)); - resultStatusDelta.setRealValuesToReplace(OperationResultStatusType.NOT_APPLICABLE); - shadowDelta.addModification(resultStatusDelta); - } - if (shadowDelta.isEmpty()) { - return repoShadow; - } - LOGGER.debug("Cancelling pending operations on {}", repoShadow); - shadowManager.modifyShadowAttributes(ctx, repoShadow, shadowDelta.getModifications(), parentResult); - shadowDelta.applyTo(repoShadow); - return repoShadow; - } - - private PrismObject cleanUpDeadShadow(ProvisioningContext ctx, - PrismObject repoShadow, - XMLGregorianCalendar now, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException, EncryptionException { - ShadowType shadowType = repoShadow.asObjectable(); - if (!ShadowUtil.isDead(shadowType)) { - return repoShadow; - } - Duration gracePeriod = ProvisioningUtil.getGracePeriod(ctx); - Duration deadRetentionPeriod = ProvisioningUtil.getDeadShadowRetentionPeriod(ctx); - Duration expirationPeriod = XmlTypeConverter.longerDuration(gracePeriod, deadRetentionPeriod); - XMLGregorianCalendar lastActivityTimestamp = null; - - for (PendingOperationType pendingOperation: shadowType.getPendingOperation()) { - lastActivityTimestamp = XmlTypeConverter.laterTimestamp(lastActivityTimestamp, pendingOperation.getRequestTimestamp()); - lastActivityTimestamp = XmlTypeConverter.laterTimestamp(lastActivityTimestamp, pendingOperation.getLastAttemptTimestamp()); - lastActivityTimestamp = XmlTypeConverter.laterTimestamp(lastActivityTimestamp, pendingOperation.getCompletionTimestamp()); - } - if (lastActivityTimestamp == null) { - MetadataType metadata = shadowType.getMetadata(); - if (metadata != null) { - lastActivityTimestamp = metadata.getModifyTimestamp(); - if (lastActivityTimestamp == null) { - lastActivityTimestamp = metadata.getCreateTimestamp(); - } - } - } - - if (ProvisioningUtil.isOverPeriod(now, expirationPeriod, lastActivityTimestamp)) { - // Perish you stinking corpse! - LOGGER.debug("Deleting dead {} because it is expired", repoShadow); - shadowManager.deleteShadow(ctx, repoShadow, parentResult); - ResourceObjectShadowChangeDescription change = new ResourceObjectShadowChangeDescription(); - change.setCleanDeadShadow(true); - change.setOldShadow(repoShadow); - change.setResource(ctx.getResource().asPrismObject()); - change.setObjectDelta(repoShadow.createDeleteDelta()); - change.setSourceChannel(SchemaConstants.CHANGE_CHANNEL_DISCOVERY_URI); - changeNotificationDispatcher.notifyChange(change, task, parentResult); - applyDefinition(repoShadow, parentResult); - ResourceOperationDescription operationDescription = createSuccessOperationDescription(ctx, repoShadow, - repoShadow.createDeleteDelta(), parentResult); - operationListener.notifySuccess(operationDescription, task, parentResult); - return null; - } else { - LOGGER.trace("Keeping dead {} because it is not expired yet, last activity={}, expiration period={}", repoShadow, lastActivityTimestamp, expirationPeriod); - return repoShadow; - } - } - - private void expirePendingOperations(ProvisioningContext ctx, PrismObject repoShadow, ObjectDelta shadowDelta, XMLGregorianCalendar now, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException { - ShadowType shadowType = repoShadow.asObjectable(); - - Duration gracePeriod = ProvisioningUtil.getGracePeriod(ctx); - Duration pendingOperationRetentionPeriod = ProvisioningUtil.getPendingOperationRetentionPeriod(ctx); - Duration expirePeriod = XmlTypeConverter.longerDuration(gracePeriod, pendingOperationRetentionPeriod); - for (PendingOperationType pendingOperation: shadowType.getPendingOperation()) { - if (ProvisioningUtil.isOverPeriod(now, expirePeriod, pendingOperation)) { - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Deleting pending operation because it is completed '{}' and expired: {}", pendingOperation.getResultStatus().value(), pendingOperation); - } - shadowDelta.addModificationDeleteContainer(ShadowType.F_PENDING_OPERATION, pendingOperation.clone()); - } - } - } - - public void applyDefinition(ObjectDelta delta, ShadowType repoShadow, - OperationResult parentResult) throws SchemaException, ObjectNotFoundException, - CommunicationException, ConfigurationException, ExpressionEvaluationException { - PrismObject shadow = null; - ResourceShadowDiscriminator discriminator = null; - if (delta.isAdd()) { - shadow = delta.getObjectToAdd(); - } else if (delta.isModify()) { - if (delta instanceof ShadowDiscriminatorObjectDelta) { - // This one does not have OID, it has to be specially processed - discriminator = ((ShadowDiscriminatorObjectDelta) delta).getDiscriminator(); - } else { - String shadowOid = delta.getOid(); - if (shadowOid == null) { - if (repoShadow == null) { - throw new IllegalArgumentException("No OID in object delta " + delta - + " and no externally-supplied shadow is present as well."); - } - shadow = repoShadow.asPrismObject(); - } else { - shadow = repositoryService.getObject(delta.getObjectTypeClass(), shadowOid, null, - parentResult); // TODO consider fetching only when - // really necessary - } - } - } else { - // Delete delta, nothing to do at all - return; - } - ProvisioningContext ctx; - if (shadow == null) { - ctx = ctxFactory.create(discriminator, null, parentResult); - ctx.assertDefinition(); - } else { - ctx = ctxFactory.create(shadow, null, parentResult); - ctx.assertDefinition(); - } - shadowCaretaker.applyAttributesDefinition(ctx, delta); - } - - public void applyDefinition(PrismObject shadow, OperationResult parentResult) - throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, ExpressionEvaluationException { - ProvisioningContext ctx = ctxFactory.create(shadow, null, parentResult); - ctx.assertDefinition(); - shadowCaretaker.applyAttributesDefinition(ctx, shadow); - } - - public void setProtectedShadow(PrismObject shadow, OperationResult parentResult) - throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException { - ProvisioningContext ctx = ctxFactory.create(shadow, null, parentResult); - ctx.assertDefinition(); - ProvisioningUtil.setProtectedFlag(ctx, shadow, matchingRuleRegistry, relationRegistry); - } - - public void applyDefinition(final ObjectQuery query, OperationResult result) - throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, ExpressionEvaluationException { - ResourceShadowDiscriminator coordinates = ObjectQueryUtil.getCoordinates(query.getFilter(), prismContext); - ProvisioningContext ctx = ctxFactory.create(coordinates, null, result); - ctx.assertDefinition(); - applyDefinition(ctx, query); - } - - private void applyDefinition(final ProvisioningContext ctx, final ObjectQuery query) - throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, ExpressionEvaluationException { - if (query == null) { - return; - } - ObjectFilter filter = query.getFilter(); - if (filter == null) { - return; - } - final RefinedObjectClassDefinition objectClassDefinition = ctx.getObjectClassDefinition(); - com.evolveum.midpoint.prism.query.Visitor visitor = subfilter -> { - if (subfilter instanceof PropertyValueFilter) { - PropertyValueFilter valueFilter = (PropertyValueFilter) subfilter; - ItemDefinition definition = valueFilter.getDefinition(); - if (definition instanceof ResourceAttributeDefinition) { - return; // already has a resource-related definition - } - if (!ShadowType.F_ATTRIBUTES.equivalent(valueFilter.getParentPath())) { - return; - } - QName attributeName = valueFilter.getElementName(); - ResourceAttributeDefinition attributeDefinition = objectClassDefinition.findAttributeDefinition(attributeName); - if (attributeDefinition == null) { - throw new TunnelException(new SchemaException("No definition for attribute " - + attributeName + " in query " + query)); - } - valueFilter.setDefinition(attributeDefinition); - } - }; - try { - filter.accept(visitor); - } catch (TunnelException te) { - throw (SchemaException) te.getCause(); - } - } - - protected ResourceType getResource(ResourceShadowDiscriminator coords, Task task, OperationResult parentResult) - throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException { - String resourceOid = coords.getResourceOid(); - if (resourceOid == null) { - throw new IllegalArgumentException("No resource OID in " + coords); - } - return resourceManager.getResource(resourceOid, null, task, parentResult).asObjectable(); - } - - //we need to remove resolved identifiers form the ShadowAssociationType before we save it to the shadow as an unfinished operation. - void normalizeAssociationDeltasBeforeSave(Collection> associationContainers) { - if (associationContainers == null) { - return; - } - for (PrismContainerValue associationContainer : associationContainers) { - if (associationContainer.contains(ShadowAssociationType.F_IDENTIFIERS) && associationContainer.contains(ShadowAssociationType.F_SHADOW_REF)) { - associationContainer.removeContainer(ShadowAssociationType.F_IDENTIFIERS); - } - } - } - - //////////////////////////////////////////////////////////////////////////// - // SEARCH - //////////////////////////////////////////////////////////////////////////// - -// public SearchResultList> searchObjects(ObjectQuery query, -// Collection> options, -// final boolean readFromRepository, Task task, final OperationResult parentResult) -// throws SchemaException, ObjectNotFoundException, CommunicationException, -// ConfigurationException, SecurityViolationException, ExpressionEvaluationException { -// -// SearchResultList> list = new SearchResultList<>(); -// SearchResultMetadata metadata = searchObjectsIterative(query, options, (shadow,result) -> list.add(shadow), readFromRepository, task, parentResult); -// list.setMetadata(metadata); -// return list; -// -// } - - public SearchResultMetadata searchObjectsIterative(ObjectQuery query, - Collection> options, final ResultHandler handler, - final boolean readFromRepository, Task task, final OperationResult parentResult) - throws SchemaException, ObjectNotFoundException, CommunicationException, - ConfigurationException, SecurityViolationException, ExpressionEvaluationException { - - ProvisioningContext ctx = createContextForSearch(query, options, task, parentResult); - - return searchObjectsIterative(ctx, query, options, handler, readFromRepository, parentResult); - } - - private ProvisioningContext createContextForSearch(ObjectQuery query, - Collection> options, Task task, OperationResult parentResult) - throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, - ExpressionEvaluationException { - ResourceShadowDiscriminator coordinates = ObjectQueryUtil.getCoordinates(query != null ? query.getFilter() : null, - prismContext); - final ProvisioningContext ctx = ctxFactory.create(coordinates, task, parentResult); - ctx.setGetOperationOptions(options); - ctx.assertDefinition(); - return ctx; - } - - @NotNull - public SearchResultList> searchObjects(ObjectQuery query, - Collection> options, Task task, final OperationResult parentResult) - throws SchemaException, ObjectNotFoundException, CommunicationException, - ConfigurationException, SecurityViolationException, ExpressionEvaluationException { - - ProvisioningContext ctx = createContextForSearch(query, options, task, parentResult); - return searchObjects(ctx, query, options, parentResult); - } - - public SearchResultMetadata searchObjectsIterative(final ProvisioningContext ctx, ObjectQuery query, - Collection> options, final ResultHandler handler, - final boolean readFromRepository, final OperationResult parentResult) - throws SchemaException, ObjectNotFoundException, CommunicationException, - ConfigurationException, SecurityViolationException, ExpressionEvaluationException { - applyDefinition(ctx, query); - - GetOperationOptions rootOptions = SelectorOptions.findRootOptions(options); - if (ProvisioningUtil.shouldDoRepoSearch(rootOptions)) { - return searchObjectsIterativeRepository(ctx, query, options, handler, parentResult); - } - boolean isDoDiscovery = ProvisioningUtil.isDoDiscovery(ctx.getResource(), rootOptions); - - // We need to record the fetch down here. Now it is certain that we are - // going to fetch from resource - // (we do not have raw/noFetch option) - InternalMonitor.recordCount(InternalCounters.SHADOW_FETCH_OPERATION_COUNT); - - ObjectQuery attributeQuery = createAttributeQuery(query); - - ResultHandler resultHandler = (PrismObject resourceObject, OperationResult objResult) -> { - LOGGER.trace("Found resource object\n{}", resourceObject.debugDumpLazily(1)); - PrismObject resultShadow; - try { - // The shadow does not have any kind or intent at this point. - // But at least locate the definition using object classes. - ProvisioningContext estimatedShadowCtx = shadowCaretaker.reapplyDefinitions(ctx, resourceObject); - // Try to find shadow that corresponds to the resource object. - if (readFromRepository) { - PrismObject repoShadow = acquireRepositoryShadow( - estimatedShadowCtx, resourceObject, true, isDoDiscovery, objResult); - - // This determines the definitions exactly. How the repo - // shadow should have proper kind/intent - ProvisioningContext shadowCtx = shadowCaretaker.applyAttributesDefinition(ctx, repoShadow); - // TODO: shadowState - repoShadow = shadowManager.updateShadow(shadowCtx, resourceObject, null, repoShadow, null, objResult); - - resultShadow = completeShadow(shadowCtx, resourceObject, repoShadow, isDoDiscovery, objResult); - - // TODO do we want also to futurize the shadow like in getObject? - - //check and fix kind/intent - ShadowType repoShadowType = repoShadow.asObjectable(); - if (isDoDiscovery && (repoShadowType.getKind() == null || repoShadowType.getIntent() == null)) { //TODO: check also empty? - // notify resourceObjectChangeListeners to fix kind and intent for Shadow - // Do NOT invoke this if discovery is disabled. This may ruin the flow (e.g. when importing objects) - // or it may lead to discovery loops. - notifyResourceObjectChangeListeners(repoShadow, ctx.getResource().asPrismObject(), false); - } - - } else { - resultShadow = resourceObject; - } - - validateShadow(resultShadow, readFromRepository); - - } catch (SchemaException e) { - objResult.recordFatalError("Schema error: " + e.getMessage(), e); - LOGGER.error("Schema error: {}", e.getMessage(), e); - return false; - } catch (ConfigurationException e) { - objResult.recordFatalError("Configuration error: " + e.getMessage(), e); - LOGGER.error("Configuration error: {}", e.getMessage(), e); - return false; - } catch (ObjectNotFoundException | CommunicationException - | SecurityViolationException | GenericConnectorException | ExpressionEvaluationException | EncryptionException e) { - objResult.recordFatalError(e.getMessage(), e); - LOGGER.error("{}", e.getMessage(), e); - return false; - } - - boolean doContinue; - try { - - doContinue = handler.handle(resultShadow, objResult); - - objResult.computeStatus(); - objResult.recordSuccessIfUnknown(); - - } catch (RuntimeException | Error e) { - objResult.recordFatalError(e); - throw e; - } - - return doContinue; - }; - - boolean fetchAssociations = SelectorOptions.hasToLoadPath(ShadowType.F_ASSOCIATION, options); - - return resourceObjectConverter.searchResourceObjects(ctx, resultHandler, attributeQuery, - fetchAssociations, parentResult); - - } - - @NotNull - public SearchResultList> searchObjects(final ProvisioningContext ctx, ObjectQuery query, - Collection> options, final OperationResult parentResult) - throws SchemaException, ObjectNotFoundException, CommunicationException, - ConfigurationException, SecurityViolationException, ExpressionEvaluationException { - applyDefinition(ctx, query); - - GetOperationOptions rootOptions = SelectorOptions.findRootOptions(options); - if (ProvisioningUtil.shouldDoRepoSearch(rootOptions)) { - return searchObjectsRepository(ctx, query, options, parentResult); - } else { - SearchResultList> rv = new SearchResultList<>(); - SearchResultMetadata metadata = searchObjectsIterative(ctx, query, options, (s, opResult) -> rv.add(s), true, - parentResult); - rv.setMetadata(metadata); - return rv; - } - } - - /** - * Acquires repository shadow for a provided resource shadow. The repository shadow is locate or created. - * In case that the shadow is created, all additional ceremonies for a new shadow is done, e.g. invoking - * change notifications (discovery). - * - * Returned shadow is NOT guaranteed to have all the attributes aligned and updated. That is only possible after - * completeShadow(). But maybe, this method can later invoke completeShadow() and do all the necessary stuff? - * - * It may look like this method would rather belong to ShadowManager. But it does NOT. It does too much stuff - * (e.g. change notification). - */ - private PrismObject acquireRepositoryShadow(ProvisioningContext ctx, - PrismObject resourceShadow, boolean unknownIntent, boolean isDoDiscovery, OperationResult parentResult) - throws SchemaException, ConfigurationException, ObjectNotFoundException, - CommunicationException, SecurityViolationException, GenericConnectorException, ExpressionEvaluationException, EncryptionException { - - PrismObject existingRepoShadow = shadowManager.lookupLiveShadowInRepository(ctx, resourceShadow, parentResult); - - if (existingRepoShadow != null) { - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Found shadow object in the repository {}", ShadowUtil.shortDumpShadow(existingRepoShadow)); - } - return existingRepoShadow; - } - - LOGGER.trace("Shadow object (in repo) corresponding to the resource object (on the resource) was not found. " - + "The repo shadow will be created. The resource object:\n{}", resourceShadow); - - // TODO: do something about shadows with mathcing secondary identifiers? We do not need to care about these any longer, do we? - //MID-5844 - // we need it for the consistency. following is the use case. Account is beeing created on the resource - // but the resource cannot be reached by midPoint. Meanwhile the account is created manually in the resource - // when reconciliation runs, origin account created while resource was not reachable doesn't contain primary identifier - // so we rather try also secondary identifier to be sure nothing goes wrong -// PrismObject repoShadow; - -// PrismObject shadowBySecondaryIdentifier = shadowManager.lookupConflictingShadowBySecondaryIdentifiers(ctx, -// resourceShadow, parentResult); -// -// // check if the shadow contains primary identifier. if it does, we can skip the next session -// if (shadowBySecondaryIdentifier != null) { -// -// ShadowType shadowType = shadowBySecondaryIdentifier.asObjectable(); -// String currentPrimaryIdentifier = shadowManager.determinePrimaryIdentifierValue(ctx, shadowBySecondaryIdentifier); -// -// LOGGER.info("###CURRENT PI: {}", currentPrimaryIdentifier); -// String expectedPrimaryIdentifier = shadowManager.determinePrimaryIdentifierValue(ctx, resourceShadow); -// LOGGER.info("### EXPECTED PI: {}", expectedPrimaryIdentifier); -// -// if (!StringUtils.equals(currentPrimaryIdentifier, expectedPrimaryIdentifier)) { -// shadowCaretaker.applyAttributesDefinition(ctx, shadowBySecondaryIdentifier); -// shadowBySecondaryIdentifier = completeShadow(ctx, resourceShadow, shadowBySecondaryIdentifier, isDoDiscovery, parentResult); -// Task task = taskManager.createTaskInstance(); -// ResourceOperationDescription failureDescription = ProvisioningUtil.createResourceFailureDescription(shadowBySecondaryIdentifier, ctx.getResource(), null, parentResult); -// shadowBySecondaryIdentifier.asObjectable().setDead(Boolean.TRUE); -// changeNotificationDispatcher.notifyFailure(failureDescription, task, parentResult); -// shadowManager.deleteConflictedShadowFromRepo(shadowBySecondaryIdentifier, parentResult); -// } -// -// } -// - - // The resource object obviously exists on the resource, but appropriate shadow does - // not exist in the repository we need to create the shadow to align repo state to the - // reality (resource) - - PrismObject createdRepoShadow; - try { - - createdRepoShadow = shadowManager.addDiscoveredRepositoryShadow(ctx, resourceShadow, parentResult); - - } catch (ObjectAlreadyExistsException e) { - // Conflict! But we haven't supplied an OID and we have checked for existing shadow before, - // therefore there should not conflict. Unless someone managed to create the same shadow - // between our check and our create attempt. In that case try to re-check for shadow existence - // once more. - - OperationResult originalRepoAddSubresult = parentResult.getLastSubresult(); - - LOGGER.debug("Attempt to create new repo shadow for {} ended up in conflict, re-trying the search for repo shadow", resourceShadow); - PrismObject conflictingShadow = shadowManager.lookupLiveShadowInRepository(ctx, resourceShadow, parentResult); - - if (conflictingShadow == null) { - // This is really strange. The shadow should not have disappeared in the meantime, dead shadow would remain instead. - // Maybe we have broken "indexes"? (e.g. primaryIdentifierValue column) - - // Do some "research" and log the results, so we have good data to diagnose this situation. - String determinedPrimaryIdentifierValue = shadowManager.determinePrimaryIdentifierValue(ctx, resourceShadow); - PrismObject potentialConflictingShadow = shadowManager.lookupShadowByPrimaryIdentifierValue(ctx, determinedPrimaryIdentifierValue, parentResult); - - LOGGER.error("Unexpected repository behavior: object already exists error even after we double-checked shadow uniqueness: {}", e.getMessage(), e); - LOGGER.debug("REPO CONFLICT: resource shadow\n{}", resourceShadow.debugDump(1)); - LOGGER.debug("REPO CONFLICT: resource shadow: determined primaryIdentifierValue: {}", determinedPrimaryIdentifierValue); - LOGGER.debug("REPO CONFLICT: potential conflicting repo shadow (by primaryIdentifierValue)\n{}", potentialConflictingShadow==null?null:potentialConflictingShadow.debugDump(1)); - - throw new SystemException( - "Unexpected repository behavior: object already exists error even after we double-checked shadow uniqueness: " + e.getMessage(), e); - } - - originalRepoAddSubresult.muteError(); - return conflictingShadow; - } - - resourceShadow.setOid(createdRepoShadow.getOid()); - ShadowType resourceShadowBean = resourceShadow.asObjectable(); - if (resourceShadowBean.getResourceRef() == null) { - resourceShadowBean.setResourceRef(new ObjectReferenceType()); - } - resourceShadowBean.getResourceRef().asReferenceValue().setObject(ctx.getResource().asPrismObject()); - - if (isDoDiscovery) { - // We have object for which there was no shadow. Which means that midPoint haven't known about this shadow before. - // Invoke notifyChange() so the new shadow is properly initialized. - - notifyResourceObjectChangeListeners(resourceShadow, ctx.getResource().asPrismObject(), true); - } - - PrismObject finalRepoShadow; - if (unknownIntent) { - // Intent may have been changed during the notifyChange processing. - // Re-read the shadow if necessary. - finalRepoShadow = shadowManager.fixShadow(ctx, createdRepoShadow, parentResult); - } else { - finalRepoShadow = createdRepoShadow; - } - - LOGGER.trace("Final repo shadow (created and possibly re-read):\n{}", finalRepoShadow.debugDumpLazily(1)); - return finalRepoShadow; - } - - private ObjectQuery createAttributeQuery(ObjectQuery query) throws SchemaException { - QueryFactory queryFactory = prismContext.queryFactory(); - - ObjectFilter filter = null; - if (query != null) { - filter = query.getFilter(); - } - - ObjectQuery attributeQuery = null; - - if (filter instanceof AndFilter) { - List conditions = ((AndFilter) filter).getConditions(); - List attributeFilter = createAttributeQueryInternal(conditions); - if (attributeFilter.size() > 1) { - attributeQuery = queryFactory.createQuery(queryFactory.createAnd(attributeFilter)); - } else if (attributeFilter.size() < 1) { - LOGGER.trace("No attribute filter defined in the query."); - } else { - attributeQuery = queryFactory.createQuery(attributeFilter.iterator().next()); - } - } - - if (query != null && query.getPaging() != null) { - if (attributeQuery == null) { - attributeQuery = queryFactory.createQuery(); - } - attributeQuery.setPaging(query.getPaging()); - } - if (query != null && query.isAllowPartialResults()) { - if (attributeQuery == null) { - attributeQuery = queryFactory.createQuery(); - } - attributeQuery.setAllowPartialResults(true); - } - - if (InternalsConfig.consistencyChecks && attributeQuery != null - && attributeQuery.getFilter() != null) { - attributeQuery.getFilter().checkConsistence(true); - } - return attributeQuery; - } - - private List createAttributeQueryInternal(List conditions) - throws SchemaException { - List attributeFilter = new ArrayList<>(); - for (ObjectFilter f : conditions) { - if (f instanceof PropertyValueFilter) { // TODO - ItemPath parentPath = ((PropertyValueFilter) f).getParentPath(); - if (parentPath.isEmpty()) { - QName elementName = ((PropertyValueFilter) f).getElementName(); - if (QNameUtil.match(ShadowType.F_OBJECT_CLASS, elementName) || - QNameUtil.match(ShadowType.F_AUXILIARY_OBJECT_CLASS, elementName) || - QNameUtil.match(ShadowType.F_KIND, elementName) || - QNameUtil.match(ShadowType.F_INTENT, elementName)) { - continue; - } - throw new SchemaException("Cannot combine on-resource and off-resource properties in a shadow search query. Encountered property " + - ((PropertyValueFilter) f).getFullPath()); - } - attributeFilter.add(f); - } else if (f instanceof NaryLogicalFilter) { - List subFilters = createAttributeQueryInternal( - ((NaryLogicalFilter) f).getConditions()); - if (subFilters.size() > 1) { - if (f instanceof OrFilter) { - attributeFilter.add(prismContext.queryFactory().createOr(subFilters)); - } else if (f instanceof AndFilter) { - attributeFilter.add(prismContext.queryFactory().createAnd(subFilters)); - } else { - throw new IllegalArgumentException( - "Could not translate query filter. Unknown type: " + f); - } - } else if (subFilters.size() < 1) { - continue; - } else { - attributeFilter.add(subFilters.iterator().next()); - } - } else if (f instanceof UnaryLogicalFilter) { - ObjectFilter subFilter = ((UnaryLogicalFilter) f).getFilter(); - attributeFilter.add(prismContext.queryFactory().createNot(subFilter)); - } else if (f instanceof SubstringFilter) { - attributeFilter.add(f); - } else if (f instanceof RefFilter) { - ItemPath parentPath = ((RefFilter)f).getParentPath(); - if (parentPath.isEmpty()) { - QName elementName = ((RefFilter) f).getElementName(); - if (QNameUtil.match(ShadowType.F_RESOURCE_REF, elementName)) { - continue; - } - } - throw new SchemaException("Cannot combine on-resource and off-resource properties in a shadow search query. Encountered filter " + f); - } else { - throw new SchemaException("Cannot combine on-resource and off-resource properties in a shadow search query. Encountered filter " + f); - } - - } - - return attributeFilter; - } - - private SearchResultMetadata searchObjectsIterativeRepository(final ProvisioningContext ctx, - ObjectQuery query, Collection> options, - final ResultHandler shadowHandler, OperationResult parentResult) - throws SchemaException, ConfigurationException, ObjectNotFoundException, - CommunicationException, ExpressionEvaluationException { - ResultHandler repoHandler = createRepoShadowHandler(ctx, options, shadowHandler); - return shadowManager.searchObjectsIterativeRepository(ctx, query, options, repoHandler, parentResult); - } - - @NotNull - private ResultHandler createRepoShadowHandler(ProvisioningContext ctx, - Collection> options, ResultHandler shadowHandler) { - return (PrismObject shadow, OperationResult objResult) -> { - try { - processRepoShadow(ctx, shadow, options, objResult); - - boolean cont = shadowHandler == null || shadowHandler.handle(shadow, objResult); - - objResult.computeStatus(); - objResult.recordSuccessIfUnknown(); - if (!objResult.isSuccess()) { - OperationResultType resultType = objResult.createOperationResultType(); - shadow.asObjectable().setFetchResult(resultType); - } - - return cont; - } catch (RuntimeException e) { - objResult.recordFatalError(e); - throw e; - } catch (SchemaException | ConfigurationException | ObjectNotFoundException - | CommunicationException | ExpressionEvaluationException e) { - objResult.recordFatalError(e); - shadow.asObjectable().setFetchResult(objResult.createOperationResultType()); - throw new SystemException(e); - } - }; - } - - @NotNull - private SearchResultList> searchObjectsRepository(ProvisioningContext ctx, ObjectQuery query, - Collection> options, OperationResult parentResult) - throws SchemaException, ConfigurationException, ObjectNotFoundException, - CommunicationException, ExpressionEvaluationException { - SearchResultList> objects = shadowManager.searchObjectsRepository(ctx, query, options, parentResult); - ResultHandler repoHandler = createRepoShadowHandler(ctx, options, null); - parentResult.setSummarizeSuccesses(true); - for (PrismObject object : objects) { - repoHandler.handle(object, parentResult.createMinorSubresult(ShadowCache.class.getName() + ".handleObject")); - } - parentResult.summarize(); // todo is this ok? - return objects; - } - - private void processRepoShadow(ProvisioningContext ctx, PrismObject shadow, - Collection> options, OperationResult objResult) - throws SchemaException, ConfigurationException, ObjectNotFoundException, CommunicationException, - ExpressionEvaluationException { - shadowCaretaker.applyAttributesDefinition(ctx, shadow); - // fixing MID-1640; hoping that the protected object filter uses only identifiers - // (that are stored in repo) - ProvisioningUtil.setProtectedFlag(ctx, shadow, matchingRuleRegistry, relationRegistry); - - validateShadow(shadow, true); - - if (GetOperationOptions.isMaxStaleness(SelectorOptions.findRootOptions(options))) { - CachingMetadataType cachingMetadata = shadow.asObjectable().getCachingMetadata(); - if (cachingMetadata == null) { - objResult.recordFatalError("Requested cached data but no cached data are available in the shadow"); - } - } - } - - private void validateShadow(PrismObject shadow, boolean requireOid) { - if (requireOid) { - Validate.notNull(shadow.getOid(), "null shadow OID"); - } - if (InternalsConfig.encryptionChecks) { - CryptoUtil.checkEncrypted(shadow); - } - } - - private void notifyResourceObjectChangeListeners(PrismObject resourceShadow, PrismObject resource, boolean newShadow) { - ResourceObjectShadowChangeDescription shadowChangeDescription = new ResourceObjectShadowChangeDescription(); - shadowChangeDescription.setResource(resource); - shadowChangeDescription.setOldShadow(newShadow ? null : resourceShadow); - shadowChangeDescription.setCurrentShadow(resourceShadow); - shadowChangeDescription.setSourceChannel(SchemaConstants.CHANGE_CHANNEL_DISCOVERY_URI); - shadowChangeDescription.setUnrelatedChange(true); - - Task task = taskManager.createTaskInstance(); - notifyResourceObjectChangeListeners(shadowChangeDescription, task, task.getResult()); - } - - public void notifyResourceObjectChangeListeners(ResourceObjectShadowChangeDescription change, Task task, - OperationResult parentResult) { - changeNotificationDispatcher.notifyChange(change, task, parentResult); - } - - public Integer countObjects(ObjectQuery query, Task task, final OperationResult result) - throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, - SecurityViolationException, ExpressionEvaluationException { - - ResourceShadowDiscriminator coordinates = ObjectQueryUtil.getCoordinates(query.getFilter(), prismContext); - final ProvisioningContext ctx = ctxFactory.create(coordinates, null, result); - ctx.assertDefinition(); - applyDefinition(ctx, query); - - RefinedObjectClassDefinition objectClassDef = ctx.getObjectClassDefinition(); - ResourceType resourceType = ctx.getResource(); - CountObjectsCapabilityType countObjectsCapabilityType = objectClassDef - .getEffectiveCapability(CountObjectsCapabilityType.class, resourceType); - if (countObjectsCapabilityType == null) { - // Unable to count. Return null which means "I do not know" - LOGGER.trace("countObjects: cannot count (no counting capability)"); - result.recordNotApplicableIfUnknown(); - return null; - } else { - CountObjectsSimulateType simulate = countObjectsCapabilityType.getSimulate(); - if (simulate == null) { - // We have native capability - - LOGGER.trace("countObjects: counting with native count capability"); - ConnectorInstance connector = ctx.getConnector(ReadCapabilityType.class, result); - try { - ObjectQuery attributeQuery = createAttributeQuery(query); - int count; - try { - count = connector.count(objectClassDef.getObjectClassDefinition(), attributeQuery, - objectClassDef.getPagedSearches(resourceType), ctx, result); - } catch (CommunicationException | GenericFrameworkException | SchemaException - | UnsupportedOperationException e) { - result.recordFatalError(e); - throw e; - } - result.computeStatus(); - result.cleanupResult(); - return count; - } catch (GenericFrameworkException | UnsupportedOperationException e) { - SystemException ex = new SystemException( - "Couldn't count objects on resource " + resourceType + ": " + e.getMessage(), e); - result.recordFatalError(ex); - throw ex; - } - - } else if (simulate == CountObjectsSimulateType.PAGED_SEARCH_ESTIMATE) { - - LOGGER.trace("countObjects: simulating counting with paged search estimate"); - if (!objectClassDef.isPagedSearchEnabled(resourceType)) { - throw new ConfigurationException( - "Configured count object capability to be simulated using a paged search but paged search capability is not present"); - } - - final Holder countHolder = new Holder<>(0); - - final ResultHandler handler = new ResultHandler() { - @Override - public boolean handle(PrismObject shadow, OperationResult objResult) { - int count = countHolder.getValue(); - count++; - countHolder.setValue(count); - return true; - } - - @Override - public String toString() { - return "(ShadowCache simulated counting handler)"; - } - }; - - query = query.clone(); - ObjectPaging paging = prismContext.queryFactory().createPaging(); - // Explicitly set offset. This makes a difference for some resources. - // E.g. LDAP connector will detect presence of an offset and it will initiate VLV search which - // can estimate number of results. If no offset is specified then continuous/linear search is - // assumed (e.g. Simple Paged Results search). Such search does not have ability to estimate - // number of results. - paging.setOffset(0); - paging.setMaxSize(1); - query.setPaging(paging); - Collection> options = schemaHelper.getOperationOptionsBuilder() - .item(ShadowType.F_ASSOCIATION).dontRetrieve() - .build(); - SearchResultMetadata resultMetadata; - try { - resultMetadata = searchObjectsIterative(query, options, handler, false, task, result); - } catch (SchemaException | ObjectNotFoundException | ConfigurationException - | SecurityViolationException e) { - result.recordFatalError(e); - throw e; - } - result.computeStatus(); - result.cleanupResult(); - - return resultMetadata.getApproxNumberOfAllResults(); - - } else if (simulate == CountObjectsSimulateType.SEQUENTIAL_SEARCH) { - //fix for MID-5204. as sequentialSearch option causes to fetch all resource objects, - // query paging is senseless here - if (query != null) { - query.setPaging(null); - } - LOGGER.trace("countObjects: simulating counting with sequential search (likely performance impact)"); - // traditional way of counting objects (i.e. counting them one by one) - final Holder countHolder = new Holder<>(0); - - final ResultHandler handler = new ResultHandler() { - - @Override - public boolean handle(PrismObject shadow, OperationResult objResult) { - int count = countHolder.getValue(); - count++; - countHolder.setValue(count); - return true; - } - }; - - Collection> options = schemaHelper.getOperationOptionsBuilder() - .item(ShadowType.F_ASSOCIATION).dontRetrieve() - .build(); - - searchObjectsIterative(query, options, handler, false, task, result); - // TODO: better error handling - result.computeStatus(); - result.cleanupResult(); - return countHolder.getValue(); - - } else { - throw new IllegalArgumentException("Unknown count capability simulate type " + simulate); - - } - } - - } - - private PrismObjectDefinition getShadowDefinition() { - return prismContext.getSchemaRegistry().findObjectDefinitionByCompileTimeClass(ShadowType.class); - } - -// private void deleteShadowFromRepoIfNeeded(Change change, OperationResult parentResult) -// throws ObjectNotFoundException { -// if (change.getObjectDelta() != null && change.getObjectDelta().getChangeType() == ChangeType.DELETE -// && change.getOldShadow() != null) { -// LOGGER.trace("Deleting detected shadow object form repository."); -// try { -// repositoryService.deleteObject(ShadowType.class, change.getOldShadow().getOid(), -// parentResult); -// LOGGER.debug("Shadow object successfully deleted form repository."); -// } catch (ObjectNotFoundException ex) { -// // What we want to delete is already deleted. Not a big problem. -// LOGGER.debug("Shadow object {} already deleted from repository ({})", change.getOldShadow(), -// ex); -// parentResult.recordHandledError( -// "Shadow object " + change.getOldShadow() + " already deleted from repository", ex); -// } -// -// } -// } - - /** - * Make sure that the shadow is complete, e.g. that all the mandatory fields - * are filled (e.g name, resourceRef, ...) Also transforms the shadow with - * respect to simulated capabilities. Also shadowRefs are added to associations. - */ - public PrismObject completeShadow(ProvisioningContext ctx, - PrismObject resourceShadow, PrismObject repoShadow, boolean isDoDiscovery, - OperationResult parentResult) - throws SchemaException, ConfigurationException, ObjectNotFoundException, - CommunicationException, SecurityViolationException, GenericConnectorException, ExpressionEvaluationException, EncryptionException { - - PrismObject resultShadow = repoShadow.clone(); - - // The real definition may be different than that of repo shadow (e.g. - // different auxiliary object classes). - resultShadow.applyDefinition(ctx.getObjectClassDefinition().getObjectDefinition(), true); - - assert resultShadow.getPrismContext() != null : "No prism context in resultShadow"; - - ResourceAttributeContainer resourceAttributesContainer = ShadowUtil - .getAttributesContainer(resourceShadow); - - ShadowType resultShadowType = resultShadow.asObjectable(); - ShadowType repoShadowType = repoShadow.asObjectable(); - ShadowType resourceShadowType = resourceShadow.asObjectable(); - - Collection auxObjectClassQNames = new ArrayList<>(); - - // Always take auxiliary object classes from the resource. Unlike - // structural object classes - // the auxiliary object classes may change. - resultShadow.removeProperty(ShadowType.F_AUXILIARY_OBJECT_CLASS); - PrismProperty resourceAuxOcProp = resourceShadow - .findProperty(ShadowType.F_AUXILIARY_OBJECT_CLASS); - if (resourceAuxOcProp != null) { - PrismProperty resultAuxOcProp = resultShadow - .findOrCreateProperty(ShadowType.F_AUXILIARY_OBJECT_CLASS); - resultAuxOcProp.addAll(PrismValueCollectionsUtil.cloneCollection(resourceAuxOcProp.getValues())); - auxObjectClassQNames.addAll(resultAuxOcProp.getRealValues()); - } - - resultShadowType.setName(new PolyStringType(ShadowUtil.determineShadowName(resourceShadow))); - if (resultShadowType.getObjectClass() == null) { - resultShadowType.setObjectClass(resourceAttributesContainer.getDefinition().getTypeName()); - } - - // Attributes - resultShadow.removeContainer(ShadowType.F_ATTRIBUTES); - ResourceAttributeContainer resultAttributes = resourceAttributesContainer.clone(); - accessChecker.filterGetAttributes(resultAttributes, ctx.computeCompositeObjectClassDefinition(auxObjectClassQNames), parentResult); - resultShadow.add(resultAttributes); - - resultShadowType.setIgnored(resourceShadowType.isIgnored()); - - resultShadowType.setActivation(resourceShadowType.getActivation()); - - ShadowType resultAccountShadow = resultShadow.asObjectable(); - ShadowType resourceAccountShadow = resourceShadow.asObjectable(); - - // Credentials - resultAccountShadow.setCredentials(resourceAccountShadow.getCredentials()); - transplantPasswordMetadata(repoShadowType, resultAccountShadow); - - // protected - ProvisioningUtil.setProtectedFlag(ctx, resultShadow, matchingRuleRegistry, relationRegistry); - - // exists, dead - // This may seem strange, but always take exists and dead flags from the repository. - // Repository is wiser in this case. It may seem that the shadow exists if it is returned - // by the resource. But that may be just a quantum illusion (gestation and corpse shadow states). - - // Activation - ActivationType resultActivationType = resultShadowType.getActivation(); - ActivationType repoActivation = repoShadowType.getActivation(); - if (repoActivation != null) { - if (resultActivationType == null) { - resultActivationType = new ActivationType(); - resultShadowType.setActivation(resultActivationType); - } - resultActivationType.setId(repoActivation.getId()); - // .. but we want metadata from repo - resultActivationType.setDisableReason(repoActivation.getDisableReason()); - resultActivationType.setEnableTimestamp(repoActivation.getEnableTimestamp()); - resultActivationType.setDisableTimestamp(repoActivation.getDisableTimestamp()); - resultActivationType.setArchiveTimestamp(repoActivation.getArchiveTimestamp()); - resultActivationType.setValidityChangeTimestamp(repoActivation.getValidityChangeTimestamp()); - } - - // Associations - PrismContainer resourceAssociationContainer = resourceShadow - .findContainer(ShadowType.F_ASSOCIATION); - if (resourceAssociationContainer != null) { - PrismContainer associationContainer = resourceAssociationContainer.clone(); - resultShadow.addReplaceExisting(associationContainer); - completeAssociations(ctx, resourceShadow, repoShadow, isDoDiscovery, associationContainer, parentResult); - } - - resultShadowType.setCachingMetadata(resourceShadowType.getCachingMetadata()); - - // Sanity asserts to catch some exotic bugs - PolyStringType resultName = resultShadow.asObjectable().getName(); - assert resultName != null : "No name generated in " + resultShadow; - assert !StringUtils.isEmpty(resultName.getOrig()) : "No name (orig) in " + resultShadow; - assert !StringUtils.isEmpty(resultName.getNorm()) : "No name (norm) in " + resultShadow; - - return resultShadow; - } - - private void completeAssociations(ProvisioningContext ctx, PrismObject resourceShadow, PrismObject repoShadow, boolean isDoDiscovery, PrismContainer associationContainer, OperationResult parentResult) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, ExpressionEvaluationException, SecurityViolationException, EncryptionException { - if (associationContainer == null) { - return; - } - - Iterator> iterator = associationContainer.getValues().iterator(); - while (iterator.hasNext()) { - PrismContainerValue associationCVal = iterator.next(); - - ResourceAttributeContainer identifierContainer = ShadowUtil.getAttributesContainer(associationCVal, ShadowAssociationType.F_IDENTIFIERS); - Collection> entitlementIdentifiers = identifierContainer.getAttributes(); - if (entitlementIdentifiers == null || entitlementIdentifiers.isEmpty()) { - throw new IllegalStateException("No entitlement identifiers present for association " + associationCVal + " " + ctx.getDesc()); - } - ShadowAssociationType shadowAssociationType = associationCVal.asContainerable(); - QName associationName = shadowAssociationType.getName(); - RefinedAssociationDefinition rEntitlementAssociationDef = ctx.getObjectClassDefinition().findAssociationDefinition(associationName); - if (rEntitlementAssociationDef == null) { - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Entitlement association with name {} couldn't be found in {} {}\nresource shadow:\n{}\nrepo shadow:\n{}", - associationName, ctx.getObjectClassDefinition(), ctx.getDesc(), - resourceShadow.debugDump(1), repoShadow == null ? null : repoShadow.debugDump(1)); - LOGGER.trace("Full refined definition: {}", ctx.getObjectClassDefinition().debugDump()); - } - throw new SchemaException("Entitlement association with name " + associationName - + " couldn't be found in " + ctx.getObjectClassDefinition() + " " + ctx.getDesc() + ", with using shadow coordinates " + ctx.isUseRefinedDefinition()); - } - ShadowKindType entitlementKind = rEntitlementAssociationDef.getKind(); - if (entitlementKind == null) { - entitlementKind = ShadowKindType.ENTITLEMENT; - } - - for (String entitlementIntent : rEntitlementAssociationDef.getIntents()) { - ProvisioningContext ctxEntitlement = ctx.spawn(entitlementKind, entitlementIntent); - - PrismObject entitlementRepoShadow; - PrismObject entitlementShadow = identifierContainer.getUserData(ResourceObjectConverter.FULL_SHADOW_KEY); - if (entitlementShadow == null) { - try { - entitlementRepoShadow = shadowManager.lookupShadowInRepository(ctxEntitlement, identifierContainer, parentResult); - if (entitlementRepoShadow == null) { - - entitlementShadow = resourceObjectConverter.locateResourceObject(ctxEntitlement, entitlementIdentifiers, parentResult); - - // Try to look up repo shadow again, this time with full resource shadow. When we - // have searched before we might have only some identifiers. The shadow - // might still be there, but it may be renamed - entitlementRepoShadow = acquireRepositoryShadow(ctxEntitlement, entitlementShadow, false, isDoDiscovery, parentResult); - } - } catch (ObjectNotFoundException e) { - // The entitlement to which we point is not there. - // Simply ignore this association value. - parentResult.muteLastSubresultError(); - LOGGER.warn("The entitlement identified by {} referenced from {} does not exist. Skipping.", associationCVal, resourceShadow); - continue; - } catch (SchemaException e) { - // The entitlement to which we point is not bad. - // Simply ignore this association value. - parentResult.muteLastSubresultError(); - LOGGER.warn("The entitlement identified by {} referenced from {} violates the schema. Skipping. Original error: {}-{}", - associationCVal, resourceShadow, e.getMessage(), e); - continue; - } - } else { - entitlementRepoShadow = acquireRepositoryShadow(ctxEntitlement, - entitlementShadow, false, isDoDiscovery, parentResult); - } - if (doesAssociationMatch(rEntitlementAssociationDef, entitlementRepoShadow)) { - ObjectReferenceType shadowRefType = ObjectTypeUtil.createObjectRef(entitlementRepoShadow, prismContext); - shadowAssociationType.setShadowRef(shadowRefType); - } else { - // We have association value that does not match its definition. This may happen because the association attribute - // may be shared among several associations. The EntitlementConverter code has no way to tell them apart. - // We can do that only if we have shadow or full resource object. And that is available at this point only. - // Therefore just silently filter out the association values that do not belong here. - // See MID-5790 - iterator.remove(); - } - } - } - } - - private boolean doesAssociationMatch(RefinedAssociationDefinition rEntitlementAssociationDef, PrismObject entitlementRepoShadow) { - ShadowKindType shadowKind = ShadowUtil.getKind(entitlementRepoShadow.asObjectable()); - String shadowIntent = ShadowUtil.getIntent(entitlementRepoShadow.asObjectable()); - if (shadowKind == null || shadowKind == ShadowKindType.UNKNOWN || shadowIntent == null) { - // We have unclassified shadow here. This should not happen in a well-configured system. But the world is a tough place. - // In case that this happens let's just keep all such shadows in all associations. This is how midPoint worked before, - // therefore we will get better compatibility. But it is also better for visibility. MidPoint will show data that are - // wrong. But it will at least show something. The alternative would be to show nothing, which is not really friendly - // for debugging. - return true; - } - ShadowKindType defKind = rEntitlementAssociationDef.getKind(); - if (defKind == null) { - defKind = ShadowKindType.ENTITLEMENT; - } - if (!defKind.equals(shadowKind)) { - return false; - } - Collection defIntents = rEntitlementAssociationDef.getIntents(); - if (!defIntents.contains(shadowIntent)) { - return false; - } - return true; - } - - private void transplantPasswordMetadata(ShadowType repoShadowType, ShadowType resultAccountShadow) { - CredentialsType repoCreds = repoShadowType.getCredentials(); - if (repoCreds == null) { - return; - } - PasswordType repoPassword = repoCreds.getPassword(); - if (repoPassword == null) { - return; - } - MetadataType repoMetadata = repoPassword.getMetadata(); - if (repoMetadata == null) { - return; - } - CredentialsType resultCreds = resultAccountShadow.getCredentials(); - if (resultCreds == null) { - resultCreds = new CredentialsType(); - resultAccountShadow.setCredentials(resultCreds); - } - PasswordType resultPassword = resultCreds.getPassword(); - if (resultPassword == null) { - resultPassword = new PasswordType(); - resultCreds.setPassword(resultPassword); - } - MetadataType resultMetadata = resultPassword.getMetadata(); - if (resultMetadata == null) { - resultMetadata = repoMetadata.clone(); - resultPassword.setMetadata(resultMetadata); - } - } - - // ENTITLEMENTS - - /** - * Makes sure that all the entitlements have identifiers in them so this is - * usable by the ResourceObjectConverter. - */ - private void preprocessEntitlements(final ProvisioningContext ctx, final PrismObject shadow, - final OperationResult result) throws SchemaException, ObjectNotFoundException, - ConfigurationException, CommunicationException, ExpressionEvaluationException { - try { - shadow.accept( - (visitable) -> { - try { - preprocessEntitlement(ctx, (PrismContainerValue) visitable, - shadow.toString(), result); - } catch (SchemaException | ObjectNotFoundException | ConfigurationException - | CommunicationException | ExpressionEvaluationException e) { - throw new TunnelException(e); - } - }, - ItemPath.create(ShadowType.F_ASSOCIATION, null), false); - } catch (TunnelException e) { - Throwable cause = e.getCause(); - if (cause instanceof SchemaException) { - throw (SchemaException) cause; - } else if (cause instanceof ObjectNotFoundException) { - throw (ObjectNotFoundException) cause; - } else if (cause instanceof ConfigurationException) { - throw (ConfigurationException) cause; - } else if (cause instanceof CommunicationException) { - throw (CommunicationException) cause; - } else if (cause instanceof ExpressionEvaluationException) { - throw (ExpressionEvaluationException) cause; - } else { - throw new SystemException("Unexpected exception " + cause, cause); - } - } - } - - /** - * Makes sure that all the entitlements have identifiers in them so this is - * usable by the ResourceObjectConverter. - */ - private void preprocessEntitlements(final ProvisioningContext ctx, - Collection modifications, final String desc, final OperationResult result) - throws SchemaException, ObjectNotFoundException, ConfigurationException, - CommunicationException, ExpressionEvaluationException { - try { - ItemDeltaCollectionsUtil.accept(modifications, - (visitable) -> { - try { - preprocessEntitlement(ctx, (PrismContainerValue) visitable, desc, - result); - } catch (SchemaException | ObjectNotFoundException | ConfigurationException - | CommunicationException | ExpressionEvaluationException e) { - throw new TunnelException(e); - } - }, - ItemPath.create(ShadowType.F_ASSOCIATION, null), false); - } catch (TunnelException e) { - Throwable cause = e.getCause(); - if (cause instanceof SchemaException) { - throw (SchemaException) cause; - } else if (cause instanceof ObjectNotFoundException) { - throw (ObjectNotFoundException) cause; - } else if (cause instanceof ConfigurationException) { - throw (ConfigurationException) cause; - } else if (cause instanceof CommunicationException) { - throw (CommunicationException) cause; - } else if (cause instanceof ExpressionEvaluationException) { - throw (ExpressionEvaluationException) cause; - } else { - throw new SystemException("Unexpected exception " + cause, cause); - } - } - } - - private void preprocessEntitlement(ProvisioningContext ctx, - PrismContainerValue association, String desc, OperationResult result) - throws SchemaException, ObjectNotFoundException, ConfigurationException, - CommunicationException, ExpressionEvaluationException { - PrismContainer identifiersContainer = association - .findContainer(ShadowAssociationType.F_IDENTIFIERS); - if (identifiersContainer != null && !identifiersContainer.isEmpty()) { - // We already have identifiers here - return; - } - ShadowAssociationType associationType = association.asContainerable(); - LOGGER.info("###Shadow association: {}, class: {}", associationType.getName(), associationType.getName().getClass()); - if (associationType.getShadowRef() == null - || StringUtils.isEmpty(associationType.getShadowRef().getOid())) { - throw new SchemaException( - "No identifiers and no OID specified in entitlements association " + association); - } - PrismObject repoShadow; - try { - repoShadow = repositoryService.getObject(ShadowType.class, - associationType.getShadowRef().getOid(), null, result); - } catch (ObjectNotFoundException e) { - throw new ObjectNotFoundException(e.getMessage() - + " while resolving entitlement association OID in " + association + " in " + desc, e); - } - shadowCaretaker.applyAttributesDefinition(ctx, repoShadow); - transplantIdentifiers(association, repoShadow); - } - - private void transplantIdentifiers(PrismContainerValue association, - PrismObject repoShadow) throws SchemaException { - PrismContainer identifiersContainer = association - .findContainer(ShadowAssociationType.F_IDENTIFIERS); - if (identifiersContainer == null) { - ResourceAttributeContainer origContainer = ShadowUtil.getAttributesContainer(repoShadow); - identifiersContainer = ObjectFactory.createResourceAttributeContainer(ShadowAssociationType.F_IDENTIFIERS, - origContainer.getDefinition(), prismContext); - association.add(identifiersContainer); - } - Collection> identifiers = ShadowUtil.getPrimaryIdentifiers(repoShadow); - for (ResourceAttribute identifier : identifiers) { - identifiersContainer.add(identifier.clone()); - } - Collection> secondaryIdentifiers = ShadowUtil - .getSecondaryIdentifiers(repoShadow); - for (ResourceAttribute identifier : secondaryIdentifiers) { - identifiersContainer.add(identifier.clone()); - } - } - - public void propagateOperations(PrismObject resource, PrismObject shadow, Task task, OperationResult result) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException, GenericFrameworkException, ObjectAlreadyExistsException, SecurityViolationException, PolicyViolationException, EncryptionException { - ResourceConsistencyType resourceConsistencyType = resource.asObjectable().getConsistency(); - if (resourceConsistencyType == null) { - LOGGER.warn("Skipping propagation of {} because no there is no consistency definition in resource", shadow); - return; - } - Duration operationGroupingInterval = resourceConsistencyType.getOperationGroupingInterval(); - if (operationGroupingInterval == null) { - LOGGER.warn("Skipping propagation of {} because no there is no operationGroupingInterval defined in resource", shadow); - return; - } - XMLGregorianCalendar now = clock.currentTimeXMLGregorianCalendar(); - - List pendingExecutionOperations = new ArrayList<>(); - boolean triggered = false; - for (PendingOperationType pendingOperation: shadow.asObjectable().getPendingOperation()) { - PendingOperationExecutionStatusType executionStatus = pendingOperation.getExecutionStatus(); - if (executionStatus == PendingOperationExecutionStatusType.EXECUTION_PENDING) { - pendingExecutionOperations.add(pendingOperation); - if (isPropagationTriggered(pendingOperation, operationGroupingInterval, now)) { - triggered = true; - } - } - } - if (!triggered) { - LOGGER.debug("Skipping propagation of {} because no pending operation triggered propagation", shadow); - return; - } - if (pendingExecutionOperations.isEmpty()) { - LOGGER.debug("Skipping propagation of {} because there are no pending executions", shadow); - return; - } - LOGGER.debug("Propagating {} pending operations in {} ", pendingExecutionOperations.size(), shadow); - - ObjectDelta operationDelta = null; - List sortedOperations = shadowCaretaker.sortPendingOperations(pendingExecutionOperations); - for (PendingOperationType pendingOperation: sortedOperations) { - ObjectDeltaType pendingDeltaType = pendingOperation.getDelta(); - ObjectDelta pendingDelta = DeltaConvertor.createObjectDelta(pendingDeltaType, prismContext); - applyDefinition(pendingDelta, shadow.asObjectable(), result); - if (operationDelta == null) { - operationDelta = pendingDelta; - } else { - operationDelta.merge(pendingDelta); - } - } - - ProvisioningContext ctx = ctxFactory.create(shadow, task, result); - ctx.setPropagation(true); - shadowCaretaker.applyAttributesDefinition(ctx, shadow); - shadowCaretaker.applyAttributesDefinition(ctx, operationDelta); - LOGGER.trace("Merged operation for {}:\n{} ", shadow, operationDelta.debugDumpLazily(1)); - - if (operationDelta.isAdd()) { - PrismObject shadowToAdd = operationDelta.getObjectToAdd(); - ProvisioningOperationState>> opState = - ProvisioningOperationState.fromPendingOperations(shadow, sortedOperations); - shadowToAdd.setOid(shadow.getOid()); - addShadowAttempt(ctx, shadowToAdd, null, opState, null, task, result); - opState.determineExecutionStatusFromResult(); - - shadowManager.updatePendingOperations(ctx, shadow, opState, pendingExecutionOperations, now, result); - - notifyAfterAdd(ctx, opState.getAsyncResult().getReturnValue(), opState, task, result); - - } else if (operationDelta.isModify()) { - Collection> modifications = operationDelta.getModifications(); - ProvisioningOperationState>>> opState = - executeResourceModify(ctx, shadow, modifications, null, null, now, task, result); - opState.determineExecutionStatusFromResult(); - - shadowManager.updatePendingOperations(ctx, shadow, opState, pendingExecutionOperations, now, result); - - notifyAfterModify(ctx, shadow, modifications, opState, task, result); - - } else if (operationDelta.isDelete()) { - ProvisioningOperationState opState = executeResourceDelete(ctx, shadow, null, null, task, result); - opState.determineExecutionStatusFromResult(); - - shadowManager.updatePendingOperations(ctx, shadow, opState, pendingExecutionOperations, now, result); - - notifyAfterDelete(ctx, shadow, opState, task, result); - - } else { - throw new IllegalStateException("Delta from outer space: "+operationDelta); - } - - // do we need to modify exists/dead flags? - - } - - private boolean isPropagationTriggered(PendingOperationType pendingOperation, Duration operationGroupingInterval, XMLGregorianCalendar now) { - XMLGregorianCalendar requestTimestamp = pendingOperation.getRequestTimestamp(); - if (requestTimestamp == null) { - return false; - } - return XmlTypeConverter.isAfterInterval(requestTimestamp, operationGroupingInterval, now); - } - - public ItemComparisonResult compare(PrismObject repositoryShadow, ItemPath path, T expectedValue, Task task, OperationResult parentResult) - throws ObjectNotFoundException, CommunicationException, SchemaException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException, EncryptionException { - - if (!path.equivalent(SchemaConstants.PATH_PASSWORD_VALUE)) { - throw new UnsupportedOperationException("Only password comparison is supported"); - } - - ProvisioningContext ctx = ctxFactory.create(repositoryShadow, task, parentResult); - try { - ctx.assertDefinition(); - shadowCaretaker.applyAttributesDefinition(ctx, repositoryShadow); - } catch (ObjectNotFoundException | SchemaException | CommunicationException - | ConfigurationException | ExpressionEvaluationException e) { - throw e; - } - - ResourceType resource = ctx.getResource(); - - PasswordCompareStrategyType passwordCompareStrategy = getPasswordCompareStrategy(ctx.getObjectClassDefinition()); - if (passwordCompareStrategy == PasswordCompareStrategyType.ERROR) { - throw new UnsupportedOperationException("Password comparison is not supported on "+resource); - } - - PrismProperty repoProperty = repositoryShadow.findProperty(path); - if (repoProperty == null) { - if (passwordCompareStrategy == PasswordCompareStrategyType.CACHED) { - if (expectedValue == null) { - return ItemComparisonResult.MATCH; - } else { - return ItemComparisonResult.MISMATCH; - } - } else { - // AUTO - return ItemComparisonResult.NOT_APPLICABLE; - } - } - - ProtectedStringType repoProtectedString = (ProtectedStringType) repoProperty.getRealValue(); - ProtectedStringType expectedProtectedString; - if (expectedValue instanceof ProtectedStringType) { - expectedProtectedString = (ProtectedStringType) expectedValue; - } else { - expectedProtectedString = new ProtectedStringType(); - expectedProtectedString.setClearValue((String) expectedValue); - } - if (protector.compareCleartext(repoProtectedString, expectedProtectedString)) { - return ItemComparisonResult.MATCH; - } else { - return ItemComparisonResult.MISMATCH; - } - } - - private PasswordCompareStrategyType getPasswordCompareStrategy(RefinedObjectClassDefinition objectClassDefinition) { - ResourcePasswordDefinitionType passwordDefinition = objectClassDefinition.getPasswordDefinition(); - if (passwordDefinition == null) { - return null; - } - return passwordDefinition.getCompareStrategy(); - } - - private ConnectorOperationOptions createConnectorOperationOptions(ProvisioningContext ctx, ProvisioningOperationOptions options, OperationResult result) throws SchemaException, ConfigurationException, ObjectNotFoundException, CommunicationException, ExpressionEvaluationException { - if (options == null) { - return null; - } - String runAsAccountOid = options.getRunAsAccountOid(); - if (runAsAccountOid == null) { - return null; - } - RunAsCapabilityType capRunAs = ctx.getEffectiveCapability(RunAsCapabilityType.class); - if (capRunAs == null) { - LOGGER.trace("Operation runAs requested, but resource does not have the capability. Ignoring runAs"); - return null; - } - PrismObject runAsShadow; - try { - runAsShadow = shadowManager.getRepoShadow(runAsAccountOid, result); - } catch (ObjectNotFoundException e) { - throw new ConfigurationException("Requested non-existing 'runAs' shadow", e); - } - ProvisioningContext runAsCtx = ctxFactory.create(runAsShadow, null, ctx.getTask(), result); - shadowCaretaker.applyAttributesDefinition(runAsCtx, runAsShadow); - ResourceObjectIdentification runAsIdentification = ResourceObjectIdentification.createFromShadow(runAsCtx.getObjectClassDefinition(), runAsShadow.asObjectable()); - ConnectorOperationOptions connOptions = new ConnectorOperationOptions(); - LOGGER.trace("RunAs identification: {}", runAsIdentification); - connOptions.setRunAsIdentification(runAsIdentification); - return connOptions; - } - - private String getAdditionalOperationDesc(OperationProvisioningScriptsType scripts, - ProvisioningOperationOptions options) { - if (scripts == null && options == null) { - return ""; - } - StringBuilder sb = new StringBuilder(" ("); - if (options != null) { - sb.append("options:"); - options.shortDump(sb); - if (scripts != null) { - sb.append("; "); - } - } - if (scripts != null) { - sb.append("scripts"); - } - sb.append(")"); - return sb.toString(); - } - -} +/* + * Copyright (c) 2010-2019 Evolveum and contributors + * + * This work is dual-licensed under the Apache License 2.0 + * and European Union Public License. See LICENSE file for details. + */ +package com.evolveum.midpoint.provisioning.impl; + +import com.evolveum.midpoint.common.Clock; +import com.evolveum.midpoint.common.crypto.CryptoUtil; +import com.evolveum.midpoint.common.refinery.RefinedAssociationDefinition; +import com.evolveum.midpoint.common.refinery.RefinedObjectClassDefinition; +import com.evolveum.midpoint.common.refinery.ShadowDiscriminatorObjectDelta; +import com.evolveum.midpoint.prism.*; +import com.evolveum.midpoint.prism.crypto.EncryptionException; +import com.evolveum.midpoint.prism.crypto.Protector; +import com.evolveum.midpoint.prism.delta.*; +import com.evolveum.midpoint.prism.match.MatchingRuleRegistry; +import com.evolveum.midpoint.prism.path.*; +import com.evolveum.midpoint.prism.polystring.PolyString; +import com.evolveum.midpoint.prism.query.*; +import com.evolveum.midpoint.prism.xml.XmlTypeConverter; +import com.evolveum.midpoint.provisioning.api.*; +import com.evolveum.midpoint.provisioning.impl.errorhandling.ErrorHandler; +import com.evolveum.midpoint.provisioning.impl.errorhandling.ErrorHandlerLocator; +import com.evolveum.midpoint.provisioning.impl.shadowmanager.ShadowManager; +import com.evolveum.midpoint.provisioning.ucf.api.*; +import com.evolveum.midpoint.provisioning.util.ProvisioningUtil; +import com.evolveum.midpoint.repo.api.RepositoryService; +import com.evolveum.midpoint.schema.*; +import com.evolveum.midpoint.schema.cache.CacheConfigurationManager; +import com.evolveum.midpoint.schema.constants.SchemaConstants; +import com.evolveum.midpoint.schema.internals.InternalCounters; +import com.evolveum.midpoint.schema.internals.InternalMonitor; +import com.evolveum.midpoint.schema.internals.InternalsConfig; +import com.evolveum.midpoint.schema.processor.*; +import com.evolveum.midpoint.schema.processor.ObjectFactory; +import com.evolveum.midpoint.schema.result.AsynchronousOperationResult; +import com.evolveum.midpoint.schema.result.AsynchronousOperationReturnValue; +import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.schema.result.OperationResultStatus; +import com.evolveum.midpoint.schema.util.ObjectQueryUtil; +import com.evolveum.midpoint.schema.util.ObjectTypeUtil; +import com.evolveum.midpoint.schema.util.ResourceTypeUtil; +import com.evolveum.midpoint.schema.util.ShadowUtil; +import com.evolveum.midpoint.task.api.Task; +import com.evolveum.midpoint.task.api.TaskManager; +import com.evolveum.midpoint.util.DebugUtil; +import com.evolveum.midpoint.util.Holder; +import com.evolveum.midpoint.util.QNameUtil; +import com.evolveum.midpoint.util.exception.*; +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.resource.capabilities_3.*; +import com.evolveum.prism.xml.ns._public.types_3.ChangeTypeType; +import com.evolveum.prism.xml.ns._public.types_3.ObjectDeltaType; +import com.evolveum.prism.xml.ns._public.types_3.PolyStringType; +import com.evolveum.prism.xml.ns._public.types_3.ProtectedStringType; + +import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang.Validate; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +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.Duration; +import javax.xml.datatype.XMLGregorianCalendar; +import javax.xml.namespace.QName; + + +import java.util.*; + +/** + * Shadow cache is a facade that covers all the operations with shadows. It + * takes care of splitting the operations between repository and resource, + * merging the data back, handling the errors and generally controlling the + * process. + * + * The two principal classes that do the operations are: + * ResourceObjectConvertor: executes operations on resource + * ShadowManager: executes operations in the repository + * + * @author Radovan Semancik + * @author Katarina Valalikova + * + */ +@Component +public class ShadowCache { + + private static final String OP_DELAYED_OPERATION = ShadowCache.class.getName() + ".delayedOperation"; + private static final String OP_OPERATION_RETRY = ShadowCache.class.getName() + ".operationRetry"; + private static final String OP_RESOURCE_OPERATION = ShadowCache.class.getName() + ".resourceOperation"; + private static final String OP_REFRESH_RETRY = ShadowCache.class.getName() + ".refreshRetry"; + + @Autowired + @Qualifier("cacheRepositoryService") + private RepositoryService repositoryService; + + @Autowired private ErrorHandlerLocator errorHandlerLocator; + @Autowired private ResourceManager resourceManager; + @Autowired private Clock clock; + @Autowired private PrismContext prismContext; + @Autowired private SchemaHelper schemaHelper; + @Autowired private ResourceObjectConverter resourceObjectConverter; + @Autowired private ShadowCaretaker shadowCaretaker; + @Autowired private MatchingRuleRegistry matchingRuleRegistry; + @Autowired private RelationRegistry relationRegistry; + @Autowired protected ShadowManager shadowManager; + @Autowired private ChangeNotificationDispatcher operationListener; + @Autowired private AccessChecker accessChecker; + @Autowired private TaskManager taskManager; + @Autowired private ChangeNotificationDispatcher changeNotificationDispatcher; + @Autowired private ProvisioningContextFactory ctxFactory; + @Autowired private Protector protector; + @Autowired private CacheConfigurationManager cacheConfigurationManager; + + private static final Trace LOGGER = TraceManager.getTrace(ShadowCache.class); + + /** + * Get the value of repositoryService. + * + * DO NOT USE. Only ShadowManager should access repository + * + * @return the value of repositoryService + */ + @Deprecated + public RepositoryService getRepositoryService() { + return repositoryService; + } + + public PrismContext getPrismContext() { + return prismContext; + } + + public PrismObject getShadow(String oid, PrismObject repositoryShadow, + Collection> identifiersOverride, Collection> options, + Task task, OperationResult parentResult) + throws ObjectNotFoundException, CommunicationException, SchemaException, + ConfigurationException, SecurityViolationException, ExpressionEvaluationException, EncryptionException { + + Validate.notNull(oid, "Object id must not be null."); + + if (repositoryShadow == null) { + LOGGER.trace("Start getting object with oid {}; identifiers override = {}", oid, identifiersOverride); + } else { + LOGGER.trace("Start getting object {}; identifiers override = {}", repositoryShadow, identifiersOverride); + } + + GetOperationOptions rootOptions = SelectorOptions.findRootOptions(options); + + // We are using parent result directly, not creating subresult. + // We want to hide the existence of shadow cache from the user. + + // Get the shadow from repository. There are identifiers that we need + // for accessing the object by UCF.Later, the repository object may + // have a fully cached object from the resource. + if (repositoryShadow == null) { + repositoryShadow = repositoryService.getObject(ShadowType.class, oid, null, parentResult); + LOGGER.trace("Got repository shadow object:\n{}", repositoryShadow.debugDumpLazily()); + } + + // Sanity check + if (!oid.equals(repositoryShadow.getOid())) { + parentResult.recordFatalError("Provided OID is not equal to OID of repository shadow"); + throw new IllegalArgumentException("Provided OID is not equal to OID of repository shadow"); + } + + ProvisioningContext ctx = ctxFactory.create(repositoryShadow, task, parentResult); + ctx.setGetOperationOptions(options); + ctx.assertDefinition(); + shadowCaretaker.applyAttributesDefinition(ctx, repositoryShadow); + + ResourceType resource = ctx.getResource(); + XMLGregorianCalendar now = clock.currentTimeXMLGregorianCalendar(); + + if (GetOperationOptions.isNoFetch(rootOptions) || GetOperationOptions.isRaw(rootOptions)) { + return processNoFetchGet(ctx, repositoryShadow, options, now, task, parentResult); + } + + if (!ResourceTypeUtil.isReadCapabilityEnabled(resource)) { + UnsupportedOperationException e = new UnsupportedOperationException("Resource does not support 'read' operation"); + parentResult.recordFatalError(e); + throw e; + } + + if (shouldRefreshOnRead(resource, rootOptions)) { + LOGGER.trace("Refreshing {} before reading", repositoryShadow); + ProvisioningOperationOptions refreshOpts = toProvisioningOperationOptions(rootOptions); + RefreshShadowOperation refreshShadowOperation = refreshShadow(repositoryShadow, refreshOpts, task, parentResult); + if (refreshShadowOperation != null) { + repositoryShadow = refreshShadowOperation.getRefreshedShadow(); + } + LOGGER.trace("Refreshed repository shadow:\n{}", DebugUtil.debugDumpLazily(repositoryShadow, 1)); + } + if (repositoryShadow == null) { + // Dead shadow was just removed + // TODO: is this OK? What about re-appeared objects + LOGGER.warn("DEAD shadow {} DEAD?", oid); + ObjectNotFoundException e = new ObjectNotFoundException("Resource object does not exist"); + parentResult.recordFatalError(e); + throw e; + } + + ShadowState shadowState = shadowCaretaker.determineShadowState(ctx, repositoryShadow, now); + LOGGER.trace("State of shadow {}: {}", repositoryShadow, shadowState); + + if (canImmediatelyReturnCached(options, repositoryShadow, shadowState, resource)) { + LOGGER.trace("Returning cached (repository) version of shadow {}", repositoryShadow); + PrismObject resultShadow = futurizeShadow(ctx, repositoryShadow, null, options, now); + shadowCaretaker.applyAttributesDefinition(ctx, resultShadow); + validateShadow(resultShadow, true); + return resultShadow; + } + + PrismObject resourceObject; + + if (identifiersOverride == null) { + Collection> primaryIdentifiers = ShadowUtil.getPrimaryIdentifiers(repositoryShadow); + if (primaryIdentifiers == null || primaryIdentifiers.isEmpty()) { + if (ProvisioningUtil.hasPendingAddOperation(repositoryShadow) || ShadowUtil + .isDead(repositoryShadow.asObjectable())) { + if (ProvisioningUtil.isFuturePointInTime(options)) { + // Get of uncreated or dead shadow, we want to see future state (how the shadow WILL look like). + // We cannot even try fetch operation here. We do not have the identifiers. + // But we have quite a good idea how the shadow is going to look like. Therefore we can return it. + PrismObject resultShadow = futurizeShadow(ctx, repositoryShadow, null, options, now); + shadowCaretaker.applyAttributesDefinition(ctx, resultShadow); + validateShadow(resultShadow, true); + // NOTE: do NOT re-try add operation here. It will be retried in separate task. + // re-trying the operation here would not provide big benefits and it will complicate the code. + return resultShadow; + } else { + // Get of uncreated shadow, but we want current state. Therefore we have to throw an error because + // the object does not exist yet - to our best knowledge. But we cannot really throw ObjectNotFound here. + // ObjectNotFound is a positive indication that the object does not exist. + // We do not know that for sure because resource is unavailable. The object might have been created in the meantime. + throw new GenericConnectorException( + "Unable to get object from the resource. Probably it has not been created yet because of previous unavailability of the resource."); + } + } + + // No identifiers found + SchemaException ex = new SchemaException("No primary identifiers found in the repository shadow " + + repositoryShadow + " with respect to " + resource); + parentResult.recordFatalError("No primary identifiers found in the repository shadow " + repositoryShadow, ex); + throw ex; + } + } + + Collection> identifiers = identifiersOverride != null ? identifiersOverride : + ShadowUtil.getAllIdentifiers(repositoryShadow); + try { + + try { + + resourceObject = resourceObjectConverter.getResourceObject(ctx, identifiers, true, parentResult); + + } catch (ObjectNotFoundException e) { + // This may be OK, e.g. for connectors that have running async add operation. + if (shadowState == ShadowState.CONCEPTION || shadowState == ShadowState.GESTATION) { + LOGGER.trace("{} was not found, but we can return cached shadow because it is in {} state", repositoryShadow, shadowState); + parentResult.deleteLastSubresultIfError(); // we don't want to see 'warning-like' orange boxes in GUI (TODO reconsider this) + parentResult.recordSuccess(); + + PrismObject resultShadow = futurizeShadow(ctx, repositoryShadow, null, options, now); + shadowCaretaker.applyAttributesDefinition(ctx, resultShadow); + LOGGER.trace("Returning futurized shadow:\n{}", DebugUtil.debugDumpLazily(resultShadow)); + validateShadow(resultShadow, true); + return resultShadow; + + } else { + LOGGER.trace("{} was not found, following normal error processing because shadow is in {} state", repositoryShadow, shadowState); + // This is live shadow that was not found on resource. Just re-throw the exception. It will + // be caught later and the usual error handlers will bury the shadow. + throw e; + } + } + + LOGGER.trace("Shadow returned by ResourceObjectConverter:\n{}", resourceObject.debugDumpLazily(1)); + + // Resource shadow may have different auxiliary object classes than + // the original repo shadow. Make sure we have the definition that + // applies to resource shadow. We will fix repo shadow later. + // BUT we need also information about kind/intent and these information is only + // in repo shadow, therefore the following 2 lines.. + resourceObject.asObjectable().setKind(repositoryShadow.asObjectable().getKind()); + resourceObject.asObjectable().setIntent(repositoryShadow.asObjectable().getIntent()); + ProvisioningContext shadowCtx = ctx.spawn(resourceObject); + + String operationCtx = "getting " + repositoryShadow + " was successfull."; + + resourceManager.modifyResourceAvailabilityStatus(resource.getOid(), AvailabilityStatusType.UP, operationCtx, task, parentResult, false); + + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("Shadow from repository:\n{}", repositoryShadow.debugDump(1)); + LOGGER.trace("Resource object fetched from resource:\n{}", resourceObject.debugDump(1)); + } + + repositoryShadow = shadowManager.updateShadow(shadowCtx, resourceObject, null, repositoryShadow, shadowState, parentResult); + LOGGER.trace("Repository shadow after update:\n{}", repositoryShadow.debugDumpLazily(1)); + + // Complete the shadow by adding attributes from the resource object + // This also completes the associations by adding shadowRefs + PrismObject assembledShadow = completeShadow(shadowCtx, resourceObject, repositoryShadow, false, parentResult); + LOGGER.trace("Shadow when assembled:\n{}", assembledShadow.debugDumpLazily(1)); + + PrismObject resultShadow = futurizeShadow(ctx, repositoryShadow, assembledShadow, options, now); + LOGGER.trace("Futurized assembled shadow:\n{}", resultShadow.debugDumpLazily(1)); + + parentResult.recordSuccess(); + validateShadow(resultShadow, true); + return resultShadow; + + } catch (Exception ex) { + try { + PrismObject handledShadow = handleGetError(ctx, repositoryShadow, rootOptions, ex, task, parentResult); + if (handledShadow == null) { + throw ex; + } + if (parentResult.getStatus() == OperationResultStatus.FATAL_ERROR) { + // We are going to return an object. Therefore this cannot + // be fatal error, as at least some information + // is returned + parentResult.setStatus(OperationResultStatus.PARTIAL_ERROR); + } + PrismObject futurizedShadow = futurizeShadow(ctx, handledShadow, null, options, now); + validateShadow(futurizedShadow, true); + return futurizedShadow; + + } catch (GenericFrameworkException | ObjectAlreadyExistsException | PolicyViolationException e) { + throw new SystemException(e.getMessage(), e); + } + } finally { + // We need to record the fetch down here. Now it is certain that we + // are going to fetch from resource (we do not have raw/noFetch option) + InternalMonitor.recordCount(InternalCounters.SHADOW_FETCH_OPERATION_COUNT); + } + } + + private ProvisioningOperationOptions toProvisioningOperationOptions(GetOperationOptions getOpts) { + if (getOpts == null) { + return null; + } + + ProvisioningOperationOptions provisioningOpts = new ProvisioningOperationOptions(); + // for now, we are interested in forceRetry option. In the future, there can be more. + provisioningOpts.setForceRetry(getOpts.getForceRetry()); + return provisioningOpts; + } + + private boolean shouldRefreshOnRead(ResourceType resource, GetOperationOptions rootOptions) { + return GetOperationOptions.isForceRefresh(rootOptions) || GetOperationOptions.isForceRetry(rootOptions) || ResourceTypeUtil.isRefreshOnRead(resource); + } + + private PrismObject processNoFetchGet(ProvisioningContext ctx, + PrismObject repositoryShadow, Collection> options, + XMLGregorianCalendar now, Task task, OperationResult parentResult) + throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException, EncryptionException { + LOGGER.trace("Processing noFetch get for {}", repositoryShadow); + + GetOperationOptions rootOptions = SelectorOptions.findRootOptions(options); + if (!GetOperationOptions.isRaw(rootOptions)) { + // Even with noFetch we still want to delete expired pending operations. And even delete + // the shadow if needed. + repositoryShadow = refreshShadowQuick(ctx, repositoryShadow, now, task, parentResult); + } + + if (repositoryShadow == null) { + ObjectNotFoundException e = new ObjectNotFoundException("Resource object not found"); + parentResult.recordFatalError(e); + throw e; + } + + PrismObject resultShadow = futurizeShadow(ctx, repositoryShadow, null, options, now); + shadowCaretaker.applyAttributesDefinition(ctx, resultShadow); + + return resultShadow; + } + + private PrismObject futurizeShadow(ProvisioningContext ctx, PrismObject repoShadow, PrismObject resourceShadow, + Collection> options, XMLGregorianCalendar now) throws SchemaException, ConfigurationException, ObjectNotFoundException, CommunicationException, ExpressionEvaluationException { + if (!ProvisioningUtil.isFuturePointInTime(options)) { + if (resourceShadow == null) { + return repoShadow; + } else { + return resourceShadow; + } + } + return shadowCaretaker.applyPendingOperations(ctx, repoShadow, resourceShadow, false, now); + } + + private boolean canReturnCachedAfterObjectNotFound(Collection> options, + PrismObject repositoryShadow, ResourceType resource) { + if (repositoryShadow.asObjectable().getPendingOperation().isEmpty()) { + return false; + } + // TODO: which case is this exactly? + // Explicitly check the capability of the resource (primary connector), not capabilities of additional connectors + return ProvisioningUtil.isPrimaryCachingOnly(resource); + } + + private boolean canImmediatelyReturnCached(Collection> options, PrismObject repositoryShadow, ShadowState shadowState, ResourceType resource) throws ConfigurationException { + if (ProvisioningUtil.resourceReadIsCachingOnly(resource)) { + return true; + } + if (shadowState == ShadowState.TOMBSTONE) { + // Once shadow is buried it stays nine feet under. Therefore there is no point in trying to access the resource. + // NOTE: this is just for tombstone! Schroedinger's shadows (corpse) will still work as if they were alive. + return true; + } + long stalenessOption = GetOperationOptions.getStaleness(SelectorOptions.findRootOptions(options)); + PointInTimeType pit = GetOperationOptions.getPointInTimeType(SelectorOptions.findRootOptions(options)); + if (pit == null) { + if (stalenessOption > 0) { + pit = PointInTimeType.CACHED; + } else { + pit = PointInTimeType.CURRENT; + } + } + switch (pit) { + case CURRENT: + // We need current reliable state. Never return cached data. + return false; + case CACHED: + return isCachedShadowValid(options, repositoryShadow, resource); + case FUTURE: + // We could, e.g. if there is a pending create operation. But let's try real get operation first. + return false; + default: + throw new IllegalArgumentException("Unknown point in time: "+pit); + } + } + + private boolean isCachedShadowValid(Collection> options, PrismObject repositoryShadow, ResourceType resource) throws ConfigurationException { + long stalenessOption = GetOperationOptions.getStaleness(SelectorOptions.findRootOptions(options)); + if (stalenessOption == 0L) { + return false; + } + CachingMetadataType cachingMetadata = repositoryShadow.asObjectable().getCachingMetadata(); + if (cachingMetadata == null) { + if (stalenessOption == Long.MAX_VALUE) { + // We must return cached version but there is no cached version. + throw new ConfigurationException("Cached version of "+repositoryShadow+" requested, but there is no cached value"); + } + return false; + } + if (stalenessOption == Long.MAX_VALUE) { + return true; + } + + XMLGregorianCalendar retrievalTimestamp = cachingMetadata.getRetrievalTimestamp(); + if (retrievalTimestamp == null) { + return false; + } + long retrievalTimestampMillis = XmlTypeConverter.toMillis(retrievalTimestamp); + return (clock.currentTimeMillis() - retrievalTimestampMillis < stalenessOption); + } + + private boolean isCompensate(GetOperationOptions rootOptions) { + return !GetOperationOptions.isDoNotDiscovery(rootOptions); + } + + public String addShadow(PrismObject shadowToAdd, OperationProvisioningScriptsType scripts, + ResourceType resource, ProvisioningOperationOptions options, Task task, + OperationResult parentResult) throws CommunicationException, GenericFrameworkException, + ObjectAlreadyExistsException, SchemaException, ObjectNotFoundException, + ConfigurationException, SecurityViolationException, PolicyViolationException, ExpressionEvaluationException, EncryptionException { + Validate.notNull(shadowToAdd, "Object to add must not be null."); + + InternalMonitor.recordCount(InternalCounters.SHADOW_CHANGE_OPERATION_COUNT); + + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("Start adding shadow object{}:\n{}", getAdditionalOperationDesc(scripts, options), shadowToAdd.debugDump(1)); + } + + ProvisioningContext ctx = ctxFactory.create(shadowToAdd, task, parentResult); + try { + ctx.assertDefinition(); + } catch (SchemaException e) { + parentResult.recordFatalError(e); + ResourceOperationDescription operationDescription = ProvisioningUtil.createResourceFailureDescription( + shadowToAdd, ctx.getResource(), shadowToAdd.createAddDelta(), parentResult); + operationListener.notifyFailure(operationDescription, task, parentResult); + throw e; + } + + ProvisioningOperationState>> opState = new ProvisioningOperationState<>(); + + return addShadowAttempt(ctx, shadowToAdd, scripts, opState, options, task, parentResult); + } + + private String addShadowAttempt(ProvisioningContext ctx, + PrismObject shadowToAdd, + OperationProvisioningScriptsType scripts, + ProvisioningOperationState>> opState, + ProvisioningOperationOptions options, + Task task, + OperationResult parentResult) + throws CommunicationException, GenericFrameworkException, + ObjectAlreadyExistsException, SchemaException, ObjectNotFoundException, + ConfigurationException, SecurityViolationException, PolicyViolationException, ExpressionEvaluationException, EncryptionException { + + PrismContainer attributesContainer = shadowToAdd.findContainer(ShadowType.F_ATTRIBUTES); + if (attributesContainer == null || attributesContainer.isEmpty()) { + SchemaException e = new SchemaException("Attempt to add shadow without any attributes: " + shadowToAdd); + parentResult.recordFatalError(e); + ResourceOperationDescription operationDescription = ProvisioningUtil.createResourceFailureDescription( + shadowToAdd, ctx.getResource(), shadowToAdd.createAddDelta(), parentResult); + operationListener.notifyFailure(operationDescription, task, parentResult); + throw e; + } + if (!(attributesContainer instanceof ResourceAttributeContainer)) { + shadowCaretaker.applyAttributesDefinition(ctx, shadowToAdd); + attributesContainer = shadowToAdd.findContainer(ShadowType.F_ATTRIBUTES); + } + +// if (opState.getRepoShadow() != null) { +// // HACK HACK HACK, not really right solution. +// // We need this for reliable uniqueness check in preAddChecks() and addResourceObject() +// // Maybe the right solution would be to pass opState as a parameter to addResourceObject()? +// // Or maybe addResourceObject() should not check uniqueness and we should check it here? +// shadowToAdd.setOid(opState.getRepoShadow().getOid()); +// } + + preAddChecks(ctx, shadowToAdd, opState, task, parentResult); + + shadowManager.addNewProposedShadow(ctx, shadowToAdd, opState, task, parentResult); + + preprocessEntitlements(ctx, shadowToAdd, parentResult); + + shadowCaretaker.applyAttributesDefinition(ctx, shadowToAdd); + shadowManager.setKindIfNecessary(shadowToAdd.asObjectable(), ctx.getObjectClassDefinition()); + accessChecker.checkAdd(ctx, shadowToAdd, parentResult); + PrismObject addedShadow = null; + OperationResultStatus finalOperationStatus = null; + + if (shouldExecuteResourceOperationDirectly(ctx)) { + + ConnectorOperationOptions connOptions = createConnectorOperationOptions(ctx, options, parentResult); + + LOGGER.trace("ADD {}: resource operation, execution starting", shadowToAdd); + + try { + + // RESOURCE OPERATION: add + AsynchronousOperationReturnValue> asyncReturnValue = + resourceObjectConverter.addResourceObject(ctx, shadowToAdd, scripts, connOptions, false, parentResult); + opState.processAsyncResult(asyncReturnValue); + addedShadow = asyncReturnValue.getReturnValue(); + + } catch (ObjectAlreadyExistsException e) { + + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("Object already exists error when trying to add {}, exploring the situation", ShadowUtil.shortDumpShadow(shadowToAdd)); + } + + // This exception may still be OK in some cases. Such as: + // We are trying to add a shadow to a semi-manual connector. + // But the resource object was recently deleted. The object is + // still in the backing store (CSV file) because of a grace + // period. Obviously, attempt to add such object would fail. + // So, we need to handle this case specially. (MID-4414) + + OperationResult failedOperationResult = parentResult.getLastSubresult(); + + if (hasDeadShadowWithDeleteOperation(ctx, shadowToAdd, parentResult)) { + + if (failedOperationResult.isError()) { + failedOperationResult.setStatus(OperationResultStatus.HANDLED_ERROR); + } + + // Try again, this time without explicit uniqueness check + try { + + LOGGER.trace("ADD {}: retrying resource operation without uniqueness check (previous dead shadow found), execution starting", shadowToAdd); + AsynchronousOperationReturnValue> asyncReturnValue = + resourceObjectConverter + .addResourceObject(ctx, shadowToAdd, scripts, connOptions, true, parentResult); + opState.processAsyncResult(asyncReturnValue); + addedShadow = asyncReturnValue.getReturnValue(); + + } catch (ObjectAlreadyExistsException innerException) { + // Mark shadow dead before we handle the error. ADD operation obviously failed. Therefore this particular + // shadow was not created as resource object. It is dead on the spot. Make sure that error handler won't confuse + // this shadow with the conflicting shadow that it is going to discover. + // This may also be a gestation quantum state collapsing to tombstone + shadowManager.markShadowTombstone(opState.getRepoShadow(), parentResult); + finalOperationStatus = handleAddError(ctx, shadowToAdd, options, opState, innerException, failedOperationResult, task, parentResult); + } catch (Exception innerException) { + finalOperationStatus = handleAddError(ctx, shadowToAdd, options, opState, innerException, parentResult.getLastSubresult(), task, parentResult); + } + + } else { + // Mark shadow dead before we handle the error. ADD operation obviously failed. Therefore this particular + // shadow was not created as resource object. It is dead on the spot. Make sure that error handler won't confuse + // this shadow with the conflicting shadow that it is going to discover. + // This may also be a gestation quantum state collapsing to tombstone + shadowManager.markShadowTombstone(opState.getRepoShadow(), parentResult); + finalOperationStatus = handleAddError(ctx, shadowToAdd, options, opState, e, failedOperationResult, task, parentResult); + } + + } catch (Exception e) { + finalOperationStatus = handleAddError(ctx, shadowToAdd, options, opState, e, parentResult.getLastSubresult(), task, parentResult); + } + + LOGGER.debug("ADD {}: resource operation executed, operation state: {}", shadowToAdd, opState.shortDumpLazily()); + + } else { + opState.setExecutionStatus(PendingOperationExecutionStatusType.EXECUTION_PENDING); + // Create dummy subresult with IN_PROGRESS state. + // This will force the entire result (parent) to be IN_PROGRESS rather than SUCCESS. + OperationResult delayedSubresult = parentResult.createSubresult(OP_DELAYED_OPERATION); + delayedSubresult.setStatus(OperationResultStatus.IN_PROGRESS); + LOGGER.debug("ADD {}: resource operation NOT executed, execution pending", shadowToAdd); + } + + // REPO OPERATION: add + // This is where the repo shadow is created or updated (if needed) + shadowManager.recordAddResult(ctx, shadowToAdd, opState, parentResult); + + if (addedShadow == null) { + addedShadow = shadowToAdd; + } + addedShadow.setOid(opState.getRepoShadow().getOid()); + + notifyAfterAdd(ctx, addedShadow, opState, task, parentResult); + + setParentOperationStatus(parentResult, opState, finalOperationStatus); + + return opState.getRepoShadow().getOid(); + } + + private void setParentOperationStatus(OperationResult parentResult, + ProvisioningOperationState opState, + OperationResultStatus finalOperationStatus) { + if (finalOperationStatus != null) { + parentResult.setStatus(finalOperationStatus); + } else { + if (opState.isCompleted()) { + parentResult.computeStatus(); + } else { + parentResult.recordInProgress(); + } + } + parentResult.setAsynchronousOperationReference(opState.getAsynchronousOperationReference()); + } + + private boolean hasDeadShadowWithDeleteOperation(ProvisioningContext ctx, + PrismObject shadowToAdd, + OperationResult parentResult) + throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, ExpressionEvaluationException { + + + Collection> previousDeadShadows = shadowManager.lookForPreviousDeadShadows(ctx, shadowToAdd, parentResult); + if (previousDeadShadows.isEmpty()) { + return false; + } + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("Previous dead shadows:\n{}", DebugUtil.debugDump(previousDeadShadows, 1)); + } + + XMLGregorianCalendar now = clock.currentTimeXMLGregorianCalendar(); + for (PrismObject previousDeadShadow : previousDeadShadows) { + if (shadowCaretaker.findPreviousPendingLifecycleOperationInGracePeriod(ctx, previousDeadShadow, now) == ChangeTypeType.DELETE) { + return true; + } + } + return false; + } + + private PrismObject handleGetError(ProvisioningContext ctx, + PrismObject repositoryShadow, + GetOperationOptions rootOptions, + Exception cause, + Task task, + OperationResult parentResult) throws SchemaException, GenericFrameworkException, CommunicationException, ObjectNotFoundException, ObjectAlreadyExistsException, ConfigurationException, SecurityViolationException, PolicyViolationException, ExpressionEvaluationException { + ErrorHandler handler = errorHandlerLocator.locateErrorHandler(cause); + if (handler == null) { + parentResult.recordFatalError("Error without a handler: " + cause.getMessage(), cause); + throw new SystemException(cause.getMessage(), cause); + } + LOGGER.debug("Handling provisioning GET exception {}: {}", cause.getClass(), cause.getMessage()); + return handler.handleGetError(ctx, repositoryShadow, rootOptions, cause, task, parentResult); + } + + private OperationResultStatus handleAddError(ProvisioningContext ctx, + PrismObject shadowToAdd, + ProvisioningOperationOptions options, + ProvisioningOperationState>> opState, + Exception cause, + OperationResult failedOperationResult, + Task task, + OperationResult parentResult) + throws SchemaException, GenericFrameworkException, CommunicationException, ObjectNotFoundException, ObjectAlreadyExistsException, ConfigurationException, SecurityViolationException, PolicyViolationException, ExpressionEvaluationException { + + // TODO: record operationExecution + + ErrorHandler handler = errorHandlerLocator.locateErrorHandler(cause); + if (handler == null) { + parentResult.recordFatalError("Error without a handler: " + cause.getMessage(), cause); + throw new SystemException(cause.getMessage(), cause); + } + LOGGER.debug("Handling provisioning ADD exception {}: {}", cause.getClass(), cause.getMessage()); + try { + + OperationResultStatus finalStatus = handler.handleAddError(ctx, shadowToAdd, options, opState, cause, failedOperationResult, task, parentResult); + LOGGER.debug("Handled provisioning ADD exception, final status: {}, operation state: {}", finalStatus, opState.shortDumpLazily()); + return finalStatus; + + } catch (CommonException e) { + LOGGER.debug("Handled provisioning ADD exception, final exception: {}, operation state: {}", e, opState.shortDumpLazily()); + ObjectDelta delta = shadowToAdd.createAddDelta(); + handleErrorHandlerException(ctx, opState, delta, task, parentResult); + throw e; + } + + } + + private void handleErrorHandlerException(ProvisioningContext ctx, + ProvisioningOperationState opState, + ObjectDelta delta, + Task task, OperationResult parentResult) throws SchemaException, ConfigurationException, ObjectNotFoundException, CommunicationException, ObjectAlreadyExistsException, ExpressionEvaluationException { + // Error handler had re-thrown the exception. We will throw the exception later. But first we need to record changes in opState. + shadowManager.recordOperationException(ctx, opState, delta, parentResult); + + PrismObject shadow = opState.getRepoShadow(); + if (delta.isAdd()) { + // This is more precise. Besides, there is no repo shadow in some cases (e.g. adding protected shadow). + shadow = delta.getObjectToAdd(); + } + ResourceOperationDescription operationDescription = ProvisioningUtil.createResourceFailureDescription(shadow, ctx.getResource(), delta, parentResult); + operationListener.notifyFailure(operationDescription, task, parentResult); + } + + private OperationResultStatus handleModifyError(ProvisioningContext ctx, + PrismObject repoShadow, + Collection modifications, + ProvisioningOperationOptions options, + ProvisioningOperationState>>> opState, + Exception cause, + OperationResult failedOperationResult, + Task task, + OperationResult parentResult) + throws SchemaException, GenericFrameworkException, CommunicationException, ObjectNotFoundException, ObjectAlreadyExistsException, ConfigurationException, SecurityViolationException, PolicyViolationException, ExpressionEvaluationException { + + // TODO: record operationExecution + + ErrorHandler handler = errorHandlerLocator.locateErrorHandler(cause); + if (handler == null) { + parentResult.recordFatalError("Error without a handler: " + cause.getMessage(), cause); + throw new SystemException(cause.getMessage(), cause); + } + LOGGER.debug("Handling provisioning MODIFY exception {}: {}", cause.getClass(), cause.getMessage()); + try { + + OperationResultStatus finalStatus = handler.handleModifyError(ctx, repoShadow, modifications, options, opState, cause, failedOperationResult, task, parentResult); + LOGGER.debug("Handled provisioning MODIFY exception, final status: {}, operation state: {}", finalStatus, opState.shortDumpLazily()); + return finalStatus; + + } catch (CommonException e) { + LOGGER.debug("Handled provisioning MODIFY exception, final exception: {}, operation state: {}", e, opState.shortDumpLazily()); + ObjectDelta delta = repoShadow.createModifyDelta(); + delta.addModifications(modifications); + handleErrorHandlerException(ctx, opState, delta, task, parentResult); + throw e; + } + } + + private OperationResultStatus handleDeleteError(ProvisioningContext ctx, + PrismObject repoShadow, + ProvisioningOperationOptions options, + ProvisioningOperationState opState, + Exception cause, + OperationResult failedOperationResult, + Task task, + OperationResult parentResult) + throws SchemaException, GenericFrameworkException, CommunicationException, ObjectNotFoundException, ObjectAlreadyExistsException, ConfigurationException, SecurityViolationException, PolicyViolationException, ExpressionEvaluationException { + + ErrorHandler handler = errorHandlerLocator.locateErrorHandler(cause); + if (handler == null) { + parentResult.recordFatalError("Error without a handler: " + cause.getMessage(), cause); + throw new SystemException(cause.getMessage(), cause); + } + LOGGER.debug("Handling provisioning DELETE exception {}: {}", cause.getClass(), cause.getMessage()); + try { + + OperationResultStatus finalStatus = handler.handleDeleteError(ctx, repoShadow, options, opState, cause, failedOperationResult, task, parentResult); + LOGGER.debug("Handled provisioning DELETE exception, final status: {}, operation state: {}", finalStatus, opState.shortDumpLazily()); + return finalStatus; + + } catch (CommonException e) { + LOGGER.debug("Handled provisioning DELETE exception, final exception: {}, operation state: {}", e, opState.shortDumpLazily()); + ObjectDelta delta = repoShadow.createDeleteDelta(); + handleErrorHandlerException(ctx, opState, delta, task, parentResult); + throw e; + } + + } + + private void notifyAfterAdd( + ProvisioningContext ctx, + PrismObject addedShadow, + ProvisioningOperationState>> opState, + Task task, + OperationResult parentResult) + throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException { + ObjectDelta delta = DeltaFactory.Object.createAddDelta(addedShadow); + ResourceOperationDescription operationDescription = createSuccessOperationDescription(ctx, addedShadow, + delta, parentResult); + + if (opState.isExecuting()) { + operationListener.notifyInProgress(operationDescription, task, parentResult); + } else if (opState.isCompleted()) { + operationListener.notifySuccess(operationDescription, task, parentResult); + } + } + + private void preAddChecks(ProvisioningContext ctx, PrismObject shadow, ProvisioningOperationState>> opState, Task task, OperationResult result) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException, ObjectAlreadyExistsException, SecurityViolationException { + checkConstraints(ctx, shadow, opState, task, result); + validateSchema(ctx, shadow, task, result); + } + + private void checkConstraints(ProvisioningContext ctx, PrismObject shadow, ProvisioningOperationState>> opState, Task task, OperationResult result) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException, ObjectAlreadyExistsException, SecurityViolationException { + ShadowCheckType shadowConstraintsCheck = ResourceTypeUtil.getShadowConstraintsCheck(ctx.getResource()); + if (shadowConstraintsCheck == ShadowCheckType.NONE) { + return; + } + + String shadowOid = shadow.getOid(); + if (opState.getRepoShadow() != null) { + shadowOid = opState.getRepoShadow().getOid(); + } + + ConstraintsChecker checker = new ConstraintsChecker(); + checker.setRepositoryService(repositoryService); + checker.setCacheConfigurationManager(cacheConfigurationManager); + checker.setShadowCache(this); + checker.setPrismContext(prismContext); + checker.setProvisioningContext(ctx); + checker.setShadowObject(shadow); + checker.setShadowOid(shadowOid); + checker.setConstraintViolationConfirmer(conflictingShadowCandidate -> !Boolean.TRUE.equals(conflictingShadowCandidate.asObjectable().isDead()) ); + checker.setUseCache(false); + + ConstraintsCheckingResult retval = checker.check(task, result); + + LOGGER.trace("Checked {} constraints, result={}", shadow.debugDump(), retval.isSatisfiesConstraints()); + if (!retval.isSatisfiesConstraints()) { + throw new ObjectAlreadyExistsException("Conflicting shadow already exists on "+ctx.getResource()); + } + } + + private void validateSchema(ProvisioningContext ctx, PrismObject shadow, Task task, OperationResult result) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException { + if (ResourceTypeUtil.isValidateSchema(ctx.getResource())) { + ShadowUtil.validateAttributeSchema(shadow, ctx.getObjectClassDefinition()); + } + } + + private boolean shouldExecuteResourceOperationDirectly(ProvisioningContext ctx) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException { + if (ctx.isPropagation()) { + return true; + } + ResourceConsistencyType consistency = ctx.getResource().getConsistency(); + if (consistency == null) { + return true; + } + Duration operationGroupingInterval = consistency.getOperationGroupingInterval(); + if (operationGroupingInterval == null) { + return true; + } + return false; + } + + private ResourceOperationDescription createSuccessOperationDescription(ProvisioningContext ctx, + PrismObject shadowType, ObjectDelta delta, OperationResult parentResult) + throws ObjectNotFoundException, SchemaException, CommunicationException, + ConfigurationException, ExpressionEvaluationException { + ResourceOperationDescription operationDescription = new ResourceOperationDescription(); + operationDescription.setCurrentShadow(shadowType); + operationDescription.setResource(ctx.getResource().asPrismObject()); + if (ctx.getTask() != null) { + operationDescription.setSourceChannel(ctx.getTask().getChannel()); + } + operationDescription.setObjectDelta(delta); + operationDescription.setResult(parentResult); + return operationDescription; + } + + public String modifyShadow(PrismObject repoShadow, + Collection modifications, OperationProvisioningScriptsType scripts, + ProvisioningOperationOptions options, Task task, OperationResult parentResult) + throws CommunicationException, GenericFrameworkException, ObjectNotFoundException, + SchemaException, ConfigurationException, SecurityViolationException, PolicyViolationException, ExpressionEvaluationException, EncryptionException, ObjectAlreadyExistsException { + + Validate.notNull(repoShadow, "Object to modify must not be null."); + Validate.notNull(modifications, "Object modification must not be null."); + + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("Start modifying {}{}:\n{}", repoShadow, getAdditionalOperationDesc(scripts, options), + DebugUtil.debugDump(modifications, 1)); + } + + InternalMonitor.recordCount(InternalCounters.SHADOW_CHANGE_OPERATION_COUNT); + + Collection additionalAuxiliaryObjectClassQNames = new ArrayList<>(); + for (ItemDelta modification : modifications) { + if (ShadowType.F_AUXILIARY_OBJECT_CLASS.equivalent(modification.getPath())) { + PropertyDelta auxDelta = (PropertyDelta) modification; + for (PrismPropertyValue pval : auxDelta.getValues(QName.class)) { + additionalAuxiliaryObjectClassQNames.add(pval.getValue()); + } + } + } + + ProvisioningContext ctx = ctxFactory.create(repoShadow, additionalAuxiliaryObjectClassQNames, task, parentResult); + ctx.assertDefinition(); + + ProvisioningOperationState>>> opState = new ProvisioningOperationState<>(); + opState.setRepoShadow(repoShadow); + + // if not explicitly we want to force retry operations during modify + // it is quite cheap and probably more safe then not do it + if (options == null) { + options = ProvisioningOperationOptions.createForceRetry(Boolean.TRUE); + } else if (options.getForceRetry() == null) { + options.setForceRetry(Boolean.TRUE); + } + + return modifyShadowAttempt(ctx, modifications, scripts, options, opState, task, parentResult); + } + + private String modifyShadowAttempt(ProvisioningContext ctx, + Collection modifications, + OperationProvisioningScriptsType scripts, + ProvisioningOperationOptions options, + ProvisioningOperationState>>> opState, + Task task, OperationResult parentResult) + throws CommunicationException, GenericFrameworkException, ObjectNotFoundException, + SchemaException, ConfigurationException, SecurityViolationException, PolicyViolationException, ExpressionEvaluationException, EncryptionException, ObjectAlreadyExistsException { + + PrismObject repoShadow = opState.getRepoShadow(); + + XMLGregorianCalendar now = clock.currentTimeXMLGregorianCalendar(); + + PendingOperationType duplicateOperation = shadowManager.checkAndRecordPendingModifyOperationBeforeExecution(ctx, repoShadow, modifications, opState, task, parentResult); + if (duplicateOperation != null) { + parentResult.recordInProgress(); + return repoShadow.getOid(); + } + + shadowCaretaker.applyAttributesDefinition(ctx, repoShadow); + + accessChecker.checkModify(ctx, repoShadow, modifications, parentResult); + + preprocessEntitlements(ctx, modifications, "delta for shadow " + repoShadow.getOid(), parentResult); + + OperationResultStatus finalOperationStatus = null; + + if (shadowManager.isRepositoryOnlyModification(modifications)) { + opState.setExecutionStatus(PendingOperationExecutionStatusType.COMPLETED); + LOGGER.debug("MODIFY {}: repository-only modification", repoShadow); + } else { + if (shouldExecuteResourceOperationDirectly(ctx)) { + LOGGER.trace("MODIFY {}: resource modification, execution starting\n{}", repoShadow, DebugUtil.debugDumpLazily(modifications)); + + RefreshShadowOperation refreshShadowOperation = null; + if (shouldRefresh(repoShadow)) { + refreshShadowOperation = refreshShadow(repoShadow, options, task, parentResult); + } + + if (refreshShadowOperation != null) { + repoShadow = refreshShadowOperation.getRefreshedShadow(); + } + + if (repoShadow == null) { + LOGGER.trace("Shadow is gone. Nothing more to do"); + parentResult.recordPartialError("Shadow disappeared during modify."); + throw new ObjectNotFoundException("Shadow is gone."); + } + + ConnectorOperationOptions connOptions = createConnectorOperationOptions(ctx, options, parentResult); + + try { + + + if (!shouldExecuteModify(refreshShadowOperation)) { + ProvisioningUtil.postponeModify(ctx, repoShadow, modifications, opState, refreshShadowOperation.getRefreshResult(), parentResult); + shadowManager.recordModifyResult(ctx, repoShadow, modifications, opState, now, parentResult); + return repoShadow.getOid(); + } else { + LOGGER.trace("Shadow exists: {}", repoShadow.debugDump()); + } + + AsynchronousOperationReturnValue>> asyncReturnValue = + resourceObjectConverter + .modifyResourceObject(ctx, repoShadow, scripts, connOptions, modifications, now, parentResult); + opState.processAsyncResult(asyncReturnValue); + + Collection> sideEffectChanges = asyncReturnValue.getReturnValue(); + if (sideEffectChanges != null) { + ItemDeltaCollectionsUtil.addAll(modifications, sideEffectChanges); + } + + } catch (Exception ex) { + LOGGER.debug("Provisioning exception: {}:{}, attempting to handle it", + ex.getClass(), ex.getMessage(), ex); + finalOperationStatus = handleModifyError(ctx, repoShadow, modifications, options, opState, ex, parentResult.getLastSubresult(), task, parentResult); + } + + LOGGER.debug("MODIFY {}: resource operation executed, operation state: {}", repoShadow, opState.shortDumpLazily()); + + } else { + opState.setExecutionStatus(PendingOperationExecutionStatusType.EXECUTION_PENDING); + // Create dummy subresult with IN_PROGRESS state. + // This will force the entire result (parent) to be IN_PROGRESS rather than SUCCESS. + OperationResult delayedSubresult = parentResult.createSubresult(OP_DELAYED_OPERATION); + delayedSubresult.setStatus(OperationResultStatus.IN_PROGRESS); + LOGGER.debug("MODIFY {}: Resource operation NOT executed, execution pending", repoShadow); + } + } + + shadowManager.recordModifyResult(ctx, repoShadow, modifications, opState, now, parentResult); + + notifyAfterModify(ctx, repoShadow, modifications, opState, task, parentResult); + + setParentOperationStatus(parentResult, opState, finalOperationStatus); + + return repoShadow.getOid(); + } + + private boolean shouldExecuteModify(RefreshShadowOperation refreshShadowOperation) { + if (refreshShadowOperation == null) { + LOGGER.trace("Nothing refreshed, modify can continue."); + return true; + } + + if (refreshShadowOperation.getExecutedDeltas() == null || refreshShadowOperation.getExecutedDeltas().isEmpty()) { + LOGGER.trace("No executed deltas after refresh. Continue with modify operation."); + return true; + } + + if (refreshShadowOperation.getRefreshedShadow() == null) { + LOGGER.trace("Shadow is gone. Probably it was deleted during refresh. Finishing modify operation now."); + return false; + } + + Collection> objectDeltaOperations = refreshShadowOperation.getExecutedDeltas(); + for (ObjectDeltaOperation shadowDelta : objectDeltaOperations) { + if (!shadowDelta.getExecutionResult().isSuccess()) { + LOGGER.trace("Refresh operation not successful. Finishing modify operation now."); + return false; + } + } + + return true; + } + + private boolean shouldRefresh(PrismObject repoShadow) { + if (repoShadow == null) { + return false; + } + + List pendingOperations = repoShadow.asObjectable().getPendingOperation(); + if (pendingOperations == null || pendingOperations.isEmpty()) { + return false; + } + + for (PendingOperationType pendingOperationType : pendingOperations) { + if (needsRetry(pendingOperationType)) { + return true; + } + } + + return false; + } + + private void notifyAfterModify( + ProvisioningContext ctx, + PrismObject repoShadow, + Collection modifications, + ProvisioningOperationState>>> opState, + Task task, + OperationResult parentResult) + throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException { + + ObjectDelta delta = prismContext.deltaFactory().object().createModifyDelta(repoShadow.getOid(), modifications, + repoShadow.getCompileTimeClass()); + ResourceOperationDescription operationDescription = createSuccessOperationDescription(ctx, repoShadow, + delta, parentResult); + + if (opState.isExecuting()) { + operationListener.notifyInProgress(operationDescription, task, parentResult); + } else { + operationListener.notifySuccess(operationDescription, task, parentResult); + } + } + + /** + * Used to execute delayed operations. + * Mostly copy&paste from modifyShadow(). But as consistency (handleError()) branch expects to return immediately + * I could not find a more elegant way to structure this without complicating the code too much. + */ + private ProvisioningOperationState>>> executeResourceModify( + ProvisioningContext ctx, + PrismObject repoShadow, + Collection modifications, + OperationProvisioningScriptsType scripts, + ProvisioningOperationOptions options, + XMLGregorianCalendar now, + Task task, + OperationResult parentResult) + throws SchemaException, GenericFrameworkException, CommunicationException, ObjectNotFoundException, + ConfigurationException, SecurityViolationException, PolicyViolationException, ExpressionEvaluationException { + ProvisioningOperationState>>> opState = new ProvisioningOperationState<>(); + opState.setRepoShadow(repoShadow); + + ConnectorOperationOptions connOptions = createConnectorOperationOptions(ctx, options, parentResult); + + try { + + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("Applying change: {}", DebugUtil.debugDump(modifications)); + } + + AsynchronousOperationReturnValue>> asyncReturnValue = + resourceObjectConverter + .modifyResourceObject(ctx, repoShadow, scripts, connOptions, modifications, now, parentResult); + opState.processAsyncResult(asyncReturnValue); + + Collection> sideEffectChanges = asyncReturnValue.getReturnValue(); + if (sideEffectChanges != null) { + ItemDeltaCollectionsUtil.addAll(modifications, sideEffectChanges); + } + + } catch (Exception ex) { + LOGGER.debug("Provisioning exception: {}:{}, attempting to handle it", + ex.getClass(), ex.getMessage(), ex); + try { + handleModifyError(ctx, repoShadow, modifications, options, opState, ex, parentResult.getLastSubresult(), task, parentResult); + parentResult.computeStatus(); + } catch (ObjectAlreadyExistsException e) { + parentResult.recordFatalError( + "While compensating communication problem for modify operation got: " + + ex.getMessage(), + ex); + throw new SystemException(e); + } + + } + + return opState; + } + + public PrismObject deleteShadow(PrismObject repoShadow, ProvisioningOperationOptions options, + OperationProvisioningScriptsType scripts, Task task, OperationResult parentResult) + throws CommunicationException, GenericFrameworkException, ObjectNotFoundException, + SchemaException, ConfigurationException, SecurityViolationException, PolicyViolationException, ExpressionEvaluationException { + + Validate.notNull(repoShadow, "Object to delete must not be null."); + Validate.notNull(parentResult, "Operation result must not be null."); + + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("Start deleting {}{}", repoShadow, getAdditionalOperationDesc(scripts, options)); + } + + InternalMonitor.recordCount(InternalCounters.SHADOW_CHANGE_OPERATION_COUNT); + + ProvisioningContext ctx = ctxFactory.create(repoShadow, task, parentResult); + try { + ctx.assertDefinition(); + } catch (ObjectNotFoundException ex) { + // if the force option is set, delete shadow from the repo + // although the resource does not exists.. + if (ProvisioningOperationOptions.isForce(options)) { + parentResult.muteLastSubresultError(); + shadowManager.deleteShadow(ctx, repoShadow, parentResult); + parentResult.recordHandledError( + "Resource defined in shadow does not exists. Shadow was deleted from the repository."); + return null; + } else { + throw ex; + } + } + + repoShadow = cancelAllPendingOperations(ctx, repoShadow, task, parentResult); + + ProvisioningOperationState opState = new ProvisioningOperationState<>(); + opState.setRepoShadow(repoShadow); + + return deleteShadowAttempt(ctx, options, scripts, opState, task, parentResult); + } + + + private PrismObject deleteShadowAttempt(ProvisioningContext ctx, + ProvisioningOperationOptions options, + OperationProvisioningScriptsType scripts, + ProvisioningOperationState opState, + Task task, + OperationResult parentResult) + throws CommunicationException, GenericFrameworkException, ObjectNotFoundException, + SchemaException, ConfigurationException, SecurityViolationException, PolicyViolationException, ExpressionEvaluationException { + + PrismObject repoShadow = opState.getRepoShadow(); + shadowCaretaker.applyAttributesDefinition(ctx, repoShadow); + + PendingOperationType duplicateOperation = shadowManager.checkAndRecordPendingDeleteOperationBeforeExecution(ctx, repoShadow, opState, task, parentResult); + if (duplicateOperation != null) { + parentResult.recordInProgress(); + return repoShadow; + } + + XMLGregorianCalendar now = clock.currentTimeXMLGregorianCalendar(); + ShadowState shadowState = shadowCaretaker.determineShadowState(ctx, repoShadow, now); + + LOGGER.trace("Deleting object {} from {}, options={}, shadowState={}", repoShadow, ctx.getResource(), options, shadowState); + OperationResultStatus finalOperationStatus = null; + + if (shouldExecuteResourceOperationDirectly(ctx)) { + + if (shadowState == ShadowState.TOMBSTONE) { + + // Do not even try to delete resource object for tombstone shadows. + // There may be dead shadow and live shadow for the resource object with the same identifiers. + // If we try to delete dead shadow then we might delete existing object by mistake + LOGGER.trace("DELETE {}: skipping resource deletion on tombstone shadow", repoShadow); + + opState.setExecutionStatus(PendingOperationExecutionStatusType.COMPLETED); + OperationResult delayedSubresult = parentResult.createSubresult(OP_RESOURCE_OPERATION); + delayedSubresult.setStatus(OperationResultStatus.NOT_APPLICABLE); + + } else { + + ConnectorOperationOptions connOptions = createConnectorOperationOptions(ctx, options, parentResult); + + LOGGER.trace("DELETE {}: resource deletion, execution starting", repoShadow); + + try { + + AsynchronousOperationResult asyncReturnValue = resourceObjectConverter + .deleteResourceObject(ctx, repoShadow, scripts, connOptions, parentResult); + opState.processAsyncResult(asyncReturnValue); + + String operationCtx = "deleting " + repoShadow + " finished successfully."; + resourceManager.modifyResourceAvailabilityStatus(ctx.getResourceOid(), AvailabilityStatusType.UP, operationCtx, task, parentResult, false); + + } catch (Exception ex) { + try { + finalOperationStatus = handleDeleteError(ctx, repoShadow, options, opState, ex, parentResult.getLastSubresult(), task, parentResult); + } catch (ObjectAlreadyExistsException e) { + parentResult.recordFatalError(e); + throw new SystemException(e.getMessage(), e); + } + } + + LOGGER.debug("DELETE {}: resource operation executed, operation state: {}", repoShadow, opState.shortDumpLazily()); + } + + } else { + opState.setExecutionStatus(PendingOperationExecutionStatusType.EXECUTION_PENDING); + // Create dummy subresult with IN_PROGRESS state. + // This will force the entire result (parent) to be IN_PROGRESS rather than SUCCESS. + OperationResult delayedSubresult = parentResult.createSubresult(OP_DELAYED_OPERATION); + delayedSubresult.setStatus(OperationResultStatus.IN_PROGRESS); + LOGGER.debug("DELETE {}: resource operation NOT executed, execution pending", repoShadow); + } + + now = clock.currentTimeXMLGregorianCalendar(); + + PrismObject resultShadow; + try { + resultShadow = shadowManager.recordDeleteResult(ctx, repoShadow, opState, options, now, parentResult); + } catch (ObjectNotFoundException ex) { + parentResult.recordFatalError("Can't delete object " + repoShadow + ". Reason: " + ex.getMessage(), + ex); + throw new ObjectNotFoundException("An error occured while deleting resource object " + repoShadow + + "whith identifiers " + repoShadow + ": " + ex.getMessage(), ex); + } catch (EncryptionException e) { + throw new SystemException(e.getMessage(), e); + } + + notifyAfterDelete(ctx, repoShadow, opState, task, parentResult); + + setParentOperationStatus(parentResult, opState, finalOperationStatus); + + LOGGER.trace("Delete operation for {} finished, result shadow: {}", repoShadow, resultShadow); + return resultShadow; + } + + private ProvisioningOperationState executeResourceDelete( + ProvisioningContext ctx, + PrismObject shadow, + OperationProvisioningScriptsType scripts, + ProvisioningOperationOptions options, + Task task, + OperationResult parentResult) throws SchemaException, GenericFrameworkException, CommunicationException, ObjectNotFoundException, ConfigurationException, SecurityViolationException, PolicyViolationException, ExpressionEvaluationException { + ProvisioningOperationState opState = new ProvisioningOperationState<>(); + opState.setRepoShadow(shadow); + ConnectorOperationOptions connOptions = createConnectorOperationOptions(ctx, options, parentResult); + try { + + AsynchronousOperationResult asyncReturnValue = resourceObjectConverter + .deleteResourceObject(ctx, shadow, scripts, connOptions , parentResult); + opState.processAsyncResult(asyncReturnValue); + + } catch (Exception ex) { + try { + handleDeleteError(ctx, shadow, options, opState, ex, parentResult.getLastSubresult(), task, parentResult); + } catch (ObjectAlreadyExistsException e) { + parentResult.recordFatalError(e); + throw new SystemException(e.getMessage(), e); + } + } + + return opState; + } + + private void notifyAfterDelete( + ProvisioningContext ctx, + PrismObject shadow, + ProvisioningOperationState opState, + Task task, + OperationResult parentResult) + throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException { + ObjectDelta delta = prismContext.deltaFactory().object().createDeleteDelta(shadow.getCompileTimeClass(), + shadow.getOid()); + ResourceOperationDescription operationDescription = createSuccessOperationDescription(ctx, shadow, + delta, parentResult); + + if (opState.isExecuting()) { + operationListener.notifyInProgress(operationDescription, task, parentResult); + } else { + operationListener.notifySuccess(operationDescription, task, parentResult); + } + } + + + @Nullable + public RefreshShadowOperation refreshShadow(PrismObject repoShadow, ProvisioningOperationOptions options, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException, EncryptionException { + LOGGER.trace("Refreshing {}", repoShadow); + ProvisioningContext ctx = ctxFactory.create(repoShadow, task, parentResult); + ctx.assertDefinition(); + shadowCaretaker.applyAttributesDefinition(ctx, repoShadow); + + repoShadow = shadowManager.refreshProvisioningIndexes(ctx, repoShadow, task, parentResult); + + RefreshShadowOperation refreshShadowOperation = refreshShadowPendingOperations(ctx, repoShadow, options, task, parentResult); + + XMLGregorianCalendar now = clock.currentTimeXMLGregorianCalendar(); + repoShadow = cleanUpDeadShadow(ctx, repoShadow, now, task, parentResult); + if (repoShadow == null) { + refreshShadowOperation.setRefreshedShadow(null); + } + + return refreshShadowOperation; + } + + + + private RefreshShadowOperation refreshShadowPendingOperations(ProvisioningContext ctx, PrismObject repoShadow, ProvisioningOperationOptions options, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException, EncryptionException { + ShadowType shadowType = repoShadow.asObjectable(); + List pendingOperations = shadowType.getPendingOperation(); + boolean isDead = ShadowUtil.isDead(shadowType); + if (!isDead && pendingOperations.isEmpty()) { + LOGGER.trace("Skipping refresh of {} pending operations because shadow is not dead and there are no pending operations", repoShadow); + RefreshShadowOperation rso = new RefreshShadowOperation(); + rso.setRefreshedShadow(repoShadow); + return rso; + } + + LOGGER.trace("Pending operations refresh of {}, dead={}, {} pending operations", repoShadow, isDead, pendingOperations.size()); + + ctx.assertDefinition(); + List sortedOperations = shadowCaretaker.sortPendingOperations(shadowType.getPendingOperation()); + + repoShadow = refreshShadowAsyncStatus(ctx, repoShadow, sortedOperations, task, parentResult); + + RefreshShadowOperation refreshShadowOperation = refreshShadowRetryOperations(ctx, repoShadow, sortedOperations, options, task, parentResult); + + return refreshShadowOperation; + } + + /** + * Used to quickly and efficiently refresh shadow before GET operations. + */ + private PrismObject refreshShadowQuick(ProvisioningContext ctx, + PrismObject repoShadow, + XMLGregorianCalendar now, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException, EncryptionException { + + ObjectDelta shadowDelta = repoShadow.createModifyDelta(); + expirePendingOperations(ctx, repoShadow, shadowDelta, now, parentResult); + + if (!shadowDelta.isEmpty()) { + shadowManager.modifyShadowAttributes(ctx, repoShadow, shadowDelta.getModifications(), parentResult); + shadowDelta.applyTo(repoShadow); + } + + repoShadow = cleanUpDeadShadow(ctx, repoShadow, now, task, parentResult); + + return repoShadow; + } + + /** + * Refresh status of asynchronous operation, e.g. status of manual connector ticket. + * This method will get new status from resouceObjectConverter and it will process the + * status in case that it has changed. + */ + private PrismObject refreshShadowAsyncStatus(ProvisioningContext ctx, PrismObject repoShadow, List sortedOperations, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException, EncryptionException { + Duration gracePeriod = ProvisioningUtil.getGracePeriod(ctx); + + List> notificationDeltas = new ArrayList<>(); + + boolean shadowInception = false; + ObjectDelta shadowDelta = repoShadow.createModifyDelta(); + for (PendingOperationType pendingOperation: sortedOperations) { + + if (!needsRefresh(pendingOperation)) { + continue; + } + + ItemPath containerPath = pendingOperation.asPrismContainerValue().getPath(); + + String asyncRef = pendingOperation.getAsynchronousOperationReference(); + if (asyncRef == null) { + continue; + } + + AsynchronousOperationResult refreshAsyncResult; + try { + refreshAsyncResult = resourceObjectConverter.refreshOperationStatus(ctx, repoShadow, asyncRef, parentResult); + } catch (CommunicationException e) { + LOGGER.debug("Communication error while trying to refresh pending operation of {}. Skipping refresh of this operation.", repoShadow, e); + parentResult.recordPartialError(e); + continue; + } + OperationResultStatus newStatus = refreshAsyncResult.getOperationResult().getStatus(); + + if (newStatus == null) { + continue; + } + OperationResultStatusType newStatusType = newStatus.createStatusType(); + if (newStatusType.equals(pendingOperation.getResultStatus())) { + continue; + } + + + boolean operationCompleted = ProvisioningUtil.isCompleted(newStatusType) && pendingOperation.getCompletionTimestamp() == null; + + if (operationCompleted && gracePeriod == null) { + LOGGER.trace("Deleting pending operation because it is completed (no grace): {}", pendingOperation); + shadowDelta.addModificationDeleteContainer(ShadowType.F_PENDING_OPERATION, pendingOperation.clone()); + + ObjectDeltaType pendingDeltaType = pendingOperation.getDelta(); + ObjectDelta pendingDelta = DeltaConvertor.createObjectDelta(pendingDeltaType, prismContext); + + if (pendingDelta.isAdd()) { + shadowInception = true; + } + + if (pendingDelta.isDelete()) { + shadowInception = false; + shadowManager.addDeadShadowDeltas(repoShadow, refreshAsyncResult, (List)shadowDelta.getModifications()); + } + continue; + + } else { + PropertyDelta resultStatusDelta = shadowDelta.createPropertyModification(containerPath.append(PendingOperationType.F_RESULT_STATUS)); + resultStatusDelta.setRealValuesToReplace(newStatusType); + shadowDelta.addModification(resultStatusDelta); + } + + if (operationCompleted) { + // Operation completed + + PropertyDelta executionStatusDelta = shadowDelta.createPropertyModification(containerPath.append(PendingOperationType.F_EXECUTION_STATUS)); + executionStatusDelta.setRealValuesToReplace(PendingOperationExecutionStatusType.COMPLETED); + shadowDelta.addModification(executionStatusDelta); + + PropertyDelta completionTimestampDelta = shadowDelta.createPropertyModification(containerPath.append(PendingOperationType.F_COMPLETION_TIMESTAMP)); + completionTimestampDelta.setRealValuesToReplace(clock.currentTimeXMLGregorianCalendar()); + shadowDelta.addModification(completionTimestampDelta); + + ObjectDeltaType pendingDeltaType = pendingOperation.getDelta(); + ObjectDelta pendingDelta = DeltaConvertor.createObjectDelta(pendingDeltaType, prismContext); + + if (pendingDelta.isAdd()) { + shadowInception = true; + } + + if (pendingDelta.isModify()) { + + // Apply shadow naming attribute modification + PrismContainer shadowAttributesContainer = repoShadow.findContainer(ItemPath.create(ShadowType.F_ATTRIBUTES)); + ResourceAttributeContainer resourceAttributeContainer = ResourceAttributeContainer.convertFromContainer(shadowAttributesContainer, ctx.getObjectClassDefinition()); + ResourceAttributeContainerDefinition resourceAttrDefinition = resourceAttributeContainer.getDefinition(); + if(resourceAttrDefinition != null) { + + // If naming attribute is present in delta... + ResourceAttributeDefinition namingAttribute = resourceAttrDefinition.getNamingAttribute(); + if (namingAttribute != null) { + if (pendingDelta.hasItemDelta(ItemPath.create(ShadowType.F_ATTRIBUTES, namingAttribute.getItemName()))) { + + // Retrieve a possible changed name per the defined naming attribute for the resource + ItemDelta namingAttributeDelta = pendingDelta.findItemDelta(ItemPath.create(ShadowType.F_ATTRIBUTES, namingAttribute.getItemName())); + Collection valuesToReplace = namingAttributeDelta.getValuesToReplace(); + Optional valueToReplace = valuesToReplace.stream().findFirst(); + + if (valueToReplace.isPresent()){ + Object valueToReplaceObj = ((PrismPropertyValue)valueToReplace.get()).getValue(); + if (valueToReplaceObj instanceof String) { + + // Apply the new naming attribute value to the shadow name by adding the change to the modification set for shadow delta + PropertyDelta nameDelta = shadowDelta.createPropertyModification(ItemPath.create(ShadowType.F_NAME)); + Collection modificationSet = new ArrayList<>(); + PolyString nameAttributeReplacement = new PolyString((String) valueToReplaceObj); + modificationSet.add(nameAttributeReplacement); + nameDelta.setValuesToReplace(PrismValueCollectionsUtil.createCollection(prismContext, modificationSet)); + shadowDelta.addModification(nameDelta); + } + } + } + } + } + + // Apply shadow attribute modifications + for (ItemDelta pendingModification: pendingDelta.getModifications()) { + shadowDelta.addModification(pendingModification.clone()); + } + } + + if (pendingDelta.isDelete()) { + shadowInception = false; + shadowManager.addDeadShadowDeltas(repoShadow, refreshAsyncResult, (List)shadowDelta.getModifications()); + } + + notificationDeltas.add(pendingDelta); + } + + } + + if (shadowInception) { + // We do not need to care about attributes in add deltas here. The add operation is already applied to + // attributes. We need this to "allocate" the identifiers, so iteration mechanism in the + // model can find unique values while taking pending create operations into consideration. + PropertyDelta existsDelta = shadowDelta.createPropertyModification(ShadowType.F_EXISTS); + existsDelta.setRealValuesToReplace(true); + shadowDelta.addModification(existsDelta); + } + + XMLGregorianCalendar now = clock.currentTimeXMLGregorianCalendar(); + expirePendingOperations(ctx, repoShadow, shadowDelta, now, parentResult); + + if (!shadowDelta.isEmpty()) { + shadowCaretaker.applyAttributesDefinition(ctx, shadowDelta); + shadowManager.modifyShadowAttributes(ctx, repoShadow, shadowDelta.getModifications(), parentResult); + } + + for (ObjectDelta notificationDelta: notificationDeltas) { + ResourceOperationDescription operationDescription = createSuccessOperationDescription(ctx, repoShadow, + notificationDelta, parentResult); + operationListener.notifySuccess(operationDescription, task, parentResult); + } + + if (shadowDelta.isEmpty()) { + return repoShadow; + } + shadowDelta.applyTo(repoShadow); + return repoShadow; + } + + private boolean needsRefresh(PendingOperationType pendingOperation) { + PendingOperationExecutionStatusType executionStatus = pendingOperation.getExecutionStatus(); + if (executionStatus == null) { + // LEGACY: 3.7 and earlier + return OperationResultStatusType.IN_PROGRESS.equals(pendingOperation.getResultStatus()); + } else { + return PendingOperationExecutionStatusType.EXECUTING.equals(executionStatus); + } + } + + + private RefreshShadowOperation refreshShadowRetryOperations(ProvisioningContext ctx, + PrismObject repoShadow, List sortedOperations, + ProvisioningOperationOptions options, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException, EncryptionException { + ShadowType shadowType = repoShadow.asObjectable(); + OperationResult retryResult = new OperationResult(OP_REFRESH_RETRY); + if (ShadowUtil.isDead(shadowType)) { + RefreshShadowOperation rso = new RefreshShadowOperation(); + retryResult.recordSuccess(); + rso.setRefreshedShadow(repoShadow); + rso.setRefreshResult(retryResult); + return rso; + } + + Duration retryPeriod = ProvisioningUtil.getRetryPeriod(ctx); + + List> notificationDeltas = new ArrayList<>(); + + Collection> executedDeltas = new ArrayList<>(); + for (PendingOperationType pendingOperation: sortedOperations) { + + if (!needsRetry(pendingOperation)) { + continue; + } + // We really want to get "now" here. Retrying operation may take some time. We want good timestamps that do not lie. + XMLGregorianCalendar now = clock.currentTimeXMLGregorianCalendar(); + if (!isAfterRetryPeriod(ctx, pendingOperation, retryPeriod, now)) { + if (PendingOperationTypeType.RETRY != pendingOperation.getType()) { + continue; + } + if (!ProvisioningOperationOptions.isForceRetry(options)) { + continue; + } + } + + LOGGER.trace("Going to retry operation {} on {}", pendingOperation, repoShadow); + + // Record attempt number and timestamp before the operation + // TODO: later use this as an optimistic lock to make sure that two threads won't retry the operation at the same time + + // TODO: move to a better place + ObjectDelta shadowDelta = repoShadow.createModifyDelta(); + ItemPath containerPath = pendingOperation.asPrismContainerValue().getPath(); + + int attemptNumber = pendingOperation.getAttemptNumber() + 1; + PropertyDelta attemptNumberDelta = shadowDelta.createPropertyModification(containerPath.append(PendingOperationType.F_ATTEMPT_NUMBER)); + attemptNumberDelta.setRealValuesToReplace(attemptNumber); + shadowDelta.addModification(attemptNumberDelta); + + PropertyDelta lastAttemptTimestampDelta = shadowDelta.createPropertyModification(containerPath.append(PendingOperationType.F_LAST_ATTEMPT_TIMESTAMP)); + lastAttemptTimestampDelta.setRealValuesToReplace(now); + shadowDelta.addModification(lastAttemptTimestampDelta); + + PropertyDelta resultStatusDelta = shadowDelta.createPropertyModification(containerPath.append(PendingOperationType.F_RESULT_STATUS)); + resultStatusDelta.setRealValuesToReplace(OperationResultStatusType.IN_PROGRESS); + shadowDelta.addModification(resultStatusDelta); + + shadowManager.modifyShadowAttributes(ctx, repoShadow, shadowDelta.getModifications(), parentResult); + shadowDelta.applyTo(repoShadow); + + ObjectDeltaType pendingDeltaType = pendingOperation.getDelta(); + ObjectDelta pendingDelta = DeltaConvertor.createObjectDelta(pendingDeltaType, prismContext); + + ProvisioningOperationState opState = + ProvisioningOperationState.fromPendingOperation(repoShadow, pendingOperation); + + LOGGER.debug("Retrying operation {} on {}, attempt #{}", pendingDelta, repoShadow, attemptNumber); + + OperationResult result = parentResult.createSubresult(OP_OPERATION_RETRY); + ObjectDeltaOperation objectDeltaOperation = new ObjectDeltaOperation<>(pendingDelta); + try { + retryOperation(ctx, pendingDelta, opState, task, result); + repoShadow = opState.getRepoShadow(); + result.computeStatus(); + if (result.isError()) { + retryResult.setStatus(result.getStatus()); + } + //TODO maybe add whole "result" as subresult to the retryResult? + result.muteError(); + } catch (CommunicationException | GenericFrameworkException | ObjectAlreadyExistsException | SchemaException | ObjectNotFoundException | ConfigurationException | SecurityViolationException e) { + // This is final failure: the error is not handled. + // Therefore the operation is now completed - finished with an error. + // But we do not want to stop the task. Just log the error. + LOGGER.error("Operation {} on {} ended up with an error after {} retries: {}", + pendingDelta, repoShadow, attemptNumber, e.getMessage(), e); + // The retry itself was a success. Operation that was retried might have failed. + // And that is recorded in the shadow. But we have successfully retried the operation. + result.recordHandledError(e); + retryResult.recordFatalError("Operation " + pendingDelta + " on " + repoShadow + " ended with an error after " + attemptNumber + " retries: " + e.getMessage()); + } catch (Throwable e) { + // This is unexpected error during retry. This means that there was other + // failure that we did not expected. This is likely to be bug - or maybe wrong + // error handling. This means that the retry was a failure. + result.recordFatalError(e); + retryResult.recordFatalError(e); + } + + objectDeltaOperation.setExecutionResult(result); + executedDeltas.add(objectDeltaOperation); + } + + RefreshShadowOperation rso = new RefreshShadowOperation(); + rso.setExecutedDeltas(executedDeltas); + rso.setRefreshedShadow(repoShadow); + parentResult.computeStatus(); + + rso.setRefreshResult(retryResult); + + LOGGER.trace("refreshshadowOperaton {}", rso.debugDump()); + return rso; + } + + private void retryOperation(ProvisioningContext ctx, + ObjectDelta pendingDelta, + ProvisioningOperationState opState, + Task task, + OperationResult result) + throws CommunicationException, GenericFrameworkException, ObjectAlreadyExistsException, SchemaException, ObjectNotFoundException, ConfigurationException, SecurityViolationException, PolicyViolationException, ExpressionEvaluationException, EncryptionException { + + ProvisioningOperationOptions options = ProvisioningOperationOptions.createForceRetry(false); + OperationProvisioningScriptsType scripts = null; // TODO + if (pendingDelta.isAdd()) { + PrismObject shadowToAdd = pendingDelta.getObjectToAdd(); + addShadowAttempt(ctx, shadowToAdd, scripts, + (ProvisioningOperationState>>) opState, + options, task, result); + opState.setRepoShadow(shadowToAdd); + } + + if (pendingDelta.isModify()) { + modifyShadowAttempt(ctx, pendingDelta.getModifications(), scripts, options, + (ProvisioningOperationState>>>) opState, + task, result); + } + + if (pendingDelta.isDelete()) { + deleteShadowAttempt(ctx, options, scripts, + (ProvisioningOperationState) opState, + task, result); + } + } + + private boolean needsRetry(PendingOperationType pendingOperation) { + return PendingOperationExecutionStatusType.EXECUTING.equals(pendingOperation.getExecutionStatus()) && + pendingOperation.getAttemptNumber() != null; + } + + private boolean isAfterRetryPeriod(ProvisioningContext ctx, PendingOperationType pendingOperation, Duration retryPeriod, XMLGregorianCalendar now) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException { + XMLGregorianCalendar lastAttemptTimestamp = pendingOperation.getLastAttemptTimestamp(); + XMLGregorianCalendar scheduledRetryTimestamp = XmlTypeConverter.addDuration(lastAttemptTimestamp, retryPeriod); + return XmlTypeConverter.compare(now, scheduledRetryTimestamp) == DatatypeConstants.GREATER; + } + + // This is very simple code that essentially works only for postponed operations (retries). + // TODO: better support for async and manual operations + private PrismObject cancelAllPendingOperations(ProvisioningContext ctx, + PrismObject repoShadow, Task task, OperationResult parentResult) throws SchemaException, ObjectNotFoundException, ConfigurationException, CommunicationException, ExpressionEvaluationException { + List pendingOperations = repoShadow.asObjectable().getPendingOperation(); + if (pendingOperations.isEmpty()) { + return repoShadow; + } + XMLGregorianCalendar now = clock.currentTimeXMLGregorianCalendar(); + ObjectDelta shadowDelta = repoShadow.createModifyDelta(); + for (PendingOperationType pendingOperation: pendingOperations) { + if (pendingOperation.getExecutionStatus() == PendingOperationExecutionStatusType.COMPLETED) { + continue; + } + if (pendingOperation.getType() != PendingOperationTypeType.RETRY) { + // Other operations are not cancellable now + continue; + } + ItemPath containerPath = pendingOperation.asPrismContainerValue().getPath(); + PropertyDelta executionStatusDelta = shadowDelta.createPropertyModification(containerPath.append(PendingOperationType.F_EXECUTION_STATUS)); + executionStatusDelta.setRealValuesToReplace(PendingOperationExecutionStatusType.COMPLETED); + shadowDelta.addModification(executionStatusDelta); + PropertyDelta completionTimestampDelta = shadowDelta.createPropertyModification(containerPath.append(PendingOperationType.F_COMPLETION_TIMESTAMP)); + completionTimestampDelta.setRealValuesToReplace(now); + shadowDelta.addModification(completionTimestampDelta); + PropertyDelta resultStatusDelta = shadowDelta.createPropertyModification(containerPath.append(PendingOperationType.F_RESULT_STATUS)); + resultStatusDelta.setRealValuesToReplace(OperationResultStatusType.NOT_APPLICABLE); + shadowDelta.addModification(resultStatusDelta); + } + if (shadowDelta.isEmpty()) { + return repoShadow; + } + LOGGER.debug("Cancelling pending operations on {}", repoShadow); + shadowManager.modifyShadowAttributes(ctx, repoShadow, shadowDelta.getModifications(), parentResult); + shadowDelta.applyTo(repoShadow); + return repoShadow; + } + + private PrismObject cleanUpDeadShadow(ProvisioningContext ctx, + PrismObject repoShadow, + XMLGregorianCalendar now, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException, EncryptionException { + ShadowType shadowType = repoShadow.asObjectable(); + if (!ShadowUtil.isDead(shadowType)) { + return repoShadow; + } + Duration gracePeriod = ProvisioningUtil.getGracePeriod(ctx); + Duration deadRetentionPeriod = ProvisioningUtil.getDeadShadowRetentionPeriod(ctx); + Duration expirationPeriod = XmlTypeConverter.longerDuration(gracePeriod, deadRetentionPeriod); + XMLGregorianCalendar lastActivityTimestamp = null; + + for (PendingOperationType pendingOperation: shadowType.getPendingOperation()) { + lastActivityTimestamp = XmlTypeConverter.laterTimestamp(lastActivityTimestamp, pendingOperation.getRequestTimestamp()); + lastActivityTimestamp = XmlTypeConverter.laterTimestamp(lastActivityTimestamp, pendingOperation.getLastAttemptTimestamp()); + lastActivityTimestamp = XmlTypeConverter.laterTimestamp(lastActivityTimestamp, pendingOperation.getCompletionTimestamp()); + } + if (lastActivityTimestamp == null) { + MetadataType metadata = shadowType.getMetadata(); + if (metadata != null) { + lastActivityTimestamp = metadata.getModifyTimestamp(); + if (lastActivityTimestamp == null) { + lastActivityTimestamp = metadata.getCreateTimestamp(); + } + } + } + + if (ProvisioningUtil.isOverPeriod(now, expirationPeriod, lastActivityTimestamp)) { + // Perish you stinking corpse! + LOGGER.debug("Deleting dead {} because it is expired", repoShadow); + shadowManager.deleteShadow(ctx, repoShadow, parentResult); + ResourceObjectShadowChangeDescription change = new ResourceObjectShadowChangeDescription(); + change.setCleanDeadShadow(true); + change.setOldShadow(repoShadow); + change.setResource(ctx.getResource().asPrismObject()); + change.setObjectDelta(repoShadow.createDeleteDelta()); + change.setSourceChannel(SchemaConstants.CHANGE_CHANNEL_DISCOVERY_URI); + changeNotificationDispatcher.notifyChange(change, task, parentResult); + applyDefinition(repoShadow, parentResult); + ResourceOperationDescription operationDescription = createSuccessOperationDescription(ctx, repoShadow, + repoShadow.createDeleteDelta(), parentResult); + operationListener.notifySuccess(operationDescription, task, parentResult); + return null; + } else { + LOGGER.trace("Keeping dead {} because it is not expired yet, last activity={}, expiration period={}", repoShadow, lastActivityTimestamp, expirationPeriod); + return repoShadow; + } + } + + private void expirePendingOperations(ProvisioningContext ctx, PrismObject repoShadow, ObjectDelta shadowDelta, XMLGregorianCalendar now, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException { + ShadowType shadowType = repoShadow.asObjectable(); + + Duration gracePeriod = ProvisioningUtil.getGracePeriod(ctx); + Duration pendingOperationRetentionPeriod = ProvisioningUtil.getPendingOperationRetentionPeriod(ctx); + Duration expirePeriod = XmlTypeConverter.longerDuration(gracePeriod, pendingOperationRetentionPeriod); + for (PendingOperationType pendingOperation: shadowType.getPendingOperation()) { + if (ProvisioningUtil.isOverPeriod(now, expirePeriod, pendingOperation)) { + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("Deleting pending operation because it is completed '{}' and expired: {}", pendingOperation.getResultStatus().value(), pendingOperation); + } + shadowDelta.addModificationDeleteContainer(ShadowType.F_PENDING_OPERATION, pendingOperation.clone()); + } + } + } + + public void applyDefinition(ObjectDelta delta, ShadowType repoShadow, + OperationResult parentResult) throws SchemaException, ObjectNotFoundException, + CommunicationException, ConfigurationException, ExpressionEvaluationException { + PrismObject shadow = null; + ResourceShadowDiscriminator discriminator = null; + if (delta.isAdd()) { + shadow = delta.getObjectToAdd(); + } else if (delta.isModify()) { + if (delta instanceof ShadowDiscriminatorObjectDelta) { + // This one does not have OID, it has to be specially processed + discriminator = ((ShadowDiscriminatorObjectDelta) delta).getDiscriminator(); + } else { + String shadowOid = delta.getOid(); + if (shadowOid == null) { + if (repoShadow == null) { + throw new IllegalArgumentException("No OID in object delta " + delta + + " and no externally-supplied shadow is present as well."); + } + shadow = repoShadow.asPrismObject(); + } else { + shadow = repositoryService.getObject(delta.getObjectTypeClass(), shadowOid, null, + parentResult); // TODO consider fetching only when + // really necessary + } + } + } else { + // Delete delta, nothing to do at all + return; + } + ProvisioningContext ctx; + if (shadow == null) { + ctx = ctxFactory.create(discriminator, null, parentResult); + ctx.assertDefinition(); + } else { + ctx = ctxFactory.create(shadow, null, parentResult); + ctx.assertDefinition(); + } + shadowCaretaker.applyAttributesDefinition(ctx, delta); + } + + public void applyDefinition(PrismObject shadow, OperationResult parentResult) + throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, ExpressionEvaluationException { + ProvisioningContext ctx = ctxFactory.create(shadow, null, parentResult); + ctx.assertDefinition(); + shadowCaretaker.applyAttributesDefinition(ctx, shadow); + } + + public void setProtectedShadow(PrismObject shadow, OperationResult parentResult) + throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException { + ProvisioningContext ctx = ctxFactory.create(shadow, null, parentResult); + ctx.assertDefinition(); + ProvisioningUtil.setProtectedFlag(ctx, shadow, matchingRuleRegistry, relationRegistry); + } + + public void applyDefinition(final ObjectQuery query, OperationResult result) + throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, ExpressionEvaluationException { + ResourceShadowDiscriminator coordinates = ObjectQueryUtil.getCoordinates(query.getFilter(), prismContext); + ProvisioningContext ctx = ctxFactory.create(coordinates, null, result); + ctx.assertDefinition(); + applyDefinition(ctx, query); + } + + private void applyDefinition(final ProvisioningContext ctx, final ObjectQuery query) + throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, ExpressionEvaluationException { + if (query == null) { + return; + } + ObjectFilter filter = query.getFilter(); + if (filter == null) { + return; + } + final RefinedObjectClassDefinition objectClassDefinition = ctx.getObjectClassDefinition(); + com.evolveum.midpoint.prism.query.Visitor visitor = subfilter -> { + if (subfilter instanceof PropertyValueFilter) { + PropertyValueFilter valueFilter = (PropertyValueFilter) subfilter; + ItemDefinition definition = valueFilter.getDefinition(); + if (definition instanceof ResourceAttributeDefinition) { + return; // already has a resource-related definition + } + if (!ShadowType.F_ATTRIBUTES.equivalent(valueFilter.getParentPath())) { + return; + } + QName attributeName = valueFilter.getElementName(); + ResourceAttributeDefinition attributeDefinition = objectClassDefinition.findAttributeDefinition(attributeName); + if (attributeDefinition == null) { + throw new TunnelException(new SchemaException("No definition for attribute " + + attributeName + " in query " + query)); + } + valueFilter.setDefinition(attributeDefinition); + } + }; + try { + filter.accept(visitor); + } catch (TunnelException te) { + throw (SchemaException) te.getCause(); + } + } + + protected ResourceType getResource(ResourceShadowDiscriminator coords, Task task, OperationResult parentResult) + throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException { + String resourceOid = coords.getResourceOid(); + if (resourceOid == null) { + throw new IllegalArgumentException("No resource OID in " + coords); + } + return resourceManager.getResource(resourceOid, null, task, parentResult).asObjectable(); + } + + //we need to remove resolved identifiers form the ShadowAssociationType before we save it to the shadow as an unfinished operation. + void normalizeAssociationDeltasBeforeSave(Collection> associationContainers) { + if (associationContainers == null) { + return; + } + for (PrismContainerValue associationContainer : associationContainers) { + if (associationContainer.contains(ShadowAssociationType.F_IDENTIFIERS) && associationContainer.contains(ShadowAssociationType.F_SHADOW_REF)) { + associationContainer.removeContainer(ShadowAssociationType.F_IDENTIFIERS); + } + } + } + + //////////////////////////////////////////////////////////////////////////// + // SEARCH + //////////////////////////////////////////////////////////////////////////// + +// public SearchResultList> searchObjects(ObjectQuery query, +// Collection> options, +// final boolean readFromRepository, Task task, final OperationResult parentResult) +// throws SchemaException, ObjectNotFoundException, CommunicationException, +// ConfigurationException, SecurityViolationException, ExpressionEvaluationException { +// +// SearchResultList> list = new SearchResultList<>(); +// SearchResultMetadata metadata = searchObjectsIterative(query, options, (shadow,result) -> list.add(shadow), readFromRepository, task, parentResult); +// list.setMetadata(metadata); +// return list; +// +// } + + public SearchResultMetadata searchObjectsIterative(ObjectQuery query, + Collection> options, final ResultHandler handler, + final boolean readFromRepository, Task task, final OperationResult parentResult) + throws SchemaException, ObjectNotFoundException, CommunicationException, + ConfigurationException, SecurityViolationException, ExpressionEvaluationException { + + ProvisioningContext ctx = createContextForSearch(query, options, task, parentResult); + + return searchObjectsIterative(ctx, query, options, handler, readFromRepository, parentResult); + } + + private ProvisioningContext createContextForSearch(ObjectQuery query, + Collection> options, Task task, OperationResult parentResult) + throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, + ExpressionEvaluationException { + ResourceShadowDiscriminator coordinates = ObjectQueryUtil.getCoordinates(query != null ? query.getFilter() : null, + prismContext); + final ProvisioningContext ctx = ctxFactory.create(coordinates, task, parentResult); + ctx.setGetOperationOptions(options); + ctx.assertDefinition(); + return ctx; + } + + @NotNull + public SearchResultList> searchObjects(ObjectQuery query, + Collection> options, Task task, final OperationResult parentResult) + throws SchemaException, ObjectNotFoundException, CommunicationException, + ConfigurationException, SecurityViolationException, ExpressionEvaluationException { + + ProvisioningContext ctx = createContextForSearch(query, options, task, parentResult); + return searchObjects(ctx, query, options, parentResult); + } + + public SearchResultMetadata searchObjectsIterative(final ProvisioningContext ctx, ObjectQuery query, + Collection> options, final ResultHandler handler, + final boolean readFromRepository, final OperationResult parentResult) + throws SchemaException, ObjectNotFoundException, CommunicationException, + ConfigurationException, SecurityViolationException, ExpressionEvaluationException { + applyDefinition(ctx, query); + + GetOperationOptions rootOptions = SelectorOptions.findRootOptions(options); + if (ProvisioningUtil.shouldDoRepoSearch(rootOptions)) { + return searchObjectsIterativeRepository(ctx, query, options, handler, parentResult); + } + boolean isDoDiscovery = ProvisioningUtil.isDoDiscovery(ctx.getResource(), rootOptions); + + // We need to record the fetch down here. Now it is certain that we are + // going to fetch from resource + // (we do not have raw/noFetch option) + InternalMonitor.recordCount(InternalCounters.SHADOW_FETCH_OPERATION_COUNT); + + ObjectQuery attributeQuery = createAttributeQuery(query); + + ResultHandler resultHandler = (PrismObject resourceObject, OperationResult objResult) -> { + LOGGER.trace("Found resource object\n{}", resourceObject.debugDumpLazily(1)); + PrismObject resultShadow; + try { + // The shadow does not have any kind or intent at this point. + // But at least locate the definition using object classes. + ProvisioningContext estimatedShadowCtx = shadowCaretaker.reapplyDefinitions(ctx, resourceObject); + // Try to find shadow that corresponds to the resource object. + if (readFromRepository) { + PrismObject repoShadow = acquireRepositoryShadow( + estimatedShadowCtx, resourceObject, true, isDoDiscovery, objResult); + + // This determines the definitions exactly. How the repo + // shadow should have proper kind/intent + ProvisioningContext shadowCtx = shadowCaretaker.applyAttributesDefinition(ctx, repoShadow); + // TODO: shadowState + repoShadow = shadowManager.updateShadow(shadowCtx, resourceObject, null, repoShadow, null, objResult); + + resultShadow = completeShadow(shadowCtx, resourceObject, repoShadow, isDoDiscovery, objResult); + + // TODO do we want also to futurize the shadow like in getObject? + + //check and fix kind/intent + ShadowType repoShadowType = repoShadow.asObjectable(); + if (isDoDiscovery && (repoShadowType.getKind() == null || repoShadowType.getIntent() == null)) { //TODO: check also empty? + // notify resourceObjectChangeListeners to fix kind and intent for Shadow + // Do NOT invoke this if discovery is disabled. This may ruin the flow (e.g. when importing objects) + // or it may lead to discovery loops. + notifyResourceObjectChangeListeners(repoShadow, ctx.getResource().asPrismObject(), false); + } + + } else { + resultShadow = resourceObject; + } + + validateShadow(resultShadow, readFromRepository); + + } catch (SchemaException e) { + objResult.recordFatalError("Schema error: " + e.getMessage(), e); + LOGGER.error("Schema error: {}", e.getMessage(), e); + return false; + } catch (ConfigurationException e) { + objResult.recordFatalError("Configuration error: " + e.getMessage(), e); + LOGGER.error("Configuration error: {}", e.getMessage(), e); + return false; + } catch (ObjectNotFoundException | CommunicationException + | SecurityViolationException | GenericConnectorException | ExpressionEvaluationException | EncryptionException e) { + objResult.recordFatalError(e.getMessage(), e); + LOGGER.error("{}", e.getMessage(), e); + return false; + } + + boolean doContinue; + try { + + doContinue = handler.handle(resultShadow, objResult); + + objResult.computeStatus(); + objResult.recordSuccessIfUnknown(); + + } catch (RuntimeException | Error e) { + objResult.recordFatalError(e); + throw e; + } + + return doContinue; + }; + + boolean fetchAssociations = SelectorOptions.hasToLoadPath(ShadowType.F_ASSOCIATION, options); + + return resourceObjectConverter.searchResourceObjects(ctx, resultHandler, attributeQuery, + fetchAssociations, parentResult); + + } + + @NotNull + public SearchResultList> searchObjects(final ProvisioningContext ctx, ObjectQuery query, + Collection> options, final OperationResult parentResult) + throws SchemaException, ObjectNotFoundException, CommunicationException, + ConfigurationException, SecurityViolationException, ExpressionEvaluationException { + applyDefinition(ctx, query); + + GetOperationOptions rootOptions = SelectorOptions.findRootOptions(options); + if (ProvisioningUtil.shouldDoRepoSearch(rootOptions)) { + return searchObjectsRepository(ctx, query, options, parentResult); + } else { + SearchResultList> rv = new SearchResultList<>(); + SearchResultMetadata metadata = searchObjectsIterative(ctx, query, options, (s, opResult) -> rv.add(s), true, + parentResult); + rv.setMetadata(metadata); + return rv; + } + } + + /** + * Acquires repository shadow for a provided resource shadow. The repository shadow is locate or created. + * In case that the shadow is created, all additional ceremonies for a new shadow is done, e.g. invoking + * change notifications (discovery). + * + * Returned shadow is NOT guaranteed to have all the attributes aligned and updated. That is only possible after + * completeShadow(). But maybe, this method can later invoke completeShadow() and do all the necessary stuff? + * + * It may look like this method would rather belong to ShadowManager. But it does NOT. It does too much stuff + * (e.g. change notification). + */ + private PrismObject acquireRepositoryShadow(ProvisioningContext ctx, + PrismObject resourceShadow, boolean unknownIntent, boolean isDoDiscovery, OperationResult parentResult) + throws SchemaException, ConfigurationException, ObjectNotFoundException, + CommunicationException, SecurityViolationException, GenericConnectorException, ExpressionEvaluationException, EncryptionException { + + PrismObject existingRepoShadow = shadowManager.lookupLiveShadowInRepository(ctx, resourceShadow, parentResult); + + if (existingRepoShadow != null) { + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("Found shadow object in the repository {}", ShadowUtil.shortDumpShadow(existingRepoShadow)); + } + return existingRepoShadow; + } + + LOGGER.trace("Shadow object (in repo) corresponding to the resource object (on the resource) was not found. " + + "The repo shadow will be created. The resource object:\n{}", resourceShadow); + + // TODO: do something about shadows with mathcing secondary identifiers? We do not need to care about these any longer, do we? + //MID-5844 + // we need it for the consistency. following is the use case. Account is beeing created on the resource + // but the resource cannot be reached by midPoint. Meanwhile the account is created manually in the resource + // when reconciliation runs, origin account created while resource was not reachable doesn't contain primary identifier + // so we rather try also secondary identifier to be sure nothing goes wrong +// PrismObject repoShadow; + +// PrismObject shadowBySecondaryIdentifier = shadowManager.lookupConflictingShadowBySecondaryIdentifiers(ctx, +// resourceShadow, parentResult); +// +// // check if the shadow contains primary identifier. if it does, we can skip the next session +// if (shadowBySecondaryIdentifier != null) { +// +// ShadowType shadowType = shadowBySecondaryIdentifier.asObjectable(); +// String currentPrimaryIdentifier = shadowManager.determinePrimaryIdentifierValue(ctx, shadowBySecondaryIdentifier); +// +// LOGGER.info("###CURRENT PI: {}", currentPrimaryIdentifier); +// String expectedPrimaryIdentifier = shadowManager.determinePrimaryIdentifierValue(ctx, resourceShadow); +// LOGGER.info("### EXPECTED PI: {}", expectedPrimaryIdentifier); +// +// if (!StringUtils.equals(currentPrimaryIdentifier, expectedPrimaryIdentifier)) { +// shadowCaretaker.applyAttributesDefinition(ctx, shadowBySecondaryIdentifier); +// shadowBySecondaryIdentifier = completeShadow(ctx, resourceShadow, shadowBySecondaryIdentifier, isDoDiscovery, parentResult); +// Task task = taskManager.createTaskInstance(); +// ResourceOperationDescription failureDescription = ProvisioningUtil.createResourceFailureDescription(shadowBySecondaryIdentifier, ctx.getResource(), null, parentResult); +// shadowBySecondaryIdentifier.asObjectable().setDead(Boolean.TRUE); +// changeNotificationDispatcher.notifyFailure(failureDescription, task, parentResult); +// shadowManager.deleteConflictedShadowFromRepo(shadowBySecondaryIdentifier, parentResult); +// } +// +// } +// + + // The resource object obviously exists on the resource, but appropriate shadow does + // not exist in the repository we need to create the shadow to align repo state to the + // reality (resource) + + PrismObject createdRepoShadow; + try { + + createdRepoShadow = shadowManager.addDiscoveredRepositoryShadow(ctx, resourceShadow, parentResult); + + } catch (ObjectAlreadyExistsException e) { + // Conflict! But we haven't supplied an OID and we have checked for existing shadow before, + // therefore there should not conflict. Unless someone managed to create the same shadow + // between our check and our create attempt. In that case try to re-check for shadow existence + // once more. + + OperationResult originalRepoAddSubresult = parentResult.getLastSubresult(); + + LOGGER.debug("Attempt to create new repo shadow for {} ended up in conflict, re-trying the search for repo shadow", resourceShadow); + PrismObject conflictingShadow = shadowManager.lookupLiveShadowInRepository(ctx, resourceShadow, parentResult); + + if (conflictingShadow == null) { + // This is really strange. The shadow should not have disappeared in the meantime, dead shadow would remain instead. + // Maybe we have broken "indexes"? (e.g. primaryIdentifierValue column) + + // Do some "research" and log the results, so we have good data to diagnose this situation. + String determinedPrimaryIdentifierValue = shadowManager.determinePrimaryIdentifierValue(ctx, resourceShadow); + PrismObject potentialConflictingShadow = shadowManager.lookupShadowByPrimaryIdentifierValue(ctx, determinedPrimaryIdentifierValue, parentResult); + + LOGGER.error("Unexpected repository behavior: object already exists error even after we double-checked shadow uniqueness: {}", e.getMessage(), e); + LOGGER.debug("REPO CONFLICT: resource shadow\n{}", resourceShadow.debugDump(1)); + LOGGER.debug("REPO CONFLICT: resource shadow: determined primaryIdentifierValue: {}", determinedPrimaryIdentifierValue); + LOGGER.debug("REPO CONFLICT: potential conflicting repo shadow (by primaryIdentifierValue)\n{}", potentialConflictingShadow==null?null:potentialConflictingShadow.debugDump(1)); + + throw new SystemException( + "Unexpected repository behavior: object already exists error even after we double-checked shadow uniqueness: " + e.getMessage(), e); + } + + originalRepoAddSubresult.muteError(); + return conflictingShadow; + } + + resourceShadow.setOid(createdRepoShadow.getOid()); + ShadowType resourceShadowBean = resourceShadow.asObjectable(); + if (resourceShadowBean.getResourceRef() == null) { + resourceShadowBean.setResourceRef(new ObjectReferenceType()); + } + resourceShadowBean.getResourceRef().asReferenceValue().setObject(ctx.getResource().asPrismObject()); + + if (isDoDiscovery) { + // We have object for which there was no shadow. Which means that midPoint haven't known about this shadow before. + // Invoke notifyChange() so the new shadow is properly initialized. + + notifyResourceObjectChangeListeners(resourceShadow, ctx.getResource().asPrismObject(), true); + } + + PrismObject finalRepoShadow; + if (unknownIntent) { + // Intent may have been changed during the notifyChange processing. + // Re-read the shadow if necessary. + finalRepoShadow = shadowManager.fixShadow(ctx, createdRepoShadow, parentResult); + } else { + finalRepoShadow = createdRepoShadow; + } + + LOGGER.trace("Final repo shadow (created and possibly re-read):\n{}", finalRepoShadow.debugDumpLazily(1)); + return finalRepoShadow; + } + + private ObjectQuery createAttributeQuery(ObjectQuery query) throws SchemaException { + QueryFactory queryFactory = prismContext.queryFactory(); + + ObjectFilter filter = null; + if (query != null) { + filter = query.getFilter(); + } + + ObjectQuery attributeQuery = null; + + if (filter instanceof AndFilter) { + List conditions = ((AndFilter) filter).getConditions(); + List attributeFilter = createAttributeQueryInternal(conditions); + if (attributeFilter.size() > 1) { + attributeQuery = queryFactory.createQuery(queryFactory.createAnd(attributeFilter)); + } else if (attributeFilter.size() < 1) { + LOGGER.trace("No attribute filter defined in the query."); + } else { + attributeQuery = queryFactory.createQuery(attributeFilter.iterator().next()); + } + } + + if (query != null && query.getPaging() != null) { + if (attributeQuery == null) { + attributeQuery = queryFactory.createQuery(); + } + attributeQuery.setPaging(query.getPaging()); + } + if (query != null && query.isAllowPartialResults()) { + if (attributeQuery == null) { + attributeQuery = queryFactory.createQuery(); + } + attributeQuery.setAllowPartialResults(true); + } + + if (InternalsConfig.consistencyChecks && attributeQuery != null + && attributeQuery.getFilter() != null) { + attributeQuery.getFilter().checkConsistence(true); + } + return attributeQuery; + } + + private List createAttributeQueryInternal(List conditions) + throws SchemaException { + List attributeFilter = new ArrayList<>(); + for (ObjectFilter f : conditions) { + if (f instanceof PropertyValueFilter) { // TODO + ItemPath parentPath = ((PropertyValueFilter) f).getParentPath(); + if (parentPath.isEmpty()) { + QName elementName = ((PropertyValueFilter) f).getElementName(); + if (QNameUtil.match(ShadowType.F_OBJECT_CLASS, elementName) || + QNameUtil.match(ShadowType.F_AUXILIARY_OBJECT_CLASS, elementName) || + QNameUtil.match(ShadowType.F_KIND, elementName) || + QNameUtil.match(ShadowType.F_INTENT, elementName)) { + continue; + } + throw new SchemaException("Cannot combine on-resource and off-resource properties in a shadow search query. Encountered property " + + ((PropertyValueFilter) f).getFullPath()); + } + attributeFilter.add(f); + } else if (f instanceof NaryLogicalFilter) { + List subFilters = createAttributeQueryInternal( + ((NaryLogicalFilter) f).getConditions()); + if (subFilters.size() > 1) { + if (f instanceof OrFilter) { + attributeFilter.add(prismContext.queryFactory().createOr(subFilters)); + } else if (f instanceof AndFilter) { + attributeFilter.add(prismContext.queryFactory().createAnd(subFilters)); + } else { + throw new IllegalArgumentException( + "Could not translate query filter. Unknown type: " + f); + } + } else if (subFilters.size() < 1) { + continue; + } else { + attributeFilter.add(subFilters.iterator().next()); + } + } else if (f instanceof UnaryLogicalFilter) { + ObjectFilter subFilter = ((UnaryLogicalFilter) f).getFilter(); + attributeFilter.add(prismContext.queryFactory().createNot(subFilter)); + } else if (f instanceof SubstringFilter) { + attributeFilter.add(f); + } else if (f instanceof RefFilter) { + ItemPath parentPath = ((RefFilter)f).getParentPath(); + if (parentPath.isEmpty()) { + QName elementName = ((RefFilter) f).getElementName(); + if (QNameUtil.match(ShadowType.F_RESOURCE_REF, elementName)) { + continue; + } + } + throw new SchemaException("Cannot combine on-resource and off-resource properties in a shadow search query. Encountered filter " + f); + } else { + throw new SchemaException("Cannot combine on-resource and off-resource properties in a shadow search query. Encountered filter " + f); + } + + } + + return attributeFilter; + } + + private SearchResultMetadata searchObjectsIterativeRepository(final ProvisioningContext ctx, + ObjectQuery query, Collection> options, + final ResultHandler shadowHandler, OperationResult parentResult) + throws SchemaException, ConfigurationException, ObjectNotFoundException, + CommunicationException, ExpressionEvaluationException { + ResultHandler repoHandler = createRepoShadowHandler(ctx, options, shadowHandler); + return shadowManager.searchObjectsIterativeRepository(ctx, query, options, repoHandler, parentResult); + } + + @NotNull + private ResultHandler createRepoShadowHandler(ProvisioningContext ctx, + Collection> options, ResultHandler shadowHandler) { + return (PrismObject shadow, OperationResult objResult) -> { + try { + processRepoShadow(ctx, shadow, options, objResult); + + boolean cont = shadowHandler == null || shadowHandler.handle(shadow, objResult); + + objResult.computeStatus(); + objResult.recordSuccessIfUnknown(); + if (!objResult.isSuccess()) { + OperationResultType resultType = objResult.createOperationResultType(); + shadow.asObjectable().setFetchResult(resultType); + } + + return cont; + } catch (RuntimeException e) { + objResult.recordFatalError(e); + throw e; + } catch (SchemaException | ConfigurationException | ObjectNotFoundException + | CommunicationException | ExpressionEvaluationException e) { + objResult.recordFatalError(e); + shadow.asObjectable().setFetchResult(objResult.createOperationResultType()); + throw new SystemException(e); + } + }; + } + + @NotNull + private SearchResultList> searchObjectsRepository(ProvisioningContext ctx, ObjectQuery query, + Collection> options, OperationResult parentResult) + throws SchemaException, ConfigurationException, ObjectNotFoundException, + CommunicationException, ExpressionEvaluationException { + SearchResultList> objects = shadowManager.searchObjectsRepository(ctx, query, options, parentResult); + ResultHandler repoHandler = createRepoShadowHandler(ctx, options, null); + parentResult.setSummarizeSuccesses(true); + for (PrismObject object : objects) { + repoHandler.handle(object, parentResult.createMinorSubresult(ShadowCache.class.getName() + ".handleObject")); + } + parentResult.summarize(); // todo is this ok? + return objects; + } + + private void processRepoShadow(ProvisioningContext ctx, PrismObject shadow, + Collection> options, OperationResult objResult) + throws SchemaException, ConfigurationException, ObjectNotFoundException, CommunicationException, + ExpressionEvaluationException { + shadowCaretaker.applyAttributesDefinition(ctx, shadow); + // fixing MID-1640; hoping that the protected object filter uses only identifiers + // (that are stored in repo) + ProvisioningUtil.setProtectedFlag(ctx, shadow, matchingRuleRegistry, relationRegistry); + + validateShadow(shadow, true); + + if (GetOperationOptions.isMaxStaleness(SelectorOptions.findRootOptions(options))) { + CachingMetadataType cachingMetadata = shadow.asObjectable().getCachingMetadata(); + if (cachingMetadata == null) { + objResult.recordFatalError("Requested cached data but no cached data are available in the shadow"); + } + } + } + + private void validateShadow(PrismObject shadow, boolean requireOid) { + if (requireOid) { + Validate.notNull(shadow.getOid(), "null shadow OID"); + } + if (InternalsConfig.encryptionChecks) { + CryptoUtil.checkEncrypted(shadow); + } + } + + private void notifyResourceObjectChangeListeners(PrismObject resourceShadow, PrismObject resource, boolean newShadow) { + ResourceObjectShadowChangeDescription shadowChangeDescription = new ResourceObjectShadowChangeDescription(); + shadowChangeDescription.setResource(resource); + shadowChangeDescription.setOldShadow(newShadow ? null : resourceShadow); + shadowChangeDescription.setCurrentShadow(resourceShadow); + shadowChangeDescription.setSourceChannel(SchemaConstants.CHANGE_CHANNEL_DISCOVERY_URI); + shadowChangeDescription.setUnrelatedChange(true); + + Task task = taskManager.createTaskInstance(); + notifyResourceObjectChangeListeners(shadowChangeDescription, task, task.getResult()); + } + + public void notifyResourceObjectChangeListeners(ResourceObjectShadowChangeDescription change, Task task, + OperationResult parentResult) { + changeNotificationDispatcher.notifyChange(change, task, parentResult); + } + + public Integer countObjects(ObjectQuery query, Task task, final OperationResult result) + throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, + SecurityViolationException, ExpressionEvaluationException { + + ResourceShadowDiscriminator coordinates = ObjectQueryUtil.getCoordinates(query.getFilter(), prismContext); + final ProvisioningContext ctx = ctxFactory.create(coordinates, null, result); + ctx.assertDefinition(); + applyDefinition(ctx, query); + + RefinedObjectClassDefinition objectClassDef = ctx.getObjectClassDefinition(); + ResourceType resourceType = ctx.getResource(); + CountObjectsCapabilityType countObjectsCapabilityType = objectClassDef + .getEffectiveCapability(CountObjectsCapabilityType.class, resourceType); + if (countObjectsCapabilityType == null) { + // Unable to count. Return null which means "I do not know" + LOGGER.trace("countObjects: cannot count (no counting capability)"); + result.recordNotApplicableIfUnknown(); + return null; + } else { + CountObjectsSimulateType simulate = countObjectsCapabilityType.getSimulate(); + if (simulate == null) { + // We have native capability + + LOGGER.trace("countObjects: counting with native count capability"); + ConnectorInstance connector = ctx.getConnector(ReadCapabilityType.class, result); + try { + ObjectQuery attributeQuery = createAttributeQuery(query); + int count; + try { + count = connector.count(objectClassDef.getObjectClassDefinition(), attributeQuery, + objectClassDef.getPagedSearches(resourceType), ctx, result); + } catch (CommunicationException | GenericFrameworkException | SchemaException + | UnsupportedOperationException e) { + result.recordFatalError(e); + throw e; + } + result.computeStatus(); + result.cleanupResult(); + return count; + } catch (GenericFrameworkException | UnsupportedOperationException e) { + SystemException ex = new SystemException( + "Couldn't count objects on resource " + resourceType + ": " + e.getMessage(), e); + result.recordFatalError(ex); + throw ex; + } + + } else if (simulate == CountObjectsSimulateType.PAGED_SEARCH_ESTIMATE) { + + LOGGER.trace("countObjects: simulating counting with paged search estimate"); + if (!objectClassDef.isPagedSearchEnabled(resourceType)) { + throw new ConfigurationException( + "Configured count object capability to be simulated using a paged search but paged search capability is not present"); + } + + final Holder countHolder = new Holder<>(0); + + final ResultHandler handler = new ResultHandler() { + @Override + public boolean handle(PrismObject shadow, OperationResult objResult) { + int count = countHolder.getValue(); + count++; + countHolder.setValue(count); + return true; + } + + @Override + public String toString() { + return "(ShadowCache simulated counting handler)"; + } + }; + + query = query.clone(); + ObjectPaging paging = prismContext.queryFactory().createPaging(); + // Explicitly set offset. This makes a difference for some resources. + // E.g. LDAP connector will detect presence of an offset and it will initiate VLV search which + // can estimate number of results. If no offset is specified then continuous/linear search is + // assumed (e.g. Simple Paged Results search). Such search does not have ability to estimate + // number of results. + paging.setOffset(0); + paging.setMaxSize(1); + query.setPaging(paging); + Collection> options = schemaHelper.getOperationOptionsBuilder() + .item(ShadowType.F_ASSOCIATION).dontRetrieve() + .build(); + SearchResultMetadata resultMetadata; + try { + resultMetadata = searchObjectsIterative(query, options, handler, false, task, result); + } catch (SchemaException | ObjectNotFoundException | ConfigurationException + | SecurityViolationException e) { + result.recordFatalError(e); + throw e; + } + result.computeStatus(); + result.cleanupResult(); + + return resultMetadata.getApproxNumberOfAllResults(); + + } else if (simulate == CountObjectsSimulateType.SEQUENTIAL_SEARCH) { + //fix for MID-5204. as sequentialSearch option causes to fetch all resource objects, + // query paging is senseless here + if (query != null) { + query.setPaging(null); + } + LOGGER.trace("countObjects: simulating counting with sequential search (likely performance impact)"); + // traditional way of counting objects (i.e. counting them one by one) + final Holder countHolder = new Holder<>(0); + + final ResultHandler handler = new ResultHandler() { + + @Override + public boolean handle(PrismObject shadow, OperationResult objResult) { + int count = countHolder.getValue(); + count++; + countHolder.setValue(count); + return true; + } + }; + + Collection> options = schemaHelper.getOperationOptionsBuilder() + .item(ShadowType.F_ASSOCIATION).dontRetrieve() + .build(); + + searchObjectsIterative(query, options, handler, false, task, result); + // TODO: better error handling + result.computeStatus(); + result.cleanupResult(); + return countHolder.getValue(); + + } else { + throw new IllegalArgumentException("Unknown count capability simulate type " + simulate); + + } + } + + } + + private PrismObjectDefinition getShadowDefinition() { + return prismContext.getSchemaRegistry().findObjectDefinitionByCompileTimeClass(ShadowType.class); + } + +// private void deleteShadowFromRepoIfNeeded(Change change, OperationResult parentResult) +// throws ObjectNotFoundException { +// if (change.getObjectDelta() != null && change.getObjectDelta().getChangeType() == ChangeType.DELETE +// && change.getOldShadow() != null) { +// LOGGER.trace("Deleting detected shadow object form repository."); +// try { +// repositoryService.deleteObject(ShadowType.class, change.getOldShadow().getOid(), +// parentResult); +// LOGGER.debug("Shadow object successfully deleted form repository."); +// } catch (ObjectNotFoundException ex) { +// // What we want to delete is already deleted. Not a big problem. +// LOGGER.debug("Shadow object {} already deleted from repository ({})", change.getOldShadow(), +// ex); +// parentResult.recordHandledError( +// "Shadow object " + change.getOldShadow() + " already deleted from repository", ex); +// } +// +// } +// } + + /** + * Make sure that the shadow is complete, e.g. that all the mandatory fields + * are filled (e.g name, resourceRef, ...) Also transforms the shadow with + * respect to simulated capabilities. Also shadowRefs are added to associations. + */ + public PrismObject completeShadow(ProvisioningContext ctx, + PrismObject resourceShadow, PrismObject repoShadow, boolean isDoDiscovery, + OperationResult parentResult) + throws SchemaException, ConfigurationException, ObjectNotFoundException, + CommunicationException, SecurityViolationException, GenericConnectorException, ExpressionEvaluationException, EncryptionException { + + PrismObject resultShadow = repoShadow.clone(); + + // The real definition may be different than that of repo shadow (e.g. + // different auxiliary object classes). + resultShadow.applyDefinition(ctx.getObjectClassDefinition().getObjectDefinition(), true); + + assert resultShadow.getPrismContext() != null : "No prism context in resultShadow"; + + ResourceAttributeContainer resourceAttributesContainer = ShadowUtil + .getAttributesContainer(resourceShadow); + + ShadowType resultShadowType = resultShadow.asObjectable(); + ShadowType repoShadowType = repoShadow.asObjectable(); + ShadowType resourceShadowType = resourceShadow.asObjectable(); + + Collection auxObjectClassQNames = new ArrayList<>(); + + // Always take auxiliary object classes from the resource. Unlike + // structural object classes + // the auxiliary object classes may change. + resultShadow.removeProperty(ShadowType.F_AUXILIARY_OBJECT_CLASS); + PrismProperty resourceAuxOcProp = resourceShadow + .findProperty(ShadowType.F_AUXILIARY_OBJECT_CLASS); + if (resourceAuxOcProp != null) { + PrismProperty resultAuxOcProp = resultShadow + .findOrCreateProperty(ShadowType.F_AUXILIARY_OBJECT_CLASS); + resultAuxOcProp.addAll(PrismValueCollectionsUtil.cloneCollection(resourceAuxOcProp.getValues())); + auxObjectClassQNames.addAll(resultAuxOcProp.getRealValues()); + } + + resultShadowType.setName(new PolyStringType(ShadowUtil.determineShadowName(resourceShadow))); + if (resultShadowType.getObjectClass() == null) { + resultShadowType.setObjectClass(resourceAttributesContainer.getDefinition().getTypeName()); + } + + // Attributes + resultShadow.removeContainer(ShadowType.F_ATTRIBUTES); + ResourceAttributeContainer resultAttributes = resourceAttributesContainer.clone(); + accessChecker.filterGetAttributes(resultAttributes, ctx.computeCompositeObjectClassDefinition(auxObjectClassQNames), parentResult); + resultShadow.add(resultAttributes); + + resultShadowType.setIgnored(resourceShadowType.isIgnored()); + + resultShadowType.setActivation(resourceShadowType.getActivation()); + + ShadowType resultAccountShadow = resultShadow.asObjectable(); + ShadowType resourceAccountShadow = resourceShadow.asObjectable(); + + // Credentials + resultAccountShadow.setCredentials(resourceAccountShadow.getCredentials()); + transplantPasswordMetadata(repoShadowType, resultAccountShadow); + + // protected + ProvisioningUtil.setProtectedFlag(ctx, resultShadow, matchingRuleRegistry, relationRegistry); + + // exists, dead + // This may seem strange, but always take exists and dead flags from the repository. + // Repository is wiser in this case. It may seem that the shadow exists if it is returned + // by the resource. But that may be just a quantum illusion (gestation and corpse shadow states). + + // Activation + ActivationType resultActivationType = resultShadowType.getActivation(); + ActivationType repoActivation = repoShadowType.getActivation(); + if (repoActivation != null) { + if (resultActivationType == null) { + resultActivationType = new ActivationType(); + resultShadowType.setActivation(resultActivationType); + } + resultActivationType.setId(repoActivation.getId()); + // .. but we want metadata from repo + resultActivationType.setDisableReason(repoActivation.getDisableReason()); + resultActivationType.setEnableTimestamp(repoActivation.getEnableTimestamp()); + resultActivationType.setDisableTimestamp(repoActivation.getDisableTimestamp()); + resultActivationType.setArchiveTimestamp(repoActivation.getArchiveTimestamp()); + resultActivationType.setValidityChangeTimestamp(repoActivation.getValidityChangeTimestamp()); + } + + // Associations + PrismContainer resourceAssociationContainer = resourceShadow + .findContainer(ShadowType.F_ASSOCIATION); + if (resourceAssociationContainer != null) { + PrismContainer associationContainer = resourceAssociationContainer.clone(); + resultShadow.addReplaceExisting(associationContainer); + completeAssociations(ctx, resourceShadow, repoShadow, isDoDiscovery, associationContainer, parentResult); + } + + resultShadowType.setCachingMetadata(resourceShadowType.getCachingMetadata()); + + // Sanity asserts to catch some exotic bugs + PolyStringType resultName = resultShadow.asObjectable().getName(); + assert resultName != null : "No name generated in " + resultShadow; + assert !StringUtils.isEmpty(resultName.getOrig()) : "No name (orig) in " + resultShadow; + assert !StringUtils.isEmpty(resultName.getNorm()) : "No name (norm) in " + resultShadow; + + return resultShadow; + } + + private void completeAssociations(ProvisioningContext ctx, PrismObject resourceShadow, PrismObject repoShadow, boolean isDoDiscovery, PrismContainer associationContainer, OperationResult parentResult) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, ExpressionEvaluationException, SecurityViolationException, EncryptionException { + if (associationContainer == null) { + return; + } + + Iterator> iterator = associationContainer.getValues().iterator(); + while (iterator.hasNext()) { + PrismContainerValue associationCVal = iterator.next(); + + ResourceAttributeContainer identifierContainer = ShadowUtil.getAttributesContainer(associationCVal, ShadowAssociationType.F_IDENTIFIERS); + Collection> entitlementIdentifiers = identifierContainer.getAttributes(); + if (entitlementIdentifiers == null || entitlementIdentifiers.isEmpty()) { + throw new IllegalStateException("No entitlement identifiers present for association " + associationCVal + " " + ctx.getDesc()); + } + ShadowAssociationType shadowAssociationType = associationCVal.asContainerable(); + QName associationName = shadowAssociationType.getName(); + RefinedAssociationDefinition rEntitlementAssociationDef = ctx.getObjectClassDefinition().findAssociationDefinition(associationName); + if (rEntitlementAssociationDef == null) { + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("Entitlement association with name {} couldn't be found in {} {}\nresource shadow:\n{}\nrepo shadow:\n{}", + associationName, ctx.getObjectClassDefinition(), ctx.getDesc(), + resourceShadow.debugDump(1), repoShadow == null ? null : repoShadow.debugDump(1)); + LOGGER.trace("Full refined definition: {}", ctx.getObjectClassDefinition().debugDump()); + } + throw new SchemaException("Entitlement association with name " + associationName + + " couldn't be found in " + ctx.getObjectClassDefinition() + " " + ctx.getDesc() + ", with using shadow coordinates " + ctx.isUseRefinedDefinition()); + } + ShadowKindType entitlementKind = rEntitlementAssociationDef.getKind(); + if (entitlementKind == null) { + entitlementKind = ShadowKindType.ENTITLEMENT; + } + + for (String entitlementIntent : rEntitlementAssociationDef.getIntents()) { + ProvisioningContext ctxEntitlement = ctx.spawn(entitlementKind, entitlementIntent); + + PrismObject entitlementRepoShadow; + PrismObject entitlementShadow = identifierContainer.getUserData(ResourceObjectConverter.FULL_SHADOW_KEY); + if (entitlementShadow == null) { + try { + entitlementRepoShadow = shadowManager.lookupShadowInRepository(ctxEntitlement, identifierContainer, parentResult); + if (entitlementRepoShadow == null) { + + entitlementShadow = resourceObjectConverter.locateResourceObject(ctxEntitlement, entitlementIdentifiers, parentResult); + + // Try to look up repo shadow again, this time with full resource shadow. When we + // have searched before we might have only some identifiers. The shadow + // might still be there, but it may be renamed + entitlementRepoShadow = acquireRepositoryShadow(ctxEntitlement, entitlementShadow, false, isDoDiscovery, parentResult); + } + } catch (ObjectNotFoundException e) { + // The entitlement to which we point is not there. + // Simply ignore this association value. + parentResult.muteLastSubresultError(); + LOGGER.warn("The entitlement identified by {} referenced from {} does not exist. Skipping.", associationCVal, resourceShadow); + continue; + } catch (SchemaException e) { + // The entitlement to which we point is not bad. + // Simply ignore this association value. + parentResult.muteLastSubresultError(); + LOGGER.warn("The entitlement identified by {} referenced from {} violates the schema. Skipping. Original error: {}-{}", + associationCVal, resourceShadow, e.getMessage(), e); + continue; + } + } else { + entitlementRepoShadow = acquireRepositoryShadow(ctxEntitlement, + entitlementShadow, false, isDoDiscovery, parentResult); + } + if (doesAssociationMatch(rEntitlementAssociationDef, entitlementRepoShadow)) { + ObjectReferenceType shadowRefType = ObjectTypeUtil.createObjectRef(entitlementRepoShadow, prismContext); + shadowAssociationType.setShadowRef(shadowRefType); + } else { + // We have association value that does not match its definition. This may happen because the association attribute + // may be shared among several associations. The EntitlementConverter code has no way to tell them apart. + // We can do that only if we have shadow or full resource object. And that is available at this point only. + // Therefore just silently filter out the association values that do not belong here. + // See MID-5790 + iterator.remove(); + } + } + } + } + + private boolean doesAssociationMatch(RefinedAssociationDefinition rEntitlementAssociationDef, PrismObject entitlementRepoShadow) { + ShadowKindType shadowKind = ShadowUtil.getKind(entitlementRepoShadow.asObjectable()); + String shadowIntent = ShadowUtil.getIntent(entitlementRepoShadow.asObjectable()); + if (shadowKind == null || shadowKind == ShadowKindType.UNKNOWN || shadowIntent == null) { + // We have unclassified shadow here. This should not happen in a well-configured system. But the world is a tough place. + // In case that this happens let's just keep all such shadows in all associations. This is how midPoint worked before, + // therefore we will get better compatibility. But it is also better for visibility. MidPoint will show data that are + // wrong. But it will at least show something. The alternative would be to show nothing, which is not really friendly + // for debugging. + return true; + } + ShadowKindType defKind = rEntitlementAssociationDef.getKind(); + if (defKind == null) { + defKind = ShadowKindType.ENTITLEMENT; + } + if (!defKind.equals(shadowKind)) { + return false; + } + Collection defIntents = rEntitlementAssociationDef.getIntents(); + if (!defIntents.contains(shadowIntent)) { + return false; + } + return true; + } + + private void transplantPasswordMetadata(ShadowType repoShadowType, ShadowType resultAccountShadow) { + CredentialsType repoCreds = repoShadowType.getCredentials(); + if (repoCreds == null) { + return; + } + PasswordType repoPassword = repoCreds.getPassword(); + if (repoPassword == null) { + return; + } + MetadataType repoMetadata = repoPassword.getMetadata(); + if (repoMetadata == null) { + return; + } + CredentialsType resultCreds = resultAccountShadow.getCredentials(); + if (resultCreds == null) { + resultCreds = new CredentialsType(); + resultAccountShadow.setCredentials(resultCreds); + } + PasswordType resultPassword = resultCreds.getPassword(); + if (resultPassword == null) { + resultPassword = new PasswordType(); + resultCreds.setPassword(resultPassword); + } + MetadataType resultMetadata = resultPassword.getMetadata(); + if (resultMetadata == null) { + resultMetadata = repoMetadata.clone(); + resultPassword.setMetadata(resultMetadata); + } + } + + // ENTITLEMENTS + + /** + * Makes sure that all the entitlements have identifiers in them so this is + * usable by the ResourceObjectConverter. + */ + private void preprocessEntitlements(final ProvisioningContext ctx, final PrismObject shadow, + final OperationResult result) throws SchemaException, ObjectNotFoundException, + ConfigurationException, CommunicationException, ExpressionEvaluationException { + try { + shadow.accept( + (visitable) -> { + try { + preprocessEntitlement(ctx, (PrismContainerValue) visitable, + shadow.toString(), result); + } catch (SchemaException | ObjectNotFoundException | ConfigurationException + | CommunicationException | ExpressionEvaluationException e) { + throw new TunnelException(e); + } + }, + ItemPath.create(ShadowType.F_ASSOCIATION, null), false); + } catch (TunnelException e) { + Throwable cause = e.getCause(); + if (cause instanceof SchemaException) { + throw (SchemaException) cause; + } else if (cause instanceof ObjectNotFoundException) { + throw (ObjectNotFoundException) cause; + } else if (cause instanceof ConfigurationException) { + throw (ConfigurationException) cause; + } else if (cause instanceof CommunicationException) { + throw (CommunicationException) cause; + } else if (cause instanceof ExpressionEvaluationException) { + throw (ExpressionEvaluationException) cause; + } else { + throw new SystemException("Unexpected exception " + cause, cause); + } + } + } + + /** + * Makes sure that all the entitlements have identifiers in them so this is + * usable by the ResourceObjectConverter. + */ + private void preprocessEntitlements(final ProvisioningContext ctx, + Collection modifications, final String desc, final OperationResult result) + throws SchemaException, ObjectNotFoundException, ConfigurationException, + CommunicationException, ExpressionEvaluationException { + try { + ItemDeltaCollectionsUtil.accept(modifications, + (visitable) -> { + try { + preprocessEntitlement(ctx, (PrismContainerValue) visitable, desc, + result); + } catch (SchemaException | ObjectNotFoundException | ConfigurationException + | CommunicationException | ExpressionEvaluationException e) { + throw new TunnelException(e); + } + }, + ItemPath.create(ShadowType.F_ASSOCIATION, null), false); + } catch (TunnelException e) { + Throwable cause = e.getCause(); + if (cause instanceof SchemaException) { + throw (SchemaException) cause; + } else if (cause instanceof ObjectNotFoundException) { + throw (ObjectNotFoundException) cause; + } else if (cause instanceof ConfigurationException) { + throw (ConfigurationException) cause; + } else if (cause instanceof CommunicationException) { + throw (CommunicationException) cause; + } else if (cause instanceof ExpressionEvaluationException) { + throw (ExpressionEvaluationException) cause; + } else { + throw new SystemException("Unexpected exception " + cause, cause); + } + } + } + + private void preprocessEntitlement(ProvisioningContext ctx, + PrismContainerValue association, String desc, OperationResult result) + throws SchemaException, ObjectNotFoundException, ConfigurationException, + CommunicationException, ExpressionEvaluationException { + PrismContainer identifiersContainer = association + .findContainer(ShadowAssociationType.F_IDENTIFIERS); + if (identifiersContainer != null && !identifiersContainer.isEmpty()) { + // We already have identifiers here + return; + } + ShadowAssociationType associationType = association.asContainerable(); + LOGGER.info("###Shadow association: {}, class: {}", associationType.getName(), associationType.getName().getClass()); + if (associationType.getShadowRef() == null + || StringUtils.isEmpty(associationType.getShadowRef().getOid())) { + throw new SchemaException( + "No identifiers and no OID specified in entitlements association " + association); + } + PrismObject repoShadow; + try { + repoShadow = repositoryService.getObject(ShadowType.class, + associationType.getShadowRef().getOid(), null, result); + } catch (ObjectNotFoundException e) { + throw new ObjectNotFoundException(e.getMessage() + + " while resolving entitlement association OID in " + association + " in " + desc, e); + } + shadowCaretaker.applyAttributesDefinition(ctx, repoShadow); + transplantIdentifiers(association, repoShadow); + } + + private void transplantIdentifiers(PrismContainerValue association, + PrismObject repoShadow) throws SchemaException { + PrismContainer identifiersContainer = association + .findContainer(ShadowAssociationType.F_IDENTIFIERS); + if (identifiersContainer == null) { + ResourceAttributeContainer origContainer = ShadowUtil.getAttributesContainer(repoShadow); + identifiersContainer = ObjectFactory.createResourceAttributeContainer(ShadowAssociationType.F_IDENTIFIERS, + origContainer.getDefinition(), prismContext); + association.add(identifiersContainer); + } + Collection> identifiers = ShadowUtil.getPrimaryIdentifiers(repoShadow); + for (ResourceAttribute identifier : identifiers) { + identifiersContainer.add(identifier.clone()); + } + Collection> secondaryIdentifiers = ShadowUtil + .getSecondaryIdentifiers(repoShadow); + for (ResourceAttribute identifier : secondaryIdentifiers) { + identifiersContainer.add(identifier.clone()); + } + } + + public void propagateOperations(PrismObject resource, PrismObject shadow, Task task, OperationResult result) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException, GenericFrameworkException, ObjectAlreadyExistsException, SecurityViolationException, PolicyViolationException, EncryptionException { + ResourceConsistencyType resourceConsistencyType = resource.asObjectable().getConsistency(); + if (resourceConsistencyType == null) { + LOGGER.warn("Skipping propagation of {} because no there is no consistency definition in resource", shadow); + return; + } + Duration operationGroupingInterval = resourceConsistencyType.getOperationGroupingInterval(); + if (operationGroupingInterval == null) { + LOGGER.warn("Skipping propagation of {} because no there is no operationGroupingInterval defined in resource", shadow); + return; + } + XMLGregorianCalendar now = clock.currentTimeXMLGregorianCalendar(); + + List pendingExecutionOperations = new ArrayList<>(); + boolean triggered = false; + for (PendingOperationType pendingOperation: shadow.asObjectable().getPendingOperation()) { + PendingOperationExecutionStatusType executionStatus = pendingOperation.getExecutionStatus(); + if (executionStatus == PendingOperationExecutionStatusType.EXECUTION_PENDING) { + pendingExecutionOperations.add(pendingOperation); + if (isPropagationTriggered(pendingOperation, operationGroupingInterval, now)) { + triggered = true; + } + } + } + if (!triggered) { + LOGGER.debug("Skipping propagation of {} because no pending operation triggered propagation", shadow); + return; + } + if (pendingExecutionOperations.isEmpty()) { + LOGGER.debug("Skipping propagation of {} because there are no pending executions", shadow); + return; + } + LOGGER.debug("Propagating {} pending operations in {} ", pendingExecutionOperations.size(), shadow); + + ObjectDelta operationDelta = null; + List sortedOperations = shadowCaretaker.sortPendingOperations(pendingExecutionOperations); + for (PendingOperationType pendingOperation: sortedOperations) { + ObjectDeltaType pendingDeltaType = pendingOperation.getDelta(); + ObjectDelta pendingDelta = DeltaConvertor.createObjectDelta(pendingDeltaType, prismContext); + applyDefinition(pendingDelta, shadow.asObjectable(), result); + if (operationDelta == null) { + operationDelta = pendingDelta; + } else { + operationDelta.merge(pendingDelta); + } + } + + ProvisioningContext ctx = ctxFactory.create(shadow, task, result); + ctx.setPropagation(true); + shadowCaretaker.applyAttributesDefinition(ctx, shadow); + shadowCaretaker.applyAttributesDefinition(ctx, operationDelta); + LOGGER.trace("Merged operation for {}:\n{} ", shadow, operationDelta.debugDumpLazily(1)); + + if (operationDelta.isAdd()) { + PrismObject shadowToAdd = operationDelta.getObjectToAdd(); + ProvisioningOperationState>> opState = + ProvisioningOperationState.fromPendingOperations(shadow, sortedOperations); + shadowToAdd.setOid(shadow.getOid()); + addShadowAttempt(ctx, shadowToAdd, null, opState, null, task, result); + opState.determineExecutionStatusFromResult(); + + shadowManager.updatePendingOperations(ctx, shadow, opState, pendingExecutionOperations, now, result); + + notifyAfterAdd(ctx, opState.getAsyncResult().getReturnValue(), opState, task, result); + + } else if (operationDelta.isModify()) { + Collection> modifications = operationDelta.getModifications(); + ProvisioningOperationState>>> opState = + executeResourceModify(ctx, shadow, modifications, null, null, now, task, result); + opState.determineExecutionStatusFromResult(); + + shadowManager.updatePendingOperations(ctx, shadow, opState, pendingExecutionOperations, now, result); + + notifyAfterModify(ctx, shadow, modifications, opState, task, result); + + } else if (operationDelta.isDelete()) { + ProvisioningOperationState opState = executeResourceDelete(ctx, shadow, null, null, task, result); + opState.determineExecutionStatusFromResult(); + + shadowManager.updatePendingOperations(ctx, shadow, opState, pendingExecutionOperations, now, result); + + notifyAfterDelete(ctx, shadow, opState, task, result); + + } else { + throw new IllegalStateException("Delta from outer space: "+operationDelta); + } + + // do we need to modify exists/dead flags? + + } + + private boolean isPropagationTriggered(PendingOperationType pendingOperation, Duration operationGroupingInterval, XMLGregorianCalendar now) { + XMLGregorianCalendar requestTimestamp = pendingOperation.getRequestTimestamp(); + if (requestTimestamp == null) { + return false; + } + return XmlTypeConverter.isAfterInterval(requestTimestamp, operationGroupingInterval, now); + } + + public ItemComparisonResult compare(PrismObject repositoryShadow, ItemPath path, T expectedValue, Task task, OperationResult parentResult) + throws ObjectNotFoundException, CommunicationException, SchemaException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException, EncryptionException { + + if (!path.equivalent(SchemaConstants.PATH_PASSWORD_VALUE)) { + throw new UnsupportedOperationException("Only password comparison is supported"); + } + + ProvisioningContext ctx = ctxFactory.create(repositoryShadow, task, parentResult); + try { + ctx.assertDefinition(); + shadowCaretaker.applyAttributesDefinition(ctx, repositoryShadow); + } catch (ObjectNotFoundException | SchemaException | CommunicationException + | ConfigurationException | ExpressionEvaluationException e) { + throw e; + } + + ResourceType resource = ctx.getResource(); + + PasswordCompareStrategyType passwordCompareStrategy = getPasswordCompareStrategy(ctx.getObjectClassDefinition()); + if (passwordCompareStrategy == PasswordCompareStrategyType.ERROR) { + throw new UnsupportedOperationException("Password comparison is not supported on "+resource); + } + + PrismProperty repoProperty = repositoryShadow.findProperty(path); + if (repoProperty == null) { + if (passwordCompareStrategy == PasswordCompareStrategyType.CACHED) { + if (expectedValue == null) { + return ItemComparisonResult.MATCH; + } else { + return ItemComparisonResult.MISMATCH; + } + } else { + // AUTO + return ItemComparisonResult.NOT_APPLICABLE; + } + } + + ProtectedStringType repoProtectedString = (ProtectedStringType) repoProperty.getRealValue(); + ProtectedStringType expectedProtectedString; + if (expectedValue instanceof ProtectedStringType) { + expectedProtectedString = (ProtectedStringType) expectedValue; + } else { + expectedProtectedString = new ProtectedStringType(); + expectedProtectedString.setClearValue((String) expectedValue); + } + if (protector.compareCleartext(repoProtectedString, expectedProtectedString)) { + return ItemComparisonResult.MATCH; + } else { + return ItemComparisonResult.MISMATCH; + } + } + + private PasswordCompareStrategyType getPasswordCompareStrategy(RefinedObjectClassDefinition objectClassDefinition) { + ResourcePasswordDefinitionType passwordDefinition = objectClassDefinition.getPasswordDefinition(); + if (passwordDefinition == null) { + return null; + } + return passwordDefinition.getCompareStrategy(); + } + + private ConnectorOperationOptions createConnectorOperationOptions(ProvisioningContext ctx, ProvisioningOperationOptions options, OperationResult result) throws SchemaException, ConfigurationException, ObjectNotFoundException, CommunicationException, ExpressionEvaluationException { + if (options == null) { + return null; + } + String runAsAccountOid = options.getRunAsAccountOid(); + if (runAsAccountOid == null) { + return null; + } + RunAsCapabilityType capRunAs = ctx.getEffectiveCapability(RunAsCapabilityType.class); + if (capRunAs == null) { + LOGGER.trace("Operation runAs requested, but resource does not have the capability. Ignoring runAs"); + return null; + } + PrismObject runAsShadow; + try { + runAsShadow = shadowManager.getRepoShadow(runAsAccountOid, result); + } catch (ObjectNotFoundException e) { + throw new ConfigurationException("Requested non-existing 'runAs' shadow", e); + } + ProvisioningContext runAsCtx = ctxFactory.create(runAsShadow, null, ctx.getTask(), result); + shadowCaretaker.applyAttributesDefinition(runAsCtx, runAsShadow); + ResourceObjectIdentification runAsIdentification = ResourceObjectIdentification.createFromShadow(runAsCtx.getObjectClassDefinition(), runAsShadow.asObjectable()); + ConnectorOperationOptions connOptions = new ConnectorOperationOptions(); + LOGGER.trace("RunAs identification: {}", runAsIdentification); + connOptions.setRunAsIdentification(runAsIdentification); + return connOptions; + } + + private String getAdditionalOperationDesc(OperationProvisioningScriptsType scripts, + ProvisioningOperationOptions options) { + if (scripts == null && options == null) { + return ""; + } + StringBuilder sb = new StringBuilder(" ("); + if (options != null) { + sb.append("options:"); + options.shortDump(sb); + if (scripts != null) { + sb.append("; "); + } + } + if (scripts != null) { + sb.append("scripts"); + } + sb.append(")"); + return sb.toString(); + } + +} diff --git a/provisioning/ucf-impl-builtin/src/main/java/com/evolveum/midpoint/provisioning/ucf/impl/builtin/ManualConnectorInstance.java b/provisioning/ucf-impl-builtin/src/main/java/com/evolveum/midpoint/provisioning/ucf/impl/builtin/ManualConnectorInstance.java index 083bcf296f6..f6f9af96081 100644 --- a/provisioning/ucf-impl-builtin/src/main/java/com/evolveum/midpoint/provisioning/ucf/impl/builtin/ManualConnectorInstance.java +++ b/provisioning/ucf-impl-builtin/src/main/java/com/evolveum/midpoint/provisioning/ucf/impl/builtin/ManualConnectorInstance.java @@ -1,407 +1,409 @@ -/* - * Copyright (c) 2017-2019 Evolveum and contributors - * - * This work is dual-licensed under the Apache License 2.0 - * and European Union Public License. See LICENSE file for details. - */ -package com.evolveum.midpoint.provisioning.ucf.impl.builtin; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Random; -import java.util.stream.Collectors; - -import com.evolveum.midpoint.common.Clock; -import com.evolveum.midpoint.casemgmt.api.CaseEventDispatcher; -import com.evolveum.midpoint.casemgmt.api.CaseEventDispatcherAware; -import com.evolveum.midpoint.prism.PrismObject; -import com.evolveum.midpoint.prism.delta.DeltaFactory; -import com.evolveum.midpoint.prism.delta.ItemDelta; -import com.evolveum.midpoint.prism.delta.ObjectDelta; -import com.evolveum.midpoint.prism.path.ItemPath; -import com.evolveum.midpoint.prism.query.ObjectQuery; -import com.evolveum.midpoint.prism.util.CloneUtil; -import com.evolveum.midpoint.provisioning.ucf.api.*; -import com.evolveum.midpoint.provisioning.ucf.api.connectors.AbstractManualConnectorInstance; -import com.evolveum.midpoint.repo.api.RepositoryAware; -import com.evolveum.midpoint.repo.api.RepositoryService; -import com.evolveum.midpoint.schema.DeltaConvertor; -import com.evolveum.midpoint.schema.constants.ConnectorTestOperation; -import com.evolveum.midpoint.schema.constants.ObjectTypes; -import com.evolveum.midpoint.schema.constants.SchemaConstants; -import com.evolveum.midpoint.schema.internals.InternalMonitor; -import com.evolveum.midpoint.schema.internals.InternalsConfig; -import com.evolveum.midpoint.schema.processor.ObjectClassComplexTypeDefinition; -import com.evolveum.midpoint.schema.processor.ResourceAttribute; -import com.evolveum.midpoint.schema.result.OperationResult; -import com.evolveum.midpoint.schema.result.OperationResultStatus; -import com.evolveum.midpoint.schema.util.ObjectTypeUtil; -import com.evolveum.midpoint.schema.util.OidUtil; -import com.evolveum.midpoint.schema.util.ShadowUtil; -import com.evolveum.midpoint.task.api.TaskManager; -import com.evolveum.midpoint.task.api.TaskManagerAware; -import com.evolveum.midpoint.util.DebugUtil; -import com.evolveum.midpoint.util.MiscUtil; -import com.evolveum.midpoint.util.QNameUtil; -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.*; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType; -import com.evolveum.prism.xml.ns._public.types_3.*; - -import javax.xml.datatype.XMLGregorianCalendar; - -/** - * @author Radovan Semancik - * - */ -@ManagedConnector(type="ManualConnector", version="1.0.0") -public class ManualConnectorInstance extends AbstractManualConnectorInstance implements RepositoryAware, - CaseEventDispatcherAware, TaskManagerAware { - - private static final String OPERATION_QUERY_CASE = ManualConnectorInstance.class.getName() + ".queryCase"; - - private static final Trace LOGGER = TraceManager.getTrace(ManualConnectorInstance.class); - - private ManualConnectorConfiguration configuration; - - private RepositoryService repositoryService; - private CaseEventDispatcher caseEventDispatcher; - private TaskManager taskManager; - - private boolean connected = false; - - private static int randomDelayRange = 0; - - private static final String DEFAULT_OPERATOR_OID = SystemObjectsType.USER_ADMINISTRATOR.value(); - - private static final Random RND = new Random(); - - private Clock clock = new Clock(); - - @ManagedConnectorConfiguration - public ManualConnectorConfiguration getConfiguration() { - return configuration; - } - - public void setConfiguration(ManualConnectorConfiguration configuration) { - this.configuration = configuration; - } - - public boolean isConnected() { - return connected; - } - - @Override - public RepositoryService getRepositoryService() { - return repositoryService; - } - - @Override - public void setRepositoryService(RepositoryService repositoryService) { - this.repositoryService = repositoryService; - } - - @Override - public void setDispatcher(CaseEventDispatcher dispatcher) { - this.caseEventDispatcher = dispatcher; - } - - @Override - public CaseEventDispatcher getDispatcher() { - return caseEventDispatcher; - } - - @Override - public void setTaskManager(TaskManager taskManager) { - this.taskManager = taskManager; - } - - @Override - public TaskManager getTaskManager() { - return taskManager; - } - - @Override - protected String createTicketAdd(PrismObject object, OperationResult result) throws SchemaException, - ObjectAlreadyExistsException { - LOGGER.debug("Creating case to add account\n{}", object.debugDump(1)); - ObjectDelta objectDelta = DeltaFactory.Object.createAddDelta(object); - ObjectDeltaType objectDeltaType = DeltaConvertor.toObjectDeltaType(objectDelta); - String shadowName; - if (object.getName() != null) { - shadowName = object.getName().toString(); - } else { - shadowName = getShadowIdentifier(ShadowUtil.getPrimaryIdentifiers(object)); - } - String description = "Please create resource account: "+shadowName; - PrismObject aCase = addCase("create", description, ShadowUtil.getResourceOid(object.asObjectable()), - shadowName, null, objectDeltaType, result); - return aCase.getOid(); - } - - @Override - protected String createTicketModify(ObjectClassComplexTypeDefinition objectClass, - PrismObject shadow, Collection> identifiers, String resourceOid, Collection changes, - OperationResult result) throws SchemaException, ObjectAlreadyExistsException { - LOGGER.debug("Creating case to modify account {}:\n{}", identifiers, DebugUtil.debugDumpLazily(changes, 1)); - if (InternalsConfig.isSanityChecks()) { - if (MiscUtil.hasDuplicates(changes)) { - throw new SchemaException("Duplicated changes: "+changes); - } - } - Collection changeDeltas = changes.stream() - .filter(change -> change != null) - .map(change -> ((PropertyModificationOperation)change).getPropertyDelta()) - .collect(Collectors.toList()); - ObjectDelta objectDelta = getPrismContext().deltaFactory().object() - .createModifyDelta("", changeDeltas, ShadowType.class); - ObjectDeltaType objectDeltaType = DeltaConvertor.toObjectDeltaType(objectDelta); - objectDeltaType.setOid(shadow.getOid()); - String shadowName = shadow.getName().toString(); - String description = "Please modify resource account: "+shadowName; - PrismObject aCase = addCase("modify", description, resourceOid, shadowName, - shadow.getOid(), objectDeltaType, result); - return aCase.getOid(); - } - - @Override - protected String createTicketDelete(ObjectClassComplexTypeDefinition objectClass, - PrismObject shadow, Collection> identifiers, String resourceOid, OperationResult result) - throws SchemaException { - LOGGER.debug("Creating case to delete account {}", identifiers); - String shadowName = shadow.getName().toString(); - String description = "Please delete resource account: "+shadowName; - ObjectDeltaType objectDeltaType = new ObjectDeltaType(); - objectDeltaType.setChangeType(ChangeTypeType.DELETE); - objectDeltaType.setObjectType(ShadowType.COMPLEX_TYPE); - ItemDeltaType itemDeltaType = new ItemDeltaType(); - itemDeltaType.setPath(new ItemPathType(ItemPath.create("kind"))); - itemDeltaType.setModificationType(ModificationTypeType.DELETE); - objectDeltaType.setOid(shadow.getOid()); - - objectDeltaType.getItemDelta().add(itemDeltaType); - PrismObject aCase; - try { - aCase = addCase("delete", description, resourceOid, shadowName, shadow.getOid(), objectDeltaType, result); - } catch (ObjectAlreadyExistsException e) { - // should not happen - throw new SystemException(e.getMessage(), e); - } - return aCase.getOid(); - } - - private PrismObject addCase(String operation, String description, String resourceOid, String shadowName, String shadowOid, - ObjectDeltaType objectDelta, OperationResult result) throws SchemaException, ObjectAlreadyExistsException { - PrismObject aCase = getPrismContext().createObject(CaseType.class); - CaseType caseType = aCase.asObjectable(); - - if (randomDelayRange != 0) { - int waitMillis = RND.nextInt(randomDelayRange); - LOGGER.info("Manual connector waiting {} ms before creating the case", waitMillis); - try { - Thread.sleep(waitMillis); - } catch (InterruptedException e) { - LOGGER.error("Manual connector wait is interrupted"); - } - LOGGER.info("Manual connector wait is over"); - } - - PrismObject resource; - try { - resource = repositoryService.getObject(ResourceType.class, resourceOid, null, result); - } catch (ObjectNotFoundException e) { - // We do not signal this as ObjectNotFoundException as it could be misinterpreted as "shadow - // object not found" with subsequent handling as such. - throw new SystemException("Resource " + resourceOid + " couldn't be found", e); - } - ResourceBusinessConfigurationType businessConfiguration = resource.asObjectable().getBusiness(); - List operators = new ArrayList<>(); - if (businessConfiguration != null) { - operators.addAll(businessConfiguration.getOperatorRef()); - } - if (operators.isEmpty() && configuration.getDefaultAssignee() != null) { - ObjectQuery query = getPrismContext().queryFor(UserType.class) - .item(UserType.F_NAME).eq(configuration.getDefaultAssignee()).matchingOrig() - .build(); - List> defaultAssignees = repositoryService - .searchObjects(UserType.class, query, null, result); - if (defaultAssignees.isEmpty()) { - LOGGER.warn("Default assignee named '{}' was not found; using system-wide default instead.", - configuration.getDefaultAssignee()); - } else { - assert defaultAssignees.size() == 1; - operators.addAll(ObjectTypeUtil.objectListToReferences(defaultAssignees)); - } - } - if (operators.isEmpty()) { - operators.add(new ObjectReferenceType().oid(DEFAULT_OPERATOR_OID).type(UserType.COMPLEX_TYPE)); - } - - String caseOid = OidUtil.generateOid(); - - caseType.setOid(caseOid); - String caseName = String.format("Request to %s '%s' on '%s'", operation, shadowName, resource.getName().getOrig()); - caseType.setName(new PolyStringType(caseName)); - - caseType.setDescription(description); - - caseType.setState(SchemaConstants.CASE_STATE_CREATED); // Case opening process will be completed by WorkflowEngine - - caseType.setObjectRef(new ObjectReferenceType().oid(resourceOid).type(ResourceType.COMPLEX_TYPE)); - - caseType.setTargetRef(new ObjectReferenceType().oid(shadowOid).targetName(shadowName).type(ShadowType.COMPLEX_TYPE)); - - // deprecated "objectChange" element was removed in midPoint 4.0. - // TODO: record operation as pending operation delta - - ObjectReferenceType archetypeRef = ObjectTypeUtil - .createObjectRef(SystemObjectsType.ARCHETYPE_MANUAL_CASE.value(), ObjectTypes.ARCHETYPE); - caseType.getArchetypeRef().add(archetypeRef.clone()); - caseType.beginAssignment().targetRef(archetypeRef).end(); - - XMLGregorianCalendar now = clock.currentTimeXMLGregorianCalendar(); - caseType.beginMetadata().setCreateTimestamp(now); - - XMLGregorianCalendar deadline; - if (businessConfiguration != null && businessConfiguration.getOperatorActionMaxDuration() != null) { - deadline = CloneUtil.clone(now); - deadline.add(businessConfiguration.getOperatorActionMaxDuration()); - } else { - deadline = null; - } - - for (ObjectReferenceType operator : operators) { - CaseWorkItemType workItem = new CaseWorkItemType(getPrismContext()) - .originalAssigneeRef(operator.clone()) - .assigneeRef(operator.clone()) - .name(caseType.getName()) - .createTimestamp(now) - .deadline(deadline); - caseType.getWorkItem().add(workItem); - } - - // TODO: case payload - // TODO: a lot of other things - - // TODO: move to case-manager - - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("CREATING CASE:\n{}", aCase.debugDump(1)); - } - - repositoryService.addObject(aCase, null, result); - - // notifications - caseEventDispatcher.dispatchCaseEvent(caseType, result); - return aCase; - } - - @Override - public OperationResultStatus queryOperationStatus(String asynchronousOperationReference, OperationResult parentResult) throws ObjectNotFoundException, SchemaException { - OperationResult result = parentResult.createMinorSubresult(OPERATION_QUERY_CASE); - - InternalMonitor.recordConnectorOperation("queryOperationStatus"); - - PrismObject acase; - try { - acase = repositoryService.getObject(CaseType.class, asynchronousOperationReference, null, result); - } catch (ObjectNotFoundException | SchemaException e) { - result.recordFatalError(e); - throw e; - } - - CaseType caseType = acase.asObjectable(); - String state = caseType.getState(); - - // States "open" and "created" are the same from the factual point of view - // They differ only in level of processing carried out by workflow manager (audit, notifications, etc). - if (QNameUtil.matchWithUri(SchemaConstants.CASE_STATE_OPEN_QNAME, state) - || QNameUtil.matchWithUri(SchemaConstants.CASE_STATE_CREATED_QNAME, state)) { - result.recordSuccess(); - return OperationResultStatus.IN_PROGRESS; - } else if (QNameUtil.matchWithUri(SchemaConstants.CASE_STATE_CLOSED_QNAME, state) - || QNameUtil.matchWithUri(SchemaConstants.CASE_STATE_CLOSING_QNAME, state)) { - String outcome = caseType.getOutcome(); - OperationResultStatus status = translateOutcome(outcome); - result.recordSuccess(); - return status; - } else { - SchemaException e = new SchemaException("Unknown case state "+state); - result.recordFatalError(e); - throw e; - } - - } - - // see CompleteWorkItemsAction.getOutcome(..) method - private OperationResultStatus translateOutcome(String outcome) { - - // TODO: better algorithm - if (outcome == null) { - return null; - } else if (outcome.equals(OperationResultStatusType.SUCCESS.value())) { - return OperationResultStatus.SUCCESS; - } else { - return OperationResultStatus.UNKNOWN; - } - } - - @Override - protected void connect(OperationResult result) { - if (connected && InternalsConfig.isSanityChecks()) { - throw new IllegalStateException("Double connect in "+this); - } - connected = true; - // Nothing else to do - } - - private String getShadowIdentifier(Collection> identifiers){ - try { - Object[] shadowIdentifiers = identifiers.toArray(); - - return ((ResourceAttribute)shadowIdentifiers[0]).getValue().getValue().toString(); - } catch (NullPointerException e){ - return ""; - } - } - - @Override - public void test(OperationResult parentResult) { - OperationResult connectionResult = parentResult - .createSubresult(ConnectorTestOperation.CONNECTOR_CONNECTION.getOperation()); - connectionResult.addContext(OperationResult.CONTEXT_IMPLEMENTATION_CLASS, ManualConnectorInstance.class); - connectionResult.addContext("connector", getConnectorObject().toString()); - - if (repositoryService == null) { - connectionResult.recordFatalError("No repository service"); - return; - } - - if (!connected && InternalsConfig.isSanityChecks()) { - throw new IllegalStateException("Attempt to test non-connected connector instance "+this); - } - - connectionResult.recordSuccess(); - } - - @Override - public void disconnect(OperationResult parentResult) { - connected = false; - } - - @SuppressWarnings("unused") - public static int getRandomDelayRange() { - return randomDelayRange; - } - - public static void setRandomDelayRange(int randomDelayRange) { - ManualConnectorInstance.randomDelayRange = randomDelayRange; - } - -} +/* + * Copyright (c) 2017-2019 Evolveum and contributors + * + * This work is dual-licensed under the Apache License 2.0 + * and European Union Public License. See LICENSE file for details. + */ +package com.evolveum.midpoint.provisioning.ucf.impl.builtin; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Random; +import java.util.stream.Collectors; + +import com.evolveum.midpoint.common.Clock; +import com.evolveum.midpoint.casemgmt.api.CaseEventDispatcher; +import com.evolveum.midpoint.casemgmt.api.CaseEventDispatcherAware; +import com.evolveum.midpoint.prism.PrismObject; +import com.evolveum.midpoint.prism.delta.DeltaFactory; +import com.evolveum.midpoint.prism.delta.ItemDelta; +import com.evolveum.midpoint.prism.delta.ObjectDelta; +import com.evolveum.midpoint.prism.path.ItemPath; +import com.evolveum.midpoint.prism.query.ObjectQuery; +import com.evolveum.midpoint.prism.util.CloneUtil; +import com.evolveum.midpoint.provisioning.ucf.api.*; +import com.evolveum.midpoint.provisioning.ucf.api.connectors.AbstractManualConnectorInstance; +import com.evolveum.midpoint.repo.api.RepositoryAware; +import com.evolveum.midpoint.repo.api.RepositoryService; +import com.evolveum.midpoint.schema.DeltaConvertor; +import com.evolveum.midpoint.schema.constants.ConnectorTestOperation; +import com.evolveum.midpoint.schema.constants.ObjectTypes; +import com.evolveum.midpoint.schema.constants.SchemaConstants; +import com.evolveum.midpoint.schema.internals.InternalMonitor; +import com.evolveum.midpoint.schema.internals.InternalsConfig; +import com.evolveum.midpoint.schema.processor.ObjectClassComplexTypeDefinition; +import com.evolveum.midpoint.schema.processor.ResourceAttribute; +import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.schema.result.OperationResultStatus; +import com.evolveum.midpoint.schema.util.ObjectTypeUtil; +import com.evolveum.midpoint.schema.util.OidUtil; +import com.evolveum.midpoint.schema.util.ShadowUtil; +import com.evolveum.midpoint.task.api.TaskManager; +import com.evolveum.midpoint.task.api.TaskManagerAware; +import com.evolveum.midpoint.util.DebugUtil; +import com.evolveum.midpoint.util.MiscUtil; +import com.evolveum.midpoint.util.QNameUtil; +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.*; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType; +import com.evolveum.prism.xml.ns._public.types_3.*; + +import javax.xml.datatype.XMLGregorianCalendar; + +/** + * @author Radovan Semancik + * + */ +@ManagedConnector(type="ManualConnector", version="1.0.0") +public class ManualConnectorInstance extends AbstractManualConnectorInstance implements RepositoryAware, + CaseEventDispatcherAware, TaskManagerAware { + + private static final String OPERATION_QUERY_CASE = ManualConnectorInstance.class.getName() + ".queryCase"; + + private static final Trace LOGGER = TraceManager.getTrace(ManualConnectorInstance.class); + + private ManualConnectorConfiguration configuration; + + private RepositoryService repositoryService; + private CaseEventDispatcher caseEventDispatcher; + private TaskManager taskManager; + + private boolean connected = false; + + private static int randomDelayRange = 0; + + private static final String DEFAULT_OPERATOR_OID = SystemObjectsType.USER_ADMINISTRATOR.value(); + + private static final Random RND = new Random(); + + private Clock clock = new Clock(); + + @ManagedConnectorConfiguration + public ManualConnectorConfiguration getConfiguration() { + return configuration; + } + + public void setConfiguration(ManualConnectorConfiguration configuration) { + this.configuration = configuration; + } + + public boolean isConnected() { + return connected; + } + + @Override + public RepositoryService getRepositoryService() { + return repositoryService; + } + + @Override + public void setRepositoryService(RepositoryService repositoryService) { + this.repositoryService = repositoryService; + } + + @Override + public void setDispatcher(CaseEventDispatcher dispatcher) { + this.caseEventDispatcher = dispatcher; + } + + @Override + public CaseEventDispatcher getDispatcher() { + return caseEventDispatcher; + } + + @Override + public void setTaskManager(TaskManager taskManager) { + this.taskManager = taskManager; + } + + @Override + public TaskManager getTaskManager() { + return taskManager; + } + + @Override + protected String createTicketAdd(PrismObject object, OperationResult result) throws SchemaException, + ObjectAlreadyExistsException { + LOGGER.debug("Creating case to add account\n{}", object.debugDump(1)); + ObjectDelta objectDelta = DeltaFactory.Object.createAddDelta(object); + ObjectDeltaType objectDeltaType = DeltaConvertor.toObjectDeltaType(objectDelta); + String shadowName; + if (object.getName() != null) { + shadowName = object.getName().toString(); + } else { + shadowName = getShadowIdentifier(ShadowUtil.getPrimaryIdentifiers(object)); + } + String description = "Please create resource account: "+shadowName; + PrismObject aCase = addCase("create", description, ShadowUtil.getResourceOid(object.asObjectable()), + shadowName, null, objectDeltaType, result); + return aCase.getOid(); + } + + @Override + protected String createTicketModify(ObjectClassComplexTypeDefinition objectClass, + PrismObject shadow, Collection> identifiers, String resourceOid, Collection changes, + OperationResult result) throws SchemaException, ObjectAlreadyExistsException { + LOGGER.debug("Creating case to modify account {}:\n{}", identifiers, DebugUtil.debugDumpLazily(changes, 1)); + if (InternalsConfig.isSanityChecks()) { + if (MiscUtil.hasDuplicates(changes)) { + throw new SchemaException("Duplicated changes: "+changes); + } + } + Collection changeDeltas = changes.stream() + .filter(change -> change != null) + .map(change -> ((PropertyModificationOperation)change).getPropertyDelta()) + .collect(Collectors.toList()); + ObjectDelta objectDelta = getPrismContext().deltaFactory().object() + .createModifyDelta("", changeDeltas, ShadowType.class); + ObjectDeltaType objectDeltaType = DeltaConvertor.toObjectDeltaType(objectDelta); + objectDeltaType.setOid(shadow.getOid()); + String shadowName = shadow.getName().toString(); + String description = "Please modify resource account: "+shadowName; + PrismObject aCase = addCase("modify", description, resourceOid, shadowName, + shadow.getOid(), objectDeltaType, result); + return aCase.getOid(); + } + + @Override + protected String createTicketDelete(ObjectClassComplexTypeDefinition objectClass, + PrismObject shadow, Collection> identifiers, String resourceOid, OperationResult result) + throws SchemaException { + LOGGER.debug("Creating case to delete account {}", identifiers); + String shadowName = shadow.getName().toString(); + String description = "Please delete resource account: "+shadowName; + ObjectDeltaType objectDeltaType = new ObjectDeltaType(); + objectDeltaType.setChangeType(ChangeTypeType.DELETE); + objectDeltaType.setObjectType(ShadowType.COMPLEX_TYPE); + ItemDeltaType itemDeltaType = new ItemDeltaType(); + itemDeltaType.setPath(new ItemPathType(ItemPath.create("kind"))); + itemDeltaType.setModificationType(ModificationTypeType.DELETE); + objectDeltaType.setOid(shadow.getOid()); + + objectDeltaType.getItemDelta().add(itemDeltaType); + PrismObject aCase; + try { + aCase = addCase("delete", description, resourceOid, shadowName, shadow.getOid(), objectDeltaType, result); + } catch (ObjectAlreadyExistsException e) { + // should not happen + throw new SystemException(e.getMessage(), e); + } + return aCase.getOid(); + } + + private PrismObject addCase(String operation, String description, String resourceOid, String shadowName, String shadowOid, + ObjectDeltaType objectDelta, OperationResult result) throws SchemaException, ObjectAlreadyExistsException { + PrismObject aCase = getPrismContext().createObject(CaseType.class); + CaseType caseType = aCase.asObjectable(); + + if (randomDelayRange != 0) { + int waitMillis = RND.nextInt(randomDelayRange); + LOGGER.info("Manual connector waiting {} ms before creating the case", waitMillis); + try { + Thread.sleep(waitMillis); + } catch (InterruptedException e) { + LOGGER.error("Manual connector wait is interrupted"); + } + LOGGER.info("Manual connector wait is over"); + } + + PrismObject resource; + try { + resource = repositoryService.getObject(ResourceType.class, resourceOid, null, result); + } catch (ObjectNotFoundException e) { + // We do not signal this as ObjectNotFoundException as it could be misinterpreted as "shadow + // object not found" with subsequent handling as such. + throw new SystemException("Resource " + resourceOid + " couldn't be found", e); + } + ResourceBusinessConfigurationType businessConfiguration = resource.asObjectable().getBusiness(); + List operators = new ArrayList<>(); + if (businessConfiguration != null) { + operators.addAll(businessConfiguration.getOperatorRef()); + } + if (operators.isEmpty() && configuration.getDefaultAssignee() != null) { + ObjectQuery query = getPrismContext().queryFor(UserType.class) + .item(UserType.F_NAME).eq(configuration.getDefaultAssignee()).matchingOrig() + .build(); + List> defaultAssignees = repositoryService + .searchObjects(UserType.class, query, null, result); + if (defaultAssignees.isEmpty()) { + LOGGER.warn("Default assignee named '{}' was not found; using system-wide default instead.", + configuration.getDefaultAssignee()); + } else { + assert defaultAssignees.size() == 1; + operators.addAll(ObjectTypeUtil.objectListToReferences(defaultAssignees)); + } + } + if (operators.isEmpty()) { + operators.add(new ObjectReferenceType().oid(DEFAULT_OPERATOR_OID).type(UserType.COMPLEX_TYPE)); + } + + String caseOid = OidUtil.generateOid(); + + caseType.setOid(caseOid); + String caseName = String.format("Request to %s '%s' on '%s'", operation, shadowName, resource.getName().getOrig()); + caseType.setName(new PolyStringType(caseName)); + + caseType.setDescription(description); + + caseType.setState(SchemaConstants.CASE_STATE_CREATED); // Case opening process will be completed by WorkflowEngine + + caseType.setObjectRef(new ObjectReferenceType().oid(resourceOid).type(ResourceType.COMPLEX_TYPE)); + + caseType.setTargetRef(new ObjectReferenceType().oid(shadowOid).targetName(shadowName).type(ShadowType.COMPLEX_TYPE)); + + // deprecated "objectChange" element was removed in midPoint 4.0. + // TODO: record operation as pending operation delta + + ObjectReferenceType archetypeRef = ObjectTypeUtil + .createObjectRef(SystemObjectsType.ARCHETYPE_MANUAL_CASE.value(), ObjectTypes.ARCHETYPE); + caseType.getArchetypeRef().add(archetypeRef.clone()); + caseType.beginAssignment().targetRef(archetypeRef).end(); + + XMLGregorianCalendar now = clock.currentTimeXMLGregorianCalendar(); + caseType.beginMetadata().setCreateTimestamp(now); + + XMLGregorianCalendar deadline; + if (businessConfiguration != null && businessConfiguration.getOperatorActionMaxDuration() != null) { + deadline = CloneUtil.clone(now); + deadline.add(businessConfiguration.getOperatorActionMaxDuration()); + } else { + deadline = null; + } + + for (ObjectReferenceType operator : operators) { + CaseWorkItemType workItem = new CaseWorkItemType(getPrismContext()) + .originalAssigneeRef(operator.clone()) + .assigneeRef(operator.clone()) + .name(caseType.getName()) + .createTimestamp(now) + .deadline(deadline); + caseType.getWorkItem().add(workItem); + } + + // TODO: case payload + // TODO: a lot of other things + + // TODO: move to case-manager + + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("CREATING CASE:\n{}", aCase.debugDump(1)); + } + + repositoryService.addObject(aCase, null, result); + + // notifications + caseEventDispatcher.dispatchCaseEvent(caseType, result); + return aCase; + } + + @Override + public OperationResultStatus queryOperationStatus(String asynchronousOperationReference, OperationResult parentResult) throws ObjectNotFoundException, SchemaException { + OperationResult result = parentResult.createMinorSubresult(OPERATION_QUERY_CASE); + + InternalMonitor.recordConnectorOperation("queryOperationStatus"); + + PrismObject acase; + try { + acase = repositoryService.getObject(CaseType.class, asynchronousOperationReference, null, result); + } catch (ObjectNotFoundException | SchemaException e) { + result.recordFatalError(e); + throw e; + } + + CaseType caseType = acase.asObjectable(); + String state = caseType.getState(); + + // States "open" and "created" are the same from the factual point of view + // They differ only in level of processing carried out by workflow manager (audit, notifications, etc). + if (QNameUtil.matchWithUri(SchemaConstants.CASE_STATE_OPEN_QNAME, state) + || QNameUtil.matchWithUri(SchemaConstants.CASE_STATE_CREATED_QNAME, state)) { + result.recordSuccess(); + return OperationResultStatus.IN_PROGRESS; + } else if (QNameUtil.matchWithUri(SchemaConstants.CASE_STATE_CLOSED_QNAME, state) + || QNameUtil.matchWithUri(SchemaConstants.CASE_STATE_CLOSING_QNAME, state)) { + String outcome = caseType.getOutcome(); + OperationResultStatus status = translateOutcome(outcome); + result.recordSuccess(); + return status; + } else { + SchemaException e = new SchemaException("Unknown case state "+state); + result.recordFatalError(e); + throw e; + } + + } + + // see CompleteWorkItemsAction.getOutcome(..) method + private OperationResultStatus translateOutcome(String outcome) { + + // TODO: better algorithm + if (outcome == null) { + return null; + } else if (outcome.equals(OperationResultStatusType.SUCCESS.value())) { + return OperationResultStatus.SUCCESS; + } else if (SchemaConstants.MODEL_APPROVAL_OUTCOME_APPROVE.equals(outcome)) { + return OperationResultStatus.SUCCESS; + } else { + return OperationResultStatus.UNKNOWN; + } + } + + @Override + protected void connect(OperationResult result) { + if (connected && InternalsConfig.isSanityChecks()) { + throw new IllegalStateException("Double connect in "+this); + } + connected = true; + // Nothing else to do + } + + private String getShadowIdentifier(Collection> identifiers){ + try { + Object[] shadowIdentifiers = identifiers.toArray(); + + return ((ResourceAttribute)shadowIdentifiers[0]).getValue().getValue().toString(); + } catch (NullPointerException e){ + return ""; + } + } + + @Override + public void test(OperationResult parentResult) { + OperationResult connectionResult = parentResult + .createSubresult(ConnectorTestOperation.CONNECTOR_CONNECTION.getOperation()); + connectionResult.addContext(OperationResult.CONTEXT_IMPLEMENTATION_CLASS, ManualConnectorInstance.class); + connectionResult.addContext("connector", getConnectorObject().toString()); + + if (repositoryService == null) { + connectionResult.recordFatalError("No repository service"); + return; + } + + if (!connected && InternalsConfig.isSanityChecks()) { + throw new IllegalStateException("Attempt to test non-connected connector instance "+this); + } + + connectionResult.recordSuccess(); + } + + @Override + public void disconnect(OperationResult parentResult) { + connected = false; + } + + @SuppressWarnings("unused") + public static int getRandomDelayRange() { + return randomDelayRange; + } + + public static void setRandomDelayRange(int randomDelayRange) { + ManualConnectorInstance.randomDelayRange = randomDelayRange; + } + +} From 489f3c32319147544e2cac92e4d1a2481e2d970c Mon Sep 17 00:00:00 2001 From: lskublik Date: Mon, 16 Mar 2020 19:07:01 +0100 Subject: [PATCH 12/21] fix for form validation (MID-6026) --- .../evolveum/midpoint/gui/impl/prism/PrismPropertyPanel.html | 2 +- .../evolveum/midpoint/gui/impl/prism/PrismPropertyPanel.java | 5 +++-- .../midpoint/web/component/message/FeedbackAlerts.html | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/prism/PrismPropertyPanel.html b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/prism/PrismPropertyPanel.html index 8d4aa479bd8..240d0e0aac8 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/prism/PrismPropertyPanel.html +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/prism/PrismPropertyPanel.html @@ -26,7 +26,7 @@ -

+
diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/prism/PrismPropertyPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/prism/PrismPropertyPanel.java index ab147720bfe..caef89e4861 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/prism/PrismPropertyPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/prism/PrismPropertyPanel.java @@ -163,10 +163,11 @@ protected void onError(AjaxRequestTarget target, RuntimeException e) { } }); + feedback.setFilter(new ComponentFeedbackMessageFilter(inputPanel.getValidatableComponent())); + } else { + feedback.setFilter(new ComponentFeedbackMessageFilter(component)); } - feedback.setFilter(new ComponentFeedbackMessageFilter(component)); - if (component instanceof InputPanel) { InputPanel inputPanel = (InputPanel) component; diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/message/FeedbackAlerts.html b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/message/FeedbackAlerts.html index 55b1e09cc90..f5adbe63d9c 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/message/FeedbackAlerts.html +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/message/FeedbackAlerts.html @@ -7,7 +7,7 @@ -
+
From f137678a39066a03523b497b62e6d2642e2f8bdc Mon Sep 17 00:00:00 2001 From: Richard Richter Date: Mon, 16 Mar 2020 10:42:39 +0100 Subject: [PATCH 13/21] TestAbstractActivation*: overridden methods moved to default subclass --- .../AbstractActivationComputerTest.java | 33 ---------------- .../common/TestActivationComputerDefault.java | 39 +++++++++++++++++++ .../TestActivationComputerLifecycle.java | 3 -- 3 files changed, 39 insertions(+), 36 deletions(-) diff --git a/infra/common/src/test/java/com/evolveum/midpoint/common/AbstractActivationComputerTest.java b/infra/common/src/test/java/com/evolveum/midpoint/common/AbstractActivationComputerTest.java index b4cb4d89e6f..f5b1622be29 100644 --- a/infra/common/src/test/java/com/evolveum/midpoint/common/AbstractActivationComputerTest.java +++ b/infra/common/src/test/java/com/evolveum/midpoint/common/AbstractActivationComputerTest.java @@ -35,7 +35,6 @@ public abstract class AbstractActivationComputerTest extends AbstractUnitTest { protected static final XMLGregorianCalendar SUMMER_SOLSTICE = XmlTypeConverter.createXMLGregorianCalendar(2013, 6, 21, 5, 4, 0); protected static final XMLGregorianCalendar AUTUMN_EQUINOX = XmlTypeConverter.createXMLGregorianCalendar(2013, 9, 22, 20, 4, 0); protected static final XMLGregorianCalendar WINTER_SOLSTICE = XmlTypeConverter.createXMLGregorianCalendar(2013, 12, 21, 17, 11, 0); - protected static final XMLGregorianCalendar YEAR_END = XmlTypeConverter.createXMLGregorianCalendar(2013, 12, 31, 23, 59, 59); // Undefined state protected static final String LIFECYCLE_STATE_LIMBO = "limbo"; @@ -100,38 +99,6 @@ public void testGetAdministrativeArchived() throws Exception { assertEquals("Unexpected effective status", ActivationStatusType.ARCHIVED, effectiveStatus); } - @Test - public void testGetDraftAdministrativeEnabled() throws Exception { - // GIVEN - Clock clock = createClock(YEAR_START); - ActivationComputer activationComputer = createActivationComputer(clock); - ActivationType activationType = createActivationType( - ActivationStatusType.DISABLED, SPRING_EQUINOX, AUTUMN_EQUINOX); - - // WHEN - ActivationStatusType effectiveStatus = activationComputer.getEffectiveStatus( - SchemaConstants.LIFECYCLE_DRAFT, activationType, createLifecycleModel()); - - // THEN - assertEquals("Unexpected effective status", ActivationStatusType.DISABLED, effectiveStatus); - } - - @Test - public void testGetProposedAdministrativeEnabled() throws Exception { - // GIVEN - Clock clock = createClock(YEAR_START); - ActivationComputer activationComputer = createActivationComputer(clock); - ActivationType activationType = createActivationType( - ActivationStatusType.ENABLED, SPRING_EQUINOX, AUTUMN_EQUINOX); - - // WHEN - ActivationStatusType effectiveStatus = activationComputer.getEffectiveStatus( - SchemaConstants.LIFECYCLE_PROPOSED, activationType, createLifecycleModel()); - - // THEN - assertEquals("Unexpected effective status", ActivationStatusType.DISABLED, effectiveStatus); - } - @Test public void testGetLimboAdministrativeEnabled() { // GIVEN diff --git a/infra/common/src/test/java/com/evolveum/midpoint/common/TestActivationComputerDefault.java b/infra/common/src/test/java/com/evolveum/midpoint/common/TestActivationComputerDefault.java index a88aca51231..045bcaa32fc 100644 --- a/infra/common/src/test/java/com/evolveum/midpoint/common/TestActivationComputerDefault.java +++ b/infra/common/src/test/java/com/evolveum/midpoint/common/TestActivationComputerDefault.java @@ -6,6 +6,13 @@ */ package com.evolveum.midpoint.common; +import static org.testng.AssertJUnit.assertEquals; + +import org.testng.annotations.Test; + +import com.evolveum.midpoint.schema.constants.SchemaConstants; +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.LifecycleStateModelType; public class TestActivationComputerDefault extends AbstractActivationComputerTest { @@ -14,4 +21,36 @@ public class TestActivationComputerDefault extends AbstractActivationComputerTes protected LifecycleStateModelType createLifecycleModel() { return null; } + + @Test + public void testGetDraftAdministrativeEnabled() { + // GIVEN + Clock clock = createClock(YEAR_START); + ActivationComputer activationComputer = createActivationComputer(clock); + ActivationType activationType = createActivationType( + ActivationStatusType.DISABLED, SPRING_EQUINOX, AUTUMN_EQUINOX); + + // WHEN + ActivationStatusType effectiveStatus = activationComputer.getEffectiveStatus( + SchemaConstants.LIFECYCLE_DRAFT, activationType, createLifecycleModel()); + + // THEN + assertEquals("Unexpected effective status", ActivationStatusType.DISABLED, effectiveStatus); + } + + @Test + public void testGetProposedAdministrativeEnabled() { + // GIVEN + Clock clock = createClock(YEAR_START); + ActivationComputer activationComputer = createActivationComputer(clock); + ActivationType activationType = createActivationType( + ActivationStatusType.ENABLED, SPRING_EQUINOX, AUTUMN_EQUINOX); + + // WHEN + ActivationStatusType effectiveStatus = activationComputer.getEffectiveStatus( + SchemaConstants.LIFECYCLE_PROPOSED, activationType, createLifecycleModel()); + + // THEN + assertEquals("Unexpected effective status", ActivationStatusType.DISABLED, effectiveStatus); + } } diff --git a/infra/common/src/test/java/com/evolveum/midpoint/common/TestActivationComputerLifecycle.java b/infra/common/src/test/java/com/evolveum/midpoint/common/TestActivationComputerLifecycle.java index 9ff46b6c707..ade08cca0ff 100644 --- a/infra/common/src/test/java/com/evolveum/midpoint/common/TestActivationComputerLifecycle.java +++ b/infra/common/src/test/java/com/evolveum/midpoint/common/TestActivationComputerLifecycle.java @@ -36,7 +36,6 @@ protected LifecycleStateModelType createLifecycleModel() throws SchemaException, } @Test - @Override public void testGetProposedAdministrativeEnabled() throws Exception { // GIVEN Clock clock = createClock(YEAR_START); @@ -53,7 +52,6 @@ public void testGetProposedAdministrativeEnabled() throws Exception { } @Test - @Override public void testGetDraftAdministrativeEnabled() throws Exception { // GIVEN Clock clock = createClock(YEAR_START); @@ -108,5 +106,4 @@ protected void testComputeInhumed( testCompute(LIFECYCLE_STATE_INHUMED, now, administrativeStatus, validFrom, validTo, ActivationStatusType.ARCHIVED, expectedValidity); } - } From 13e090269e16596c06d9defbd77aa78c088bb2c6 Mon Sep 17 00:00:00 2001 From: Richard Richter Date: Mon, 16 Mar 2020 19:19:31 +0100 Subject: [PATCH 14/21] MidpointTestMixin: added skipTestIf(cond, desc) + used in two classes --- .../expression/script/TestGroovyExpressions.java | 9 ++------- .../evolveum/midpoint/model/intest/TestAudit.java | 11 +++-------- .../midpoint/tools/testng/MidpointTestMixin.java | 13 +++++++++++++ 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/model/model-common/src/test/java/com/evolveum/midpoint/model/common/expression/script/TestGroovyExpressions.java b/model/model-common/src/test/java/com/evolveum/midpoint/model/common/expression/script/TestGroovyExpressions.java index 6945dc9d755..25dd9538a20 100644 --- a/model/model-common/src/test/java/com/evolveum/midpoint/model/common/expression/script/TestGroovyExpressions.java +++ b/model/model-common/src/test/java/com/evolveum/midpoint/model/common/expression/script/TestGroovyExpressions.java @@ -13,7 +13,6 @@ import org.apache.commons.lang3.SystemUtils; import org.testng.AssertJUnit; -import org.testng.SkipException; import org.testng.annotations.Test; import com.evolveum.midpoint.model.common.expression.script.groovy.GroovyScriptEvaluator; @@ -504,9 +503,7 @@ public void testSyntaxError() throws Exception { */ @Test public void testStringExec() throws Exception { - if (SystemUtils.IS_OS_WINDOWS) { - throw new SkipException("Skipped for Windows"); - } + skipTestIf(SystemUtils.IS_OS_WINDOWS, "'echo' used in script is not available Windows"); // WHEN evaluateAndAssertStringScalarExpression( @@ -524,9 +521,7 @@ public void testStringExec() throws Exception { */ @Test public void testListExec() throws Exception { - if (SystemUtils.IS_OS_WINDOWS) { - throw new SkipException("Skipped for Windows"); - } + skipTestIf(SystemUtils.IS_OS_WINDOWS, "'echo' used in script is not available Windows"); // WHEN evaluateAndAssertStringScalarExpression( diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestAudit.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestAudit.java index 2f545b3abb1..d93a8991781 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestAudit.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestAudit.java @@ -526,10 +526,7 @@ public void test300ConcurrentAudits() throws Exception { final int ITERATIONS = 300; final long TIMEOUT = 600000; - if (isH2()) { - display("Skipping " + getTestNameShort() + " because of H2 database"); - return; - } +// skipTestIf(isH2(), "because of H2 database"); // creating objects List oids = new ArrayList<>(NUM_THREADS); @@ -604,10 +601,8 @@ public void test310ConcurrentAuditsRaw() throws Exception { final int ITERATIONS = 300; final long TIMEOUT = 600000; - if (isH2()) { - display("Skipping " + getTestNameShort() + " because of H2 database"); - return; - } + // Originally we wanted to skip this because of possible concurrency issues on H2, but we'll try it for a while +// skipTestIf(isH2(), "H2 database can have MVCC issues"); final AtomicBoolean failed = new AtomicBoolean(false); // signal to kill other threads after a failure diff --git a/tools/test-ng/src/main/java/com/evolveum/midpoint/tools/testng/MidpointTestMixin.java b/tools/test-ng/src/main/java/com/evolveum/midpoint/tools/testng/MidpointTestMixin.java index b597a1f605f..8bc0017cfaa 100644 --- a/tools/test-ng/src/main/java/com/evolveum/midpoint/tools/testng/MidpointTestMixin.java +++ b/tools/test-ng/src/main/java/com/evolveum/midpoint/tools/testng/MidpointTestMixin.java @@ -13,6 +13,7 @@ import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.testng.ITestResult; +import org.testng.SkipException; /** * Mixin with various utility methods, mostly related to test header/footer/section output/logging. @@ -223,4 +224,16 @@ default void expect(String description) { System.out.println(TEST_OUT_SECTION_PREFIX + testName + ": EXPECT " + description + TEST_OUT_SECTION_SUFFIX); logger().info(TEST_LOG_SECTION_PREFIX + testName + ": EXPECT " + description + TEST_LOG_SECTION_SUFFIX); } + + /** + * Skips test if skip condition is met by throwing {@link SkipException}. + * Message will contain the test name and provided description. + */ + default void skipTestIf(boolean skipCondition, String description) { + if (skipCondition) { + String message = "Skipping " + getTestNameShort() + ": " + description; + display(message); + throw new SkipException(message); + } + } } From 84d346dc0133eb47cd598ff1c088488a9581b84f Mon Sep 17 00:00:00 2001 From: Richard Richter Date: Mon, 16 Mar 2020 19:21:44 +0100 Subject: [PATCH 15/21] TestAudit: fixes of test300/310, thread creates new task and more... - it also clones userAdministrator before login, sometimes it fails on concurrent access while clearing collection deep in prism - better throwable logging if caught in thread --- .../evolveum/midpoint/model/intest/TestAudit.java | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestAudit.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestAudit.java index d93a8991781..8b7502cad26 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestAudit.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestAudit.java @@ -524,7 +524,7 @@ private void assertRecordsFromInitial(XMLGregorianCalendar to, int expectedNumbe public void test300ConcurrentAudits() throws Exception { final int NUM_THREADS = 2; final int ITERATIONS = 300; - final long TIMEOUT = 600000; + final long TIMEOUT = 600_000; // skipTestIf(isH2(), "because of H2 database"); @@ -545,8 +545,8 @@ public void test300ConcurrentAudits() throws Exception { final int index = i; Thread thread = new Thread(() -> { try { - login(userAdministrator); - Task threadTask = getTestTask(); + login(userAdministrator.clone()); + Task threadTask = createTask(); OperationResult threadResult = threadTask.getResult(); for (int iteration = 0; iteration < ITERATIONS; iteration++) { display("Executing iteration " + iteration + " on user " + index); @@ -557,8 +557,7 @@ public void test300ConcurrentAudits() throws Exception { } results.set(index, null); } catch (Throwable t) { - System.err.println("Thread " + index + " got an exception " + t); - LoggingUtils.logUnexpectedException(logger, "Thread {} got an exception", t, index); + display("Thread " + index + " got an exception ", t); results.set(index, t); } }); @@ -599,7 +598,7 @@ public void test300ConcurrentAudits() throws Exception { public void test310ConcurrentAuditsRaw() throws Exception { final int NUM_THREADS = 2; final int ITERATIONS = 300; - final long TIMEOUT = 600000; + final long TIMEOUT = 600_000; // Originally we wanted to skip this because of possible concurrency issues on H2, but we'll try it for a while // skipTestIf(isH2(), "H2 database can have MVCC issues"); @@ -613,8 +612,8 @@ public void test310ConcurrentAuditsRaw() throws Exception { final int index = i; Thread thread = new Thread(() -> { try { - login(userAdministrator); - Task threadTask = getTestTask(); + login(userAdministrator.clone()); + Task threadTask = createTask(); OperationResult threadResult = threadTask.getResult(); for (int iteration = 0; iteration < ITERATIONS; iteration++) { display("Executing iteration " + iteration + " in worker " + index); From 3a07d4f29fd4add2462bc511eab87e92fb4698b2 Mon Sep 17 00:00:00 2001 From: Richard Richter Date: Mon, 16 Mar 2020 19:22:37 +0100 Subject: [PATCH 16/21] TestAudit: test300QueryUnknown renamed to 290 (there were too test300*) --- .../test/java/com/evolveum/midpoint/model/intest/TestAudit.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestAudit.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestAudit.java index 8b7502cad26..824a4960500 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestAudit.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestAudit.java @@ -469,7 +469,7 @@ public void test254ReconstructHermanHermit() throws Exception { } @Test - public void test300QueryUnknown() throws Exception { + public void test290QueryUnknown() throws Exception { Task task = getTestTask(); OperationResult result = task.getResult(); From 182ae60ee1e55795e1393c2b3f9069b8f5a770a4 Mon Sep 17 00:00:00 2001 From: Richard Richter Date: Mon, 16 Mar 2020 19:26:53 +0100 Subject: [PATCH 17/21] MappingImpl: minor cosmetics/wrapping --- .../model/common/mapping/MappingImpl.java | 30 ++++++++++++------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/mapping/MappingImpl.java b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/mapping/MappingImpl.java index cede7ba1995..8078848f684 100644 --- a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/mapping/MappingImpl.java +++ b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/mapping/MappingImpl.java @@ -943,10 +943,10 @@ private void parseSources(Task task, OperationResult result) } } - private Source parseSource(VariableBindingDefinitionType sourceDefinition, - Task task, OperationResult result) - throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, - ConfigurationException, SecurityViolationException { + private Source parseSource( + VariableBindingDefinitionType sourceDefinition, Task task, OperationResult result) + throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException, + CommunicationException, ConfigurationException, SecurityViolationException { ItemPath path = getSourcePath(sourceDefinition); QName sourceQName = sourceDefinition.getName() != null ? sourceDefinition.getName() : ItemPath.toName(path.last()); String variableName = sourceQName.getLocalPart(); @@ -991,7 +991,10 @@ private Source parseS // apply domain ValueSetDefinitionType domainSetType = sourceDefinition.getSet(); if (domainSetType != null) { - ValueSetDefinition setDef = new ValueSetDefinition<>(domainSetType, sourceItemDefinition, expressionProfile, variableName, "domain of " + variableName + " in " + getMappingContextDescription(), task, result); + ValueSetDefinition setDef = new ValueSetDefinition<>( + domainSetType, sourceItemDefinition, expressionProfile, variableName, + "domain of " + variableName + " in " + getMappingContextDescription(), + task, result); setDef.init(expressionFactory); setDef.setAdditionalVariables(variables); try { @@ -1072,9 +1075,12 @@ private void parseTarget() throws SchemaException { outputPath = defaultTargetPath; } else { ItemPath path = itemPathType.getItemPath(); - outputDefinition = ExpressionUtil.resolveDefinitionPath(path, variables, targetContext, "target definition in " + getMappingContextDescription()); + outputDefinition = ExpressionUtil.resolveDefinitionPath( + path, variables, targetContext, + "target definition in " + getMappingContextDescription()); if (outputDefinition == null) { - throw new SchemaException("No target item that would conform to the path " + path + " in " + getMappingContextDescription()); + throw new SchemaException("No target item that would conform to the path " + + path + " in " + getMappingContextDescription()); } outputPath = path.stripVariableSegment(); } @@ -1135,7 +1141,9 @@ private void setOrigin() { } } - private void evaluateCondition(Task task, OperationResult result) throws SchemaException, ExpressionEvaluationException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException { + private void evaluateCondition(Task task, OperationResult result) + throws SchemaException, ExpressionEvaluationException, ObjectNotFoundException, + CommunicationException, ConfigurationException, SecurityViolationException { ExpressionType conditionExpressionType = mappingType.getCondition(); if (conditionExpressionType == null) { // True -> True @@ -1158,7 +1166,10 @@ private void evaluateCondition(Task task, OperationResult result) throws SchemaE conditionOutputTriple = expression.evaluate(context, result); } - private void evaluateExpression(Task task, OperationResult result, boolean conditionResultOld, boolean conditionResultNew) throws SchemaException, ExpressionEvaluationException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException { + private void evaluateExpression(Task task, OperationResult result, + boolean conditionResultOld, boolean conditionResultNew) + throws SchemaException, ExpressionEvaluationException, ObjectNotFoundException, + CommunicationException, ConfigurationException, SecurityViolationException { ExpressionType expressionType = null; if (mappingType != null) { expressionType = mappingType.getExpression(); @@ -1947,5 +1958,4 @@ public MappingStrengthType getStrength() { return MappingImpl.getStrength(mappingType); } } - } From 23021976351e40a3bce5f70bc2578421885d29ea Mon Sep 17 00:00:00 2001 From: Richard Richter Date: Mon, 16 Mar 2020 19:28:49 +0100 Subject: [PATCH 18/21] MappingEvaluator: removed unused param from evaluateOutboundMapping... +reformat --- .../ProjectionCredentialsProcessor.java | 3 +- .../projector/mappings/MappingEvaluator.java | 173 +++++++----------- 2 files changed, 64 insertions(+), 112 deletions(-) diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/credentials/ProjectionCredentialsProcessor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/credentials/ProjectionCredentialsProcessor.java index 47d0d89e598..853d7f89a49 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/credentials/ProjectionCredentialsProcessor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/credentials/ProjectionCredentialsProcessor.java @@ -68,7 +68,6 @@ import com.evolveum.midpoint.xml.ns._public.common.common_3.ValuePolicyType; import com.evolveum.midpoint.xml.ns._public.common.common_3.VariableBindingDefinitionType; import com.evolveum.midpoint.xml.ns._public.resource.capabilities_3.CredentialsCapabilityType; -import com.evolveum.midpoint.xml.ns._public.resource.capabilities_3.PasswordCapabilityType; import com.evolveum.prism.xml.ns._public.types_3.ItemPathType; import com.evolveum.prism.xml.ns._public.types_3.ProtectedStringType; @@ -259,7 +258,7 @@ public ValuePolicyType resolve() { mappingEvaluator.evaluateOutboundMapping(context, projCtx, outboundMappingTypes, - SchemaConstants.PATH_PASSWORD_VALUE, SchemaConstants.PATH_PASSWORD_VALUE, initializer, processor, + SchemaConstants.PATH_PASSWORD_VALUE, initializer, processor, now, MappingTimeEval.CURRENT, evaluateWeak, "password mapping", task, result); } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/mappings/MappingEvaluator.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/mappings/MappingEvaluator.java index 89d532ffc1b..b3aec6e62d3 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/mappings/MappingEvaluator.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/mappings/MappingEvaluator.java @@ -8,63 +8,44 @@ import java.util.*; import java.util.Map.Entry; - import javax.xml.bind.JAXBElement; import javax.xml.datatype.DatatypeConstants; import javax.xml.datatype.XMLGregorianCalendar; -import com.evolveum.midpoint.model.impl.lens.*; -import com.evolveum.midpoint.model.impl.lens.projector.*; -import com.evolveum.midpoint.prism.*; -import com.evolveum.midpoint.prism.path.ItemPath; -import com.evolveum.midpoint.repo.common.ObjectResolver; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import com.evolveum.midpoint.repo.common.expression.ExpressionUtil; -import com.evolveum.midpoint.repo.common.expression.ExpressionVariables; -import com.evolveum.midpoint.repo.common.expression.Source; -import com.evolveum.midpoint.repo.common.expression.ValuePolicyResolver; -import com.evolveum.midpoint.model.common.mapping.MappingImpl; import com.evolveum.midpoint.model.common.mapping.MappingFactory; +import com.evolveum.midpoint.model.common.mapping.MappingImpl; import com.evolveum.midpoint.model.impl.expr.ExpressionEnvironment; import com.evolveum.midpoint.model.impl.expr.ModelExpressionThreadLocalHolder; +import com.evolveum.midpoint.model.impl.lens.*; +import com.evolveum.midpoint.model.impl.lens.projector.ContextLoader; import com.evolveum.midpoint.model.impl.lens.projector.credentials.CredentialsProcessor; import com.evolveum.midpoint.model.impl.util.ModelImplUtils; +import com.evolveum.midpoint.prism.*; import com.evolveum.midpoint.prism.delta.ItemDelta; import com.evolveum.midpoint.prism.delta.PrismValueDeltaSetTriple; +import com.evolveum.midpoint.prism.path.ItemPath; import com.evolveum.midpoint.prism.path.UniformItemPath; import com.evolveum.midpoint.prism.util.ObjectDeltaObject; +import com.evolveum.midpoint.repo.common.ObjectResolver; +import com.evolveum.midpoint.repo.common.expression.ExpressionUtil; +import com.evolveum.midpoint.repo.common.expression.ExpressionVariables; +import com.evolveum.midpoint.repo.common.expression.Source; +import com.evolveum.midpoint.repo.common.expression.ValuePolicyResolver; import com.evolveum.midpoint.schema.constants.ExpressionConstants; import com.evolveum.midpoint.schema.expression.TypedValue; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.task.api.Task; -import com.evolveum.midpoint.util.exception.CommonException; -import com.evolveum.midpoint.util.exception.CommunicationException; -import com.evolveum.midpoint.util.exception.ConfigurationException; -import com.evolveum.midpoint.util.exception.ExpressionEvaluationException; -import com.evolveum.midpoint.util.exception.ObjectNotFoundException; -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.*; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; -import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentHolderType; -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.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.SystemConfigurationType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ValuePolicyType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.*; import com.evolveum.prism.xml.ns._public.types_3.ProtectedStringType; /** * @author Radovan Semancik - * */ @Component public class MappingEvaluator { @@ -83,19 +64,19 @@ public PrismContext getPrismContext() { static final List FOCUS_VARIABLE_NAMES = Arrays.asList(ExpressionConstants.VAR_FOCUS, ExpressionConstants.VAR_USER); - public void evaluateMapping(MappingImpl mapping, + public void evaluateMapping(MappingImpl mapping, LensContext lensContext, Task task, OperationResult parentResult) throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException, SecurityViolationException, ConfigurationException, CommunicationException { evaluateMapping(mapping, lensContext, null, task, parentResult); } - public void evaluateMapping(MappingImpl mapping, + public void evaluateMapping(MappingImpl mapping, LensContext lensContext, LensProjectionContext projContext, Task task, OperationResult parentResult) throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException, SecurityViolationException, ConfigurationException, CommunicationException { - ExpressionEnvironment env = new ExpressionEnvironment<>(); + ExpressionEnvironment env = new ExpressionEnvironment<>(); env.setLensContext(lensContext); env.setProjectionContext(projContext); env.setMapping(mapping); @@ -118,10 +99,10 @@ public vo try { task.recordState("Started evaluation of mapping " + mapping.getMappingContextDescription() + "."); mapping.evaluate(task, parentResult); - task.recordState("Successfully finished evaluation of mapping " + mapping.getMappingContextDescription() + " in " + (System.currentTimeMillis()-start) + " ms."); + task.recordState("Successfully finished evaluation of mapping " + mapping.getMappingContextDescription() + " in " + (System.currentTimeMillis() - start) + " ms."); } catch (IllegalArgumentException e) { - task.recordState("Evaluation of mapping " + mapping.getMappingContextDescription() + " finished with error in " + (System.currentTimeMillis()-start) + " ms."); - throw new IllegalArgumentException(e.getMessage()+" in "+mapping.getContextDescription(), e); + task.recordState("Evaluation of mapping " + mapping.getMappingContextDescription() + " finished with error in " + (System.currentTimeMillis() - start) + " ms."); + throw new IllegalArgumentException(e.getMessage() + " in " + mapping.getContextDescription(), e); } finally { task.recordMappingOperation(objectOid, objectName, objectTypeName, mappingName, System.currentTimeMillis() - start); ModelExpressionThreadLocalHolder.popExpressionEnvironment(); @@ -134,26 +115,28 @@ public vo // TODO: unify OutboundProcessor.evaluateMapping() with MappingEvaluator.evaluateOutboundMapping(...) public void evaluateOutboundMapping(final LensContext context, final LensProjectionContext projCtx, List outboundMappings, - final ItemPath focusPropertyPath, final ItemPath projectionPropertyPath, - final MappingInitializer,PrismPropertyDefinition> initializer, MappingOutputProcessor> processor, + final ItemPath projectionPropertyPath, final MappingInitializer, + PrismPropertyDefinition> initializer, MappingOutputProcessor> processor, XMLGregorianCalendar now, final MappingTimeEval evaluateCurrent, boolean evaluateWeak, - String desc, final Task task, final OperationResult result) throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, SecurityViolationException { + String desc, final Task task, final OperationResult result) + throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException, + CommunicationException, ConfigurationException, SecurityViolationException { String projCtxDesc = projCtx.toHumanReadableString(); PrismObject shadowNew = projCtx.getObjectNew(); - MappingInitializer,PrismPropertyDefinition> internalInitializer = - builder -> { + MappingInitializer, PrismPropertyDefinition> internalInitializer = + builder -> { - builder.addVariableDefinitions(ModelImplUtils.getDefaultExpressionVariables(context, projCtx)); + builder.addVariableDefinitions(ModelImplUtils.getDefaultExpressionVariables(context, projCtx)); - builder.originType(OriginType.OUTBOUND); - builder.originObject(projCtx.getResource()); + builder.originType(OriginType.OUTBOUND); + builder.originObject(projCtx.getResource()); - initializer.initialize(builder); + initializer.initialize(builder); - return builder; - }; + return builder; + }; MappingEvaluatorParams, PrismPropertyDefinition, ShadowType, F> params = new MappingEvaluatorParams<>(); params.setMappingTypes(outboundMappings); @@ -176,24 +159,25 @@ public void evaluateOutboundMapping(final LensContext Map> evaluateMappingSetProjection( - MappingEvaluatorParams params, - Task task, OperationResult result) throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, SecurityViolationException { + public Map> evaluateMappingSetProjection( + MappingEvaluatorParams params, Task task, OperationResult result) + throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException, + CommunicationException, ConfigurationException, SecurityViolationException { String mappingDesc = params.getMappingDesc(); LensElementContext targetContext = params.getTargetContext(); PrismObjectDefinition targetObjectDefinition = targetContext.getObjectDefinition(); ItemPath defaultTargetItemPath = params.getDefaultTargetItemPath(); - Map> outputTripleMap = new HashMap<>(); + Map> outputTripleMap = new HashMap<>(); XMLGregorianCalendar nextRecomputeTime = null; String triggerOriginDescription = null; Collection mappingTypes = params.getMappingTypes(); - Collection> mappings = new ArrayList<>(mappingTypes.size()); + Collection> mappings = new ArrayList<>(mappingTypes.size()); - for (MappingType mappingType: mappingTypes) { + for (MappingType mappingType : mappingTypes) { - MappingImpl.Builder mappingBuilder = mappingFactory.createMappingBuilder(mappingType, mappingDesc); + MappingImpl.Builder mappingBuilder = mappingFactory.createMappingBuilder(mappingType, mappingDesc); String mappingName = null; if (mappingType.getName() != null) { mappingName = mappingType.getName(); @@ -219,9 +203,9 @@ public initializedMappingBuilder = params.getInitializer().initialize(mappingBuilder); + MappingImpl.Builder initializedMappingBuilder = params.getInitializer().initialize(mappingBuilder); - MappingImpl mapping = initializedMappingBuilder.build(); + MappingImpl mapping = initializedMappingBuilder.build(); boolean timeConstraintValid = mapping.evaluateTimeConstraintValid(task, result); if (params.getEvaluateCurrent() == MappingTimeEval.CURRENT && !timeConstraintValid) { @@ -238,7 +222,7 @@ public mapping: mappings) { + for (MappingImpl mapping : mappings) { if (mapping.getStrength() == MappingStrengthType.WEAK) { // Evaluate weak mappings in a second run. @@ -247,11 +231,11 @@ public aPrioriItemDelta = params.getAPrioriTargetDelta().findItemDelta(mappingOutputPathUniform); + ItemDelta aPrioriItemDelta = params.getAPrioriTargetDelta().findItemDelta(mappingOutputPathUniform); if (mapping.getStrength() != MappingStrengthType.STRONG) { if (aPrioriItemDelta != null && !aPrioriItemDelta.isEmpty()) { continue; @@ -264,7 +248,7 @@ public mappingOutputTriple = mapping.getOutputTriple(); if (LOGGER.isTraceEnabled()) { LOGGER.trace("Output triple of mapping {}\n{}", mapping.getContextDescription(), - mappingOutputTriple==null?null:mappingOutputTriple.debugDump(1)); + mappingOutputTriple == null ? null : mappingOutputTriple.debugDump(1)); } if (isMeaningful(mappingOutputTriple)) { @@ -302,7 +286,7 @@ public mapping: mappings) { + for (MappingImpl mapping : mappings) { if (mapping.getStrength() != MappingStrengthType.WEAK) { continue; @@ -310,7 +294,7 @@ public mappingOutputStruct = outputTripleMap.get(mappingOutputPath); @@ -333,7 +317,7 @@ public aPrioriTargetItem = null; + Item aPrioriTargetItem = null; if (aPrioriTargetObject != null && mappingOutputPath != null) { aPrioriTargetItem = aPrioriTargetObject.findItem(mappingOutputPath); } @@ -377,7 +361,7 @@ public processor = params.getProcessor(); - for (Entry> outputTripleMapEntry: outputTripleMap.entrySet()) { + for (Entry> outputTripleMapEntry : outputTripleMap.entrySet()) { UniformItemPath mappingOutputPath = outputTripleMapEntry.getKey(); MappingOutputStruct mappingOutputStruct = outputTripleMapEntry.getValue(); PrismValueDeltaSetTriple outputTriple = mappingOutputStruct.getOutputTriple(); @@ -401,15 +385,15 @@ public targetItemDelta = targetItemDefinition.createEmptyDelta(mappingOutputPath); + ItemDelta targetItemDelta = targetItemDefinition.createEmptyDelta(mappingOutputPath); - Item aPrioriTargetItem; + Item aPrioriTargetItem; if (aPrioriTargetObject != null) { aPrioriTargetItem = aPrioriTargetObject.findItem(mappingOutputPath); } else { @@ -450,7 +434,7 @@ public mapping: mappings) { + for (MappingImpl mapping : mappings) { XMLGregorianCalendar mappingNextRecomputeTime = mapping.getNextRecomputeTime(); if (mappingNextRecomputeTime != null) { if (mapping.isSatisfyCondition() && (nextRecomputeTime == null || nextRecomputeTime.compare(mappingNextRecomputeTime) == DatatypeConstants.GREATER)) { @@ -549,10 +533,10 @@ private boolean hasNoOrHashedValuesOnly(Collection set if (set == null) { return true; } - for (V pval: set) { + for (V pval : set) { Object val = pval.getRealValue(); if (val instanceof ProtectedStringType) { - if (!((ProtectedStringType)val).isHashed()) { + if (!((ProtectedStringType) val).isHashed()) { return false; } } else { @@ -567,7 +551,7 @@ private boolean hasNoValue(Item aPrioriTargetItem) { || (aPrioriTargetItem.isEmpty() && !aPrioriTargetItem.isIncomplete()); } - public MappingImpl createFocusMapping(final MappingFactory mappingFactory, + public MappingImpl createFocusMapping(final MappingFactory mappingFactory, final LensContext context, final MappingType mappingType, ObjectType originObject, ObjectDeltaObject focusOdo, AssignmentPathVariables assignmentPathVariables, PrismObject configuration, XMLGregorianCalendar now, String contextDesc, Task task, OperationResult result) throws SchemaException, ExpressionEvaluationException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException { @@ -600,6 +584,7 @@ public > evaluators = mappingType.getExpression().getExpressionEvaluator(); if (evaluators != null) { for (JAXBElement jaxbEvaluator : evaluators) { @@ -625,7 +610,7 @@ public ValuePolicyType resolve() { ObjectReferenceType ref = ((GenerateExpressionEvaluatorType) object).getValuePolicyRef(); try { ValuePolicyType valuePolicyType = mappingFactory.getObjectResolver().resolve(ref, ValuePolicyType.class, - null, "resolving value policy for generate attribute "+ outputDefinition.getItemName()+" value", task, new OperationResult("Resolving value policy")); + null, "resolving value policy for generate attribute " + outputDefinition.getItemName() + " value", task, new OperationResult("Resolving value policy")); if (valuePolicyType != null) { return valuePolicyType; } @@ -653,7 +638,7 @@ public ValuePolicyType resolve() { TypedValue> defaultTargetContext = new TypedValue<>(defaultTargetObject); Collection targetValues = ExpressionUtil.computeTargetValues(mappingType.getTarget(), defaultTargetContext, variables, mappingFactory.getObjectResolver(), contextDesc, prismContext, task, result); - MappingImpl.Builder mappingBuilder = mappingFactory.createMappingBuilder(mappingType, contextDesc) + MappingImpl.Builder mappingBuilder = mappingFactory.createMappingBuilder(mappingType, contextDesc) .sourceContext(focusOdo) .defaultSource(defaultSource) .targetContext(defaultTargetObject.getDefinition()) @@ -668,7 +653,7 @@ public ValuePolicyType resolve() { mappingBuilder = LensUtil.addAssignmentPathVariables(mappingBuilder, assignmentPathVariables, prismContext); - MappingImpl mapping = mappingBuilder.build(); + MappingImpl mapping = mappingBuilder.build(); ItemPath itemPath = mapping.getOutputPath(); if (itemPath == null) { @@ -677,7 +662,7 @@ public ValuePolicyType resolve() { } if (defaultTargetObject != null) { - Item existingTargetItem = (Item) defaultTargetObject.findItem(itemPath); + Item existingTargetItem = (Item) defaultTargetObject.findItem(itemPath); if (existingTargetItem != null && !existingTargetItem.isEmpty() && mapping.getStrength() == MappingStrengthType.WEAK) { LOGGER.trace("Mapping {} is weak and target already has a value {}, skipping.", mapping, existingTargetItem); @@ -687,36 +672,4 @@ public ValuePolicyType resolve() { return mapping; } - -// private Collection computeTargetValues(VariableBindingDefinitionType target, -// Object defaultTargetContext, ExpressionVariables variables, ObjectResolver objectResolver, String contextDesc, -// Task task, OperationResult result) throws SchemaException, ObjectNotFoundException { -// if (target == null) { -// // Is this correct? What about default targets? -// return null; -// } -// -// ItemPathType itemPathType = target.getPath(); -// if (itemPathType == null) { -// // Is this correct? What about default targets? -// return null; -// } -// ItemPath path = itemPathType.getItemPath(); -// -// Object object = ExpressionUtil.resolvePath(path, variables, defaultTargetContext, objectResolver, contextDesc, task, result); -// if (object == null) { -// return new ArrayList<>(); -// } else if (object instanceof Item) { -// return ((Item) object).getValues(); -// } else if (object instanceof PrismValue) { -// return (List) Collections.singletonList((PrismValue) object); -// } else if (object instanceof ItemDeltaItem) { -// ItemDeltaItem idi = (ItemDeltaItem) object; -// PrismValueDeltaSetTriple triple = idi.toDeltaSetTriple(); -// return triple != null ? triple.getNonNegativeValues() : new ArrayList(); -// } else { -// throw new IllegalStateException("Unsupported target value(s): " + object.getClass() + " (" + object + ")"); -// } -// } - } From 85dd538d73ca438f827f924840e2eeeb76456e44 Mon Sep 17 00:00:00 2001 From: Richard Richter Date: Mon, 16 Mar 2020 22:24:17 +0100 Subject: [PATCH 19/21] MidpointTestMixin: added display(Expected)Exception here The same was removed from IntegrationTestTools. On many places "expected" version should be used and is not (yet). --- .../midpoint/web/TestInitialObjects.java | 2 +- .../model/impl/lens/TestDependencies.java | 2 +- .../lens/TestPasswordPolicyProcessor.java | 2 +- .../model/impl/lens/TestProjector.java | 2 +- .../TestAbstractAuthenticationEvaluator.java | 38 ++--- .../midpoint/model/intest/TestAudit.java | 2 +- .../intest/TestModelServiceContract.java | 4 +- .../model/intest/TestPreviewChanges.java | 2 +- .../model/intest/TestStrangeCases.java | 8 +- .../intest/archetypes/TestArchetypes.java | 2 +- .../model/intest/mapping/TestMapping.java | 2 +- .../model/intest/multi/TestMultiResource.java | 8 +- .../intest/negative/TestAssignmentErrors.java | 2 +- .../intest/negative/TestBrokenResources.java | 12 +- .../model/intest/orgstruct/TestOrgStruct.java | 2 +- .../intest/password/AbstractPasswordTest.java | 6 +- .../intest/persona/TestPersonaPassword.java | 2 +- .../midpoint/model/intest/rbac/TestRbac.java | 12 +- .../intest/security/TestSecurityBasic.java | 6 +- .../midpoint/report/TestReportWebService.java | 8 +- .../midpoint/wf/impl/AbstractWfTest.java | 2 +- .../provisioning/impl/dummy/TestDummy.java | 10 +- .../impl/dummy/TestDummyConsistency.java | 12 +- .../impl/dummy/TestDummyNegative.java | 12 +- .../impl/dummy/TestDummySecurity.java | 4 +- .../provisioning/impl/opendj/TestOpenDj.java | 12 +- .../impl/opendj/TestOpenDjNegative.java | 30 ++-- .../midpoint/test/AbstractHigherUnitTest.java | 159 +++++++----------- .../test/AbstractIntegrationTest.java | 8 - .../midpoint/test/IntegrationTestTools.java | 31 +--- .../testing/story/TestServiceAccounts.java | 6 +- .../midpoint/testing/story/TestUnix.java | 2 +- .../tools/testng/MidpointTestMixin.java | 27 ++- 33 files changed, 195 insertions(+), 244 deletions(-) diff --git a/gui/admin-gui/src/test/java/com/evolveum/midpoint/web/TestInitialObjects.java b/gui/admin-gui/src/test/java/com/evolveum/midpoint/web/TestInitialObjects.java index b64cf52be13..d0b51a3992a 100644 --- a/gui/admin-gui/src/test/java/com/evolveum/midpoint/web/TestInitialObjects.java +++ b/gui/admin-gui/src/test/java/com/evolveum/midpoint/web/TestInitialObjects.java @@ -42,7 +42,7 @@ public void testInitialObjects() throws Exception { } catch (Throwable e) { String msg = "Error processing file "+file.getName()+": "+e.getMessage(); logger.error(msg, e); - display(msg, e); + displayException(msg, e); throw e; } } diff --git a/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestDependencies.java b/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestDependencies.java index 1bf562d9138..99e7d0d4cc0 100644 --- a/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestDependencies.java +++ b/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestDependencies.java @@ -373,7 +373,7 @@ public void test300SortToWavesXYZCircular() throws Exception { AssertJUnit.fail("Unexpected success"); } catch (PolicyViolationException e) { // This is expected - display("Expected exception", e); + displayException("Expected exception", e); } } diff --git a/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestPasswordPolicyProcessor.java b/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestPasswordPolicyProcessor.java index 09984f0de96..fe5d0a27b51 100644 --- a/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestPasswordPolicyProcessor.java +++ b/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestPasswordPolicyProcessor.java @@ -180,7 +180,7 @@ private void doTestModifyPasswordExpectFailure(String password) throws Exception fail("Expected PolicyViolationException but didn't get one."); } catch (PolicyViolationException ex) { // this is expected - display("expected exception", ex); + displayException("expected exception", ex); result.computeStatus(); TestUtil.assertFailure(result); } diff --git a/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestProjector.java b/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestProjector.java index 881cfa47d4f..d07349c7c5c 100644 --- a/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestProjector.java +++ b/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestProjector.java @@ -635,7 +635,7 @@ public void test269DeleteBarbossaDummyAccount() throws Exception { } catch (PolicyViolationException e) { // THEN: success // this is expected - display("Expected exception", e); + displayException("Expected exception", e); } } diff --git a/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/security/TestAbstractAuthenticationEvaluator.java b/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/security/TestAbstractAuthenticationEvaluator.java index cd5d135f4de..6ce37afe69a 100644 --- a/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/security/TestAbstractAuthenticationEvaluator.java +++ b/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/security/TestAbstractAuthenticationEvaluator.java @@ -212,7 +212,7 @@ public void test101PasswordLoginBadPasswordJack() throws Exception { // THEN then(); - display("expected exception", e); + displayException("expected exception", e); assertBadPasswordException(e); } XMLGregorianCalendar endTs = clock.currentTimeXMLGregorianCalendar(); @@ -243,7 +243,7 @@ public void test102PasswordLoginNullPasswordJack() throws Exception { // THEN then(); - display("expected exception", e); + displayException("expected exception", e); assertPasswordEncodingException(e); } @@ -273,7 +273,7 @@ public void test103PasswordLoginEmptyPasswordJack() throws Exception { // THEN then(); - display("expected exception", e); + displayException("expected exception", e); assertPasswordEncodingException(e); } @@ -302,7 +302,7 @@ public void test105PasswordLoginNullUsernameNullPassword() { // THEN then(); - display("expected exception", e); + displayException("expected exception", e); assertPasswordEncodingException(e); } @@ -327,7 +327,7 @@ public void test106PasswordLoginEmptyUsernameBadPassword() { // THEN then(); - display("expected exception", e); + displayException("expected exception", e); assertNoUserException(e); } @@ -352,7 +352,7 @@ public void test107PasswordLoginBadUsernameBadPassword() { // THEN then(); - display("expected exception", e); + displayException("expected exception", e); assertNoUserException(e); } @@ -384,7 +384,7 @@ public void test125PasswordLoginBadPasswordJackAfterLockoutFailedAttemptsDuratio // THEN then(); - display("expected exception", e); + displayException("expected exception", e); assertBadPasswordException(e); } XMLGregorianCalendar endTs = clock.currentTimeXMLGregorianCalendar(); @@ -413,7 +413,7 @@ public void test130PasswordLoginLockout() throws Exception { } catch (BadCredentialsException e) { // This is expected - display("expected exception", e); + displayException("expected exception", e); assertBadPasswordException(e); } @@ -430,7 +430,7 @@ public void test130PasswordLoginLockout() throws Exception { } catch (BadCredentialsException e) { // This is expected - display("expected exception", e); + displayException("expected exception", e); assertBadPasswordException(e); } @@ -464,7 +464,7 @@ public void test132PasswordLoginLockedoutGoodPassword() throws Exception { // THEN then(); - display("expected exception", e); + displayException("expected exception", e); assertLockedException(e); } @@ -491,7 +491,7 @@ public void test133PasswordLoginLockedoutBadPassword() throws Exception { // THEN then(); - display("expected exception", e); + displayException("expected exception", e); // this is important. The exception should give no indication whether the password is // good or bad @@ -546,7 +546,7 @@ public void test136PasswordLoginLockoutAgain() throws Exception { // THEN then(); - display("expected exception", e); + displayException("expected exception", e); assertBadPasswordException(e); } @@ -565,7 +565,7 @@ public void test136PasswordLoginLockoutAgain() throws Exception { // THEN then(); - display("expected exception", e); + displayException("expected exception", e); assertBadPasswordException(e); } @@ -584,7 +584,7 @@ public void test136PasswordLoginLockoutAgain() throws Exception { // THEN then(); - display("expected exception", e); + displayException("expected exception", e); assertBadPasswordException(e); } @@ -615,7 +615,7 @@ public void test137PasswordLoginLockedoutGoodPasswordAgain() throws Exception { // THEN then(); - display("expected exception", e); + displayException("expected exception", e); assertLockedException(e); } @@ -685,7 +685,7 @@ public void test139TryToLockByModelService() throws Exception { // THEN then(); - display("expected exception", e); + displayException("expected exception", e); } @@ -883,7 +883,7 @@ public void test202UserGuybrushPasswordLoginBadPassword() throws Exception { // THEN then(); - display("expected exception", e); + displayException("expected exception", e); assertBadPasswordException(e); } XMLGregorianCalendar endTs = clock.currentTimeXMLGregorianCalendar(); @@ -938,7 +938,7 @@ public void test210UserGuybrushPasswordLoginGoodPasswordExpired() throws Excepti // THEN then(); - display("expected exception", e); + displayException("expected exception", e); assertExpiredException(e); } @@ -1069,7 +1069,7 @@ private void loginJackGoodPasswordExpectDenied() throws ObjectNotFoundException, // THEN then(); - display("expected exception", e); + displayException("expected exception", e); // this is important. The exception should give no indication whether the password is // good or bad diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestAudit.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestAudit.java index 824a4960500..094c7a09787 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestAudit.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestAudit.java @@ -557,7 +557,7 @@ public void test300ConcurrentAudits() throws Exception { } results.set(index, null); } catch (Throwable t) { - display("Thread " + index + " got an exception ", t); + displayException("Thread " + index + " got an exception ", t); results.set(index, t); } }); diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestModelServiceContract.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestModelServiceContract.java index a5703c41c8a..d3e2a7edde7 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestModelServiceContract.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestModelServiceContract.java @@ -163,7 +163,7 @@ public void test099ModifyUserAddAccountFailing() throws Exception { } catch (UnsupportedOperationException e) { // THEN then(); - display("Expected exception", e); + displayException("Expected exception", e); } assertFailure(result); @@ -2056,7 +2056,7 @@ public void test180ModifyUserAddAccountFullEnforcement() throws Exception { AssertJUnit.fail("Unexpected executeChanges success"); } catch (PolicyViolationException e) { // This is expected - display("Expected exception", e); + displayException("Expected exception", e); } // THEN diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestPreviewChanges.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestPreviewChanges.java index 0fb41e35d45..3a0d8a11dce 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestPreviewChanges.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestPreviewChanges.java @@ -330,7 +330,7 @@ private void doPreviewFail( AssertJUnit.fail("Expected exception, but it haven't come"); } catch (SchemaException e) { // This is expected - display("Expected exception", e); + displayException("Expected exception", e); } result.computeStatus(); diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestStrangeCases.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestStrangeCases.java index c08b4c6591a..7c935ba9d2a 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestStrangeCases.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestStrangeCases.java @@ -205,7 +205,7 @@ public void test050AddRoleRecursionAssignment() throws Exception { assertNotReached(); } catch (PolicyViolationException e) { // This is expected - display("Expected exception", e); + displayException("Expected exception", e); } // THEN @@ -280,7 +280,7 @@ public void test100ModifyUserGuybrushAddAccountDummyRedNoAttributesConflict() th AssertJUnit.fail("Unexpected executeChanges success"); } catch (ObjectAlreadyExistsException e) { // This is expected - display("Expected exception", e); + displayException("Expected exception", e); } //TODO: this is not yet expected.. there is a checking code in the ProjectionValueProcessor.. @@ -709,7 +709,7 @@ public void test230ModifyUserJackUserTemplatePolicyViolation() throws Exception // THEN then(); - display("Exception (expected)", e); + displayException("Exception (expected)", e); assertExceptionUserFriendly(e, "We do not serve your kind here"); display("Result", result); @@ -911,7 +911,7 @@ public void test332AssignDeGhoulashRecursion() throws Exception { assertNotReached(); } catch (PolicyViolationException e) { // This is expected - display("Expected exception", e); + displayException("Expected exception", e); } // THEN diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/archetypes/TestArchetypes.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/archetypes/TestArchetypes.java index d267cd39e38..f0de021b365 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/archetypes/TestArchetypes.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/archetypes/TestArchetypes.java @@ -766,7 +766,7 @@ public void test162AddFraudster() throws Exception { assertNotReached(); } catch (PolicyViolationException e) { // Expected - display("Expected exception", e); + displayException("Expected exception", e); } // THEN diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/mapping/TestMapping.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/mapping/TestMapping.java index ae72befcea3..80fac366577 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/mapping/TestMapping.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/mapping/TestMapping.java @@ -3067,7 +3067,7 @@ public void test420AssignAntinihilistToJack() throws Exception { assignRole(USER_JACK_OID, ROLE_ANTINIHILIST_OID, task, result); } catch (ExpressionEvaluationException e) { - display("Exception", e); + displayException("Exception", e); Throwable cause = e.getCause(); if (!(cause instanceof AssertionError)) { throw e; diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/multi/TestMultiResource.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/multi/TestMultiResource.java index 9199ef7896e..4e567158282 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/multi/TestMultiResource.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/multi/TestMultiResource.java @@ -264,7 +264,7 @@ public void test121JackTryDeleteAccount() throws Exception { AssertJUnit.fail("Unexpected success"); } catch (PolicyViolationException e) { // This is expected - display("Expected exception", e); + displayException("Expected exception", e); } } @@ -1319,7 +1319,7 @@ public void test350AddAccountLavender() throws Exception { AssertJUnit.fail("Unexpected success"); } catch (PolicyViolationException e) { // this is expected - display("Expected exception", e); + displayException("Expected exception", e); } // THEN @@ -1442,7 +1442,7 @@ public void test370DeleteAccountDummy() throws Exception { AssertJUnit.fail("Unexpected success"); } catch (PolicyViolationException e) { // this is expected - display("Expected exception", e); + displayException("Expected exception", e); } // THEN @@ -1477,7 +1477,7 @@ public void test372UnlinkAccountDummy() throws Exception { AssertJUnit.fail("Unexpected success"); } catch (PolicyViolationException e) { // this is expected - display("Expected exception", e); + displayException("Expected exception", e); } // THEN diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/negative/TestAssignmentErrors.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/negative/TestAssignmentErrors.java index 0cf2d760efc..562991a9041 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/negative/TestAssignmentErrors.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/negative/TestAssignmentErrors.java @@ -321,7 +321,7 @@ public void test210UserSharptoothAssignAccountBrokenGeneric() throws Exception { } catch (GenericConnectorException e) { // THEN then(); - display("Expected exception", e); + displayException("Expected exception", e); } assertFailure(result); diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/negative/TestBrokenResources.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/negative/TestBrokenResources.java index 4453188fe86..12d69564af1 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/negative/TestBrokenResources.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/negative/TestBrokenResources.java @@ -201,7 +201,7 @@ public void test100GetAccountMurray() throws Exception { AssertJUnit.fail("Expected SystemException but the operation was successful"); } catch (SystemException e) { // This is expected - display("Expected exception", e); + displayException("Expected exception", e); result.computeStatus(); display("getObject result", result); TestUtil.assertFailure("getObject result", result); @@ -787,7 +787,7 @@ public void test401AssignTwoResourcesBroken() throws Exception { } catch (GenericConnectorException e) { // THEN then(); - display("Expected exception", e); + displayException("Expected exception", e); } result.computeStatus(); @@ -928,7 +928,7 @@ public void test510AssignResourceBlackError() throws Exception { } catch (GenericConnectorException e) { // THEN then(); - display("Expected exception", e); + displayException("Expected exception", e); } assertFailure(result); @@ -995,7 +995,7 @@ public void test514ModifyUserEmployeeNumberRuntime() throws Exception { } catch (RuntimeException e) { // THEN then(); - display("Expected exception", e); + displayException("Expected exception", e); assertEquals("Wrong exception message", "Booom! PowerFail script failed (runtime)", e.getMessage()); } @@ -1033,7 +1033,7 @@ public void test518UnassignResourceBlack() throws Exception { } catch (RuntimeException e) { // THEN then(); - display("Expected exception", e); + displayException("Expected exception", e); assertEquals("Wrong exception message", "Booom! PowerFail script failed (runtime)", e.getMessage()); } @@ -1215,7 +1215,7 @@ public void test600GuybrushAssignAccountDummyViolet() throws Exception { assertNotReached(); } catch (ExpressionEvaluationException e) { - display("Expected exception", e); + displayException("Expected exception", e); } // THEN diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/orgstruct/TestOrgStruct.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/orgstruct/TestOrgStruct.java index 54b135b85bf..ad10c8c8f8e 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/orgstruct/TestOrgStruct.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/orgstruct/TestOrgStruct.java @@ -800,7 +800,7 @@ public void test310JackConflictParentOrgRefAndAssignmentsAddOrg() throws Excepti } catch (PolicyViolationException e) { // THEN then(); - display("Expected exception", e); + displayException("Expected exception", e); assertFailure(result); } diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/password/AbstractPasswordTest.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/password/AbstractPasswordTest.java index 65dd3b4dfcf..18c3d0f8327 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/password/AbstractPasswordTest.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/password/AbstractPasswordTest.java @@ -1189,7 +1189,7 @@ public void test222ModifyUserJackPasswordBadContainer() throws Exception { } catch (PolicyViolationException e) { // This is expected - display("Expected exception", e); + displayException("Expected exception", e); } // THEN @@ -1333,7 +1333,7 @@ private void doTestModifyUserJackPasswordFailureWithHistory( } catch (PolicyViolationException e) { // This is expected - display("Exected exception", e); + displayException("Exected exception", e); } // THEN @@ -1401,7 +1401,7 @@ public void test300TwoParentOrgRefs() throws Exception { AssertJUnit.fail("Unexpected success"); } catch (PolicyViolationException e) { // This is expected - display("Expected exception", e); + displayException("Expected exception", e); } // THEN diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/persona/TestPersonaPassword.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/persona/TestPersonaPassword.java index c97c0a6786f..808477a42bd 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/persona/TestPersonaPassword.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/persona/TestPersonaPassword.java @@ -87,7 +87,7 @@ public void test145ModifyPersonaPasswordBack() throws Exception { assertNotReached(); } catch (PolicyViolationException e) { // expected - display("expected exception", e); + displayException("expected exception", e); } // THEN diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/rbac/TestRbac.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/rbac/TestRbac.java index 37bf55015a3..0874a0b83b1 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/rbac/TestRbac.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/rbac/TestRbac.java @@ -1628,7 +1628,7 @@ public void test602JackAssignRolePirate() throws Exception { AssertJUnit.fail("Unexpected success"); } catch (PolicyViolationException e) { // this is expected - display("Expected exception", e); + displayException("Expected exception", e); assertMessage(e, "Violation of SoD policy: Role \"Judge\" excludes role \"Pirate\", they cannot be assigned at the same time"); } @@ -1753,7 +1753,7 @@ public void test612JackAssignRoleGovernor() throws Exception { AssertJUnit.fail("Unexpected success"); } catch (PolicyViolationException e) { // this is expected - display("Expected exception", e); + displayException("Expected exception", e); assertMessage(e, "Role \"Governor\" requires at most 1 assignees with the relation of \"default\". The operation would result in 2 assignees."); } @@ -1787,7 +1787,7 @@ public void test613JackAssignRoleGovernorAsApprover() throws Exception { AssertJUnit.fail("Unexpected success"); } catch (PolicyViolationException e) { // this is expected - display("Expected exception", e); + displayException("Expected exception", e); assertMessage(e, "Role \"Governor\" requires at most 0 assignees with the relation of \"approver\". The operation would result in 1 assignees."); } @@ -1912,7 +1912,7 @@ public void test625BignoseAssignRoleCanibal() throws Exception { AssertJUnit.fail("Unexpected success"); } catch (PolicyViolationException e) { // this is expected - display("Expected exception", e); + displayException("Expected exception", e); assertMessage(e, "Role \"Cannibal\" requires at most 3 assignees with the relation of \"default\". The operation would result in 4 assignees."); } @@ -1967,7 +1967,7 @@ public void test628RedskullUnassignRoleCanibal() throws Exception { AssertJUnit.fail("Unexpected success"); } catch (PolicyViolationException e) { // this is expected - display("Expected exception", e); + displayException("Expected exception", e); assertMessage(e, "Role \"Cannibal\" requires at least 2 assignees with the relation of \"default\". The operation would result in 1 assignees."); } @@ -2035,7 +2035,7 @@ public void test632RappUnassignRoleCannibalAsOwner() throws Exception { AssertJUnit.fail("Unexpected success"); } catch (PolicyViolationException e) { // this is expected - display("Expected exception", e); + displayException("Expected exception", e); assertMessage(e, "Role \"Cannibal\" requires at least 1 assignees with the relation of \"owner\". The operation would result in 0 assignees."); } diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/security/TestSecurityBasic.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/security/TestSecurityBasic.java index 23d4e398ebf..859dd85f987 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/security/TestSecurityBasic.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/security/TestSecurityBasic.java @@ -1532,7 +1532,7 @@ private void assertJack24xManager(boolean fullControl) throws Exception { addObject(ORG_CHEATERS_FILE, task, result); // MID-3874 assertNotReached(); } catch (PolicyViolationException e) { - display("Expected exception", e); + displayException("Expected exception", e); assertFailure(result); } @@ -1584,7 +1584,7 @@ private void assertJack24xManager(boolean fullControl) throws Exception { } catch (SchemaException e) { // This is expected. The authorizations will mix on-resource and off-resource search. - display("Expected exception", e); + displayException("Expected exception", e); } result.computeStatus(); TestUtil.assertFailure(result); @@ -1668,7 +1668,7 @@ private void assertJack24xManagerDefense(boolean fullControl) throws Exception { } catch (SchemaException e) { // This is expected. The authorizations will mix on-resource and off-resource search. - display("Expected exception", e); + displayException("Expected exception", e); } assertFailure(result); diff --git a/model/report-impl/src/test/java/com/evolveum/midpoint/report/TestReportWebService.java b/model/report-impl/src/test/java/com/evolveum/midpoint/report/TestReportWebService.java index f6584446cc4..b2a8ee7e7e2 100644 --- a/model/report-impl/src/test/java/com/evolveum/midpoint/report/TestReportWebService.java +++ b/model/report-impl/src/test/java/com/evolveum/midpoint/report/TestReportWebService.java @@ -91,7 +91,7 @@ public void test110ProcessReportUserListNoReportOid() { } catch (Fault f) { // THEN then(); - display("Expected fault", f); + displayException("Expected fault", f); } } @@ -111,7 +111,7 @@ public void test112ProcessReportUserListInvalidReportOid() { } catch (Fault f) { // THEN then(); - display("Expected fault", f); + displayException("Expected fault", f); } } @@ -136,7 +136,7 @@ public void test115ProcessReportUserListUnauthorizedReader() throws Exception { } catch (Fault f) { // THEN then(); - display("Expected fault", f); + displayException("Expected fault", f); } finally { login(USER_ADMINISTRATOR_USERNAME); } @@ -163,7 +163,7 @@ public void test116ProcessReportUserListUnauthorizedRunner() throws Exception { } catch (Fault f) { // THEN then(); - display("Expected fault", f); + displayException("Expected fault", f); } finally { login(USER_ADMINISTRATOR_USERNAME); } diff --git a/model/workflow-impl/src/test/java/com/evolveum/midpoint/wf/impl/AbstractWfTest.java b/model/workflow-impl/src/test/java/com/evolveum/midpoint/wf/impl/AbstractWfTest.java index d291ee0d736..0b50456aea4 100644 --- a/model/workflow-impl/src/test/java/com/evolveum/midpoint/wf/impl/AbstractWfTest.java +++ b/model/workflow-impl/src/test/java/com/evolveum/midpoint/wf/impl/AbstractWfTest.java @@ -251,7 +251,7 @@ public void timeout() { try { task.refresh(waitResult); } catch (Throwable e) { - display("Exception during task refresh", e); + displayException("Exception during task refresh", e); } OperationResult result = task.getResult(); display("Result of timed-out task", result); diff --git a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummy.java b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummy.java index 4c92069e8a3..095b840dcd7 100644 --- a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummy.java +++ b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummy.java @@ -231,7 +231,7 @@ public void test107AGetModifiedAccountFromCacheMax() throws Exception { } catch (ConfigurationException e) { // Caching is disabled, this is expected. then(); - display("Expected exception", e); + displayException("Expected exception", e); assertFailure(result); } @@ -1997,7 +1997,7 @@ public boolean handle(PrismObject object, OperationResult parentResu } catch (SchemaException e) { // This is expected - display("Expected exception", e); + displayException("Expected exception", e); } // THEN @@ -3740,7 +3740,7 @@ public void test502ModifyProtectedAccountShadowAttributes() throws Exception { AssertJUnit.fail("Expected security exception while modifying 'daemon' account"); } catch (SecurityViolationException e) { // This is expected - display("Expected exception", e); + displayException("Expected exception", e); } result.computeStatus(); @@ -3802,7 +3802,7 @@ public void test509DeleteProtectedAccountShadow() throws Exception { } catch (SecurityViolationException e) { // This is expected then(); - display("Expected exception", e); + displayException("Expected exception", e); } assertFailure(result); @@ -3951,7 +3951,7 @@ public void test600AddAccountAlreadyExist() throws Exception { } catch (ObjectAlreadyExistsException e) { // This is expected then(); - display("Expected exception", e); + displayException("Expected exception", e); } // THEN diff --git a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummyConsistency.java b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummyConsistency.java index 942ff84f1bd..6a91ea7d6fd 100644 --- a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummyConsistency.java +++ b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummyConsistency.java @@ -1417,7 +1417,7 @@ public void test800AddAccountMorganAlreadyExists() throws Exception { assertNotReached(); } catch (ObjectAlreadyExistsException e) { then(); - display("expected exception", e); + displayException("expected exception", e); } // THEN @@ -1495,7 +1495,7 @@ public void test802AddAccountMorganAlreadyExistsAgain() throws Exception { assertNotReached(); } catch (ObjectAlreadyExistsException e) { then(); - display("expected exception", e); + displayException("expected exception", e); } // THEN @@ -1614,7 +1614,7 @@ public void test806RenameAccountElizabethAlreadyExists() throws Exception { assertNotReached(); } catch (ObjectAlreadyExistsException e) { then(); - display("expected exception", e); + displayException("expected exception", e); } // THEN @@ -1692,7 +1692,7 @@ public void test808RenameAccountElizabethAlreadyExistsAgain() throws Exception { assertNotReached(); } catch (ObjectAlreadyExistsException e) { then(); - display("expected exception", e); + displayException("expected exception", e); } // THEN @@ -1852,7 +1852,7 @@ public void test812ModifyAccountWillNotFound() throws Exception { assertNotReached(); } catch (ObjectNotFoundException e) { then(); - display("expected exception", e); + displayException("expected exception", e); } // THEN @@ -1991,7 +1991,7 @@ public void test816AddAccountElizabethAfterDeathAlreadyExists() throws Exception provisioningService.addObject(account, null, null, task, result); } catch (ObjectAlreadyExistsException e) { then(); - display("expected exception", e); + displayException("expected exception", e); } // THEN diff --git a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummyNegative.java b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummyNegative.java index 5c4f77679b5..696a95ec261 100644 --- a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummyNegative.java +++ b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummyNegative.java @@ -137,7 +137,7 @@ public void test200AddAccountNullAttributes() throws Exception { assertNotReached(); } catch (SchemaException e) { // This is expected - display("Expected exception", e); + displayException("Expected exception", e); } then(); @@ -166,7 +166,7 @@ public void test201AddAccountEmptyAttributes() throws Exception { AssertJUnit.fail("The addObject operation was successful. But expecting an exception."); } catch (SchemaException e) { // This is expected - display("Expected exception", e); + displayException("Expected exception", e); } syncServiceMock.assertNotifyFailureOnly(); @@ -196,7 +196,7 @@ public void test210AddAccountNoObjectClass() throws Exception { AssertJUnit.fail("The addObject operation was successful. But expecting an exception."); } catch (SchemaException e) { // This is expected - display("Expected exception", e); + displayException("Expected exception", e); } syncServiceMock.assertNotifyFailureOnly(); @@ -224,7 +224,7 @@ public void test220AddAccountNoResourceRef() throws Exception { AssertJUnit.fail("The addObject operation was successful. But expecting an exception."); } catch (SchemaException e) { // This is expected - display("Expected exception", e); + displayException("Expected exception", e); } //FIXME: not sure, if this check is needed..if the resource is not specified, provisioning probably will be not called. @@ -254,7 +254,7 @@ public void test221DeleteAccountResourceNotFound() throws Exception { // AssertJUnit.fail("The addObject operation was successful. But expecting an exception."); } catch (SchemaException e) { // This is expected - display("Expected exception", e); + displayException("Expected exception", e); } //FIXME: is this really notify failure? the resource does not exist but shadow is deleted. maybe other case of notify? @@ -288,7 +288,7 @@ public void test230GetAccountDeletedShadow() throws Exception { assertNotReached(); } catch (ObjectNotFoundException e) { // this is expected - display("Expected exception", e); + displayException("Expected exception", e); result.computeStatus(); display("Result", result); TestUtil.assertFailure(result); diff --git a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummySecurity.java b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummySecurity.java index c9083560523..8462325d10b 100644 --- a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummySecurity.java +++ b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummySecurity.java @@ -70,7 +70,7 @@ public void test100AddAccountDrink() throws Exception { AssertJUnit.fail("Unexpected success"); } catch (SecurityViolationException e) { // This is expected - display("Expected exception", e); + displayException("Expected exception", e); } } @@ -191,7 +191,7 @@ public void test210ModifyAccountQuote() throws Exception { } catch (SecurityViolationException e) { // This is expected - display("Expected exception", e); + displayException("Expected exception", e); } } diff --git a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/opendj/TestOpenDj.java b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/opendj/TestOpenDj.java index b6b965d22fa..0f43f688692 100644 --- a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/opendj/TestOpenDj.java +++ b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/opendj/TestOpenDj.java @@ -884,7 +884,7 @@ public void test130AddDeleteAccountSparrow() throws Exception { provisioningService.getObject(ShadowType.class, ACCOUNT_SPARROW_OID, null, task, result); Assert.fail("Expected exception ObjectNotFoundException, but haven't got one."); } catch (ObjectNotFoundException ex) { - display("Expected exception", ex); + displayException("Expected exception", ex); } try { @@ -892,7 +892,7 @@ public void test130AddDeleteAccountSparrow() throws Exception { // objType = container.getObject(); Assert.fail("Expected exception, but haven't got one."); } catch (ObjectNotFoundException ex) { - display("Expected exception", ex); + displayException("Expected exception", ex); assertTrue(ex.getMessage().contains(ACCOUNT_SPARROW_OID)); } @@ -2011,7 +2011,7 @@ public void test300AddObjectObjectAlreadyExistResource() throws Exception { } catch (ObjectAlreadyExistsException e) { // This is expected - display("Expected exception", e); + displayException("Expected exception", e); // The exception should originate from the LDAP layers IntegrationTestTools.assertInMessageRecursive(e, "LDAP"); @@ -2037,7 +2037,7 @@ public void test310AddObjectNoSn() throws Exception { } catch (SchemaException e) { // This is expected - display("Expected exception", e); + displayException("Expected exception", e); // This error should be detectable before it reaches a resource. Therefore we check that the // cause was not a LDAP exception @@ -2157,7 +2157,7 @@ public void test329DeleteAccountPosix() throws Exception { provisioningService.getObject(ShadowType.class, ACCOUNT_POSIX_MCMUTTON_OID, null, task, result); Assert.fail("Expected exception ObjectNotFoundException, but haven't got one."); } catch (ObjectNotFoundException ex) { - display("Expected exception", ex); + displayException("Expected exception", ex); } try { @@ -2165,7 +2165,7 @@ public void test329DeleteAccountPosix() throws Exception { // objType = container.getObject(); Assert.fail("Expected exception, but haven't got one."); } catch (ObjectNotFoundException ex) { - display("Expected exception", ex); + displayException("Expected exception", ex); assertTrue(ex.getMessage().contains(ACCOUNT_POSIX_MCMUTTON_OID)); } diff --git a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/opendj/TestOpenDjNegative.java b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/opendj/TestOpenDjNegative.java index dba2afa6132..9d7039376e3 100644 --- a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/opendj/TestOpenDjNegative.java +++ b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/opendj/TestOpenDjNegative.java @@ -159,7 +159,7 @@ public void test110GetObjectNoShadow() throws Exception { AssertJUnit.fail("getObject succeeded unexpectedly"); } catch (ObjectNotFoundException e) { // This is expected - display("Expected exception", e); + displayException("Expected exception", e); } result.computeStatus(); @@ -184,7 +184,7 @@ public void test111GetObjectShadow() throws Exception { // } catch (CommunicationException e) { } catch (ConfigurationException e) { // This is expected - display("Expected exception", e); + displayException("Expected exception", e); } result.computeStatus(); @@ -204,7 +204,7 @@ public void test120ListResourceObjects() throws Exception { AssertJUnit.fail("listResourceObjects succeeded unexpectedly"); } catch (ConfigurationException e) { // This is expected - display("Expected exception", e); + displayException("Expected exception", e); } result.computeStatus(); @@ -229,7 +229,7 @@ public void test121SearchAccounts() throws Exception { AssertJUnit.fail("searchObjectsIterative succeeded unexpectedly"); } catch (ConfigurationException e) { // This is expected - display("Expected exception", e); + displayException("Expected exception", e); } result.computeStatus(); @@ -264,7 +264,7 @@ public boolean handle(PrismObject prismObject, OperationResult paren AssertJUnit.fail("searchObjectsIterative succeeded unexpectedly"); } catch (ConfigurationException e) { // This is expected - display("Expected exception", e); + displayException("Expected exception", e); } result.computeStatus(); @@ -287,7 +287,7 @@ public void test130AddAccountWill() throws Exception { AssertJUnit.fail("addObject succeeded unexpectedly"); } catch (ConfigurationException e) { // This is expected - display("Expected exception", e); + displayException("Expected exception", e); } result.computeStatus(); @@ -306,7 +306,7 @@ public void test140AddDeleteAccountSparrow() throws Exception { AssertJUnit.fail("addObject succeeded unexpectedly"); } catch (ConfigurationException e) { // This is expected - display("Expected exception", e); + displayException("Expected exception", e); } result.computeStatus(); @@ -331,7 +331,7 @@ public void test150ModifyObject() throws Exception { AssertJUnit.fail("addObject succeeded unexpectedly"); } catch (ConfigurationException e) { // This is expected - display("Expected exception", e); + displayException("Expected exception", e); } result.computeStatus(); @@ -354,7 +354,7 @@ public void test190Synchronize() throws Exception { AssertJUnit.fail("addObject succeeded unexpectedly"); } catch (CommunicationException e) { // This is expected - display("Expected exception", e); + displayException("Expected exception", e); } result.computeStatus(); @@ -398,7 +398,7 @@ public void test510GetObjectNoShadow() throws Exception { AssertJUnit.fail("getObject succeeded unexpectedly"); } catch (ObjectNotFoundException e) { // This is expected - display("Expected exception", e); + displayException("Expected exception", e); } result.computeStatus(); @@ -449,7 +449,7 @@ public void test520ListResourceObjects() throws Exception { AssertJUnit.fail("listResourceObjects succeeded unexpectedly"); } catch (CommunicationException e) { // This is expected - display("Expected exception", e); + displayException("Expected exception", e); } assertFailure(result); @@ -474,7 +474,7 @@ public void test521SearchAccounts() throws SchemaException, ObjectNotFoundExcept AssertJUnit.fail("searchObjectsIterative succeeded unexpectedly"); } catch (CommunicationException e) { // This is expected - display("Expected exception", e); + displayException("Expected exception", e); } result.computeStatus(); @@ -507,7 +507,7 @@ public boolean handle(PrismObject prismObject, OperationResult paren AssertJUnit.fail("searchObjectsIterative succeeded unexpectedly"); } catch (CommunicationException e) { // This is expected - display("Expected exception", e); + displayException("Expected exception", e); } assertFailure(result); @@ -549,7 +549,7 @@ public void test530AddAccountWill() throws Exception { assertNotReached(); } catch (GenericConnectorException e) { - display("expected exception", e); + displayException("expected exception", e); } Collection> options = SelectorOptions.createCollection(GetOperationOptions.createPointInTimeType(PointInTimeType.FUTURE)); @@ -654,7 +654,7 @@ public void test590Synchronize() throws Exception { AssertJUnit.fail("addObject succeeded unexpectedly"); } catch (CommunicationException e) { // This is expected - display("Expected exception", e); + displayException("Expected exception", e); } assertFailure(result); diff --git a/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/AbstractHigherUnitTest.java b/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/AbstractHigherUnitTest.java index 5a62ddd2eaa..2de1dc04e3b 100644 --- a/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/AbstractHigherUnitTest.java +++ b/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/AbstractHigherUnitTest.java @@ -6,11 +6,7 @@ */ package com.evolveum.midpoint.test; -import static org.testng.AssertJUnit.assertEquals; -import static org.testng.AssertJUnit.assertFalse; -import static org.testng.AssertJUnit.assertNotNull; -import static org.testng.AssertJUnit.assertNull; -import static org.testng.AssertJUnit.assertTrue; +import static org.testng.AssertJUnit.*; import java.io.File; import java.io.IOException; @@ -18,13 +14,10 @@ import java.util.Collection; import java.util.List; import java.util.stream.Collectors; - import javax.xml.bind.JAXBException; import javax.xml.datatype.XMLGregorianCalendar; import javax.xml.namespace.QName; -import com.evolveum.midpoint.prism.path.ItemName; -import com.evolveum.midpoint.prism.path.ItemPath; import org.apache.commons.lang.StringUtils; import org.opends.server.types.Entry; import org.opends.server.types.SearchResultEntry; @@ -37,18 +30,11 @@ import com.evolveum.midpoint.common.refinery.RefinedObjectClassDefinition; import com.evolveum.midpoint.common.refinery.RefinedResourceSchema; import com.evolveum.midpoint.common.refinery.RefinedResourceSchemaImpl; -import com.evolveum.midpoint.prism.ConsistencyCheckScope; -import com.evolveum.midpoint.prism.Containerable; -import com.evolveum.midpoint.prism.Item; -import com.evolveum.midpoint.prism.PrismContainer; -import com.evolveum.midpoint.prism.PrismContext; -import com.evolveum.midpoint.prism.PrismObject; -import com.evolveum.midpoint.prism.PrismObjectDefinition; -import com.evolveum.midpoint.prism.PrismProperty; -import com.evolveum.midpoint.prism.PrismReference; -import com.evolveum.midpoint.prism.PrismValue; +import com.evolveum.midpoint.prism.*; import com.evolveum.midpoint.prism.delta.ObjectDelta; import com.evolveum.midpoint.prism.match.MatchingRule; +import com.evolveum.midpoint.prism.path.ItemName; +import com.evolveum.midpoint.prism.path.ItemPath; import com.evolveum.midpoint.prism.polystring.PolyString; import com.evolveum.midpoint.prism.query.ObjectFilter; import com.evolveum.midpoint.prism.query.builder.S_FilterEntryOrEmpty; @@ -65,31 +51,16 @@ import com.evolveum.midpoint.schema.util.ResourceTypeUtil; import com.evolveum.midpoint.schema.util.ShadowUtil; import com.evolveum.midpoint.task.api.Task; -import com.evolveum.midpoint.tools.testng.AbstractUnitTest; import com.evolveum.midpoint.test.util.MidPointTestConstants; import com.evolveum.midpoint.test.util.TestUtil; +import com.evolveum.midpoint.tools.testng.AbstractUnitTest; import com.evolveum.midpoint.util.DebugDumpable; import com.evolveum.midpoint.util.LocalizableMessage; import com.evolveum.midpoint.util.PrettyPrinter; import com.evolveum.midpoint.util.exception.CommonException; import com.evolveum.midpoint.util.exception.ObjectNotFoundException; import com.evolveum.midpoint.util.exception.SchemaException; -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.AssignmentType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.CredentialsStorageTypeType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.FocusType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.LockoutStatusType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.OperationResultType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.OrgType; -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.TimeIntervalStatusType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.*; import com.evolveum.prism.xml.ns._public.types_3.PolyStringType; /** @@ -144,29 +115,29 @@ protected static ObjectType unmarshallValueFromFile(String filePath) throws IOEx } protected void assertNoChanges(ObjectDelta delta) { - assertNull("Unexpected changes: "+ delta, delta); + assertNull("Unexpected changes: " + delta, delta); } protected void assertNoChanges(String desc, ObjectDelta delta) { - assertNull("Unexpected changes in "+desc+": "+ delta, delta); + assertNull("Unexpected changes in " + desc + ": " + delta, delta); } - protected void assertEffectiveActivation(PrismObject focus, ActivationStatusType expected) { + protected void assertEffectiveActivation(PrismObject focus, ActivationStatusType expected) { ActivationType activationType = focus.asObjectable().getActivation(); - assertNotNull("No activation in "+focus, activationType); - assertEquals("Wrong effectiveStatus in activation in "+focus, expected, activationType.getEffectiveStatus()); + assertNotNull("No activation in " + focus, activationType); + assertEquals("Wrong effectiveStatus in activation in " + focus, expected, activationType.getEffectiveStatus()); } - protected void assertEffectiveActivation(AssignmentType assignmentType, ActivationStatusType expected) { + protected void assertEffectiveActivation(AssignmentType assignmentType, ActivationStatusType expected) { ActivationType activationType = assignmentType.getActivation(); - assertNotNull("No activation in "+assignmentType, activationType); - assertEquals("Wrong effectiveStatus in activation in "+assignmentType, expected, activationType.getEffectiveStatus()); + assertNotNull("No activation in " + assignmentType, activationType); + assertEquals("Wrong effectiveStatus in activation in " + assignmentType, expected, activationType.getEffectiveStatus()); } - protected void assertValidityStatus(PrismObject focus, TimeIntervalStatusType expected) { + protected void assertValidityStatus(PrismObject focus, TimeIntervalStatusType expected) { ActivationType activationType = focus.asObjectable().getActivation(); - assertNotNull("No activation in "+focus, activationType); - assertEquals("Wrong validityStatus in activation in "+focus, expected, activationType.getValidityStatus()); + assertNotNull("No activation in " + focus, activationType); + assertEquals("Wrong validityStatus in activation in " + focus, expected, activationType.getValidityStatus()); } protected void assertShadow(PrismObject shadow) { @@ -175,9 +146,9 @@ protected void assertShadow(PrismObject shadow) { protected void assertObject(PrismObject object) { object.checkConsistence(true, true, ConsistencyCheckScope.THOROUGH); - assertTrue("Incomplete definition in "+object, object.hasCompleteDefinition()); + assertTrue("Incomplete definition in " + object, object.hasCompleteDefinition()); assertFalse("No OID", StringUtils.isEmpty(object.getOid())); - assertNotNull("Null name in "+object, object.asObjectable().getName()); + assertNotNull("Null name in " + object, object.asObjectable().getName()); } protected void assertUser(PrismObject user, String oid, String name, String fullName, String givenName, String familyName) { @@ -191,10 +162,10 @@ protected void assertUser(PrismObject user, String oid, String name, S assertEquals("Wrong " + user + " OID (prism)", oid, user.getOid()); assertEquals("Wrong " + user + " OID (jaxb)", oid, userType.getOid()); } - PrismAsserts.assertEqualsPolyString("Wrong "+user+" name", name, userType.getName()); - PrismAsserts.assertEqualsPolyString("Wrong "+user+" fullName", fullName, userType.getFullName()); - PrismAsserts.assertEqualsPolyString("Wrong "+user+" givenName", givenName, userType.getGivenName()); - PrismAsserts.assertEqualsPolyString("Wrong "+user+" familyName", familyName, userType.getFamilyName()); + PrismAsserts.assertEqualsPolyString("Wrong " + user + " name", name, userType.getName()); + PrismAsserts.assertEqualsPolyString("Wrong " + user + " fullName", fullName, userType.getFullName()); + PrismAsserts.assertEqualsPolyString("Wrong " + user + " givenName", givenName, userType.getGivenName()); + PrismAsserts.assertEqualsPolyString("Wrong " + user + " familyName", familyName, userType.getFamilyName()); if (location != null) { PrismAsserts.assertEqualsPolyString("Wrong " + user + " location", location, @@ -203,7 +174,7 @@ protected void assertUser(PrismObject user, String oid, String name, S } protected void assertSubtype(PrismObject object, String subtype) { - assertTrue("Object "+object+" does not have subtype "+subtype, FocusTypeUtil.hasSubtype(object, subtype)); + assertTrue("Object " + object + " does not have subtype " + subtype, FocusTypeUtil.hasSubtype(object, subtype)); } protected void assertShadowCommon(PrismObject accountShadow, String oid, String username, ResourceType resourceType, QName objectClass) throws SchemaException { @@ -215,8 +186,8 @@ protected void assertAccountShadowCommon(PrismObject accountShadow, } protected void assertAccountShadowCommon(PrismObject accountShadow, String oid, String username, ResourceType resourceType, - MatchingRule nameMatchingRule, boolean requireNormalizedIdentfiers) throws SchemaException { - assertShadowCommon(accountShadow,oid,username,resourceType,getAccountObjectClass(resourceType),nameMatchingRule, requireNormalizedIdentfiers); + MatchingRule nameMatchingRule, boolean requireNormalizedIdentfiers) throws SchemaException { + assertShadowCommon(accountShadow, oid, username, resourceType, getAccountObjectClass(resourceType), nameMatchingRule, requireNormalizedIdentfiers); } protected QName getAccountObjectClass(ResourceType resourceType) { @@ -233,7 +204,7 @@ protected void assertShadowCommon(PrismObject shadow, String oid, St } protected void assertShadowCommon(PrismObject shadow, String oid, String username, ResourceType resourceType, - QName objectClass, final MatchingRule nameMatchingRule, boolean requireNormalizedIdentfiers, boolean useMatchingRuleForShadowName) throws SchemaException { + QName objectClass, final MatchingRule nameMatchingRule, boolean requireNormalizedIdentfiers, boolean useMatchingRuleForShadowName) throws SchemaException { assertShadow(shadow); if (oid != null) { assertEquals("Shadow OID mismatch (prism)", oid, shadow.getOid()); @@ -245,8 +216,8 @@ protected void assertShadowCommon(PrismObject shadow, String oid, St assertEquals("Shadow objectclass", objectClass, resourceObjectShadowType.getObjectClass()); assertEquals("Shadow resourceRef OID", resourceType.getOid(), shadow.asObjectable().getResourceRef().getOid()); PrismContainer attributesContainer = shadow.findContainer(ShadowType.F_ATTRIBUTES); - assertNotNull("Null attributes in shadow for "+username, attributesContainer); - assertFalse("Empty attributes in shadow for "+username, attributesContainer.isEmpty()); + assertNotNull("Null attributes in shadow for " + username, attributesContainer); + assertFalse("Empty attributes in shadow for " + username, attributesContainer.isEmpty()); if (useMatchingRuleForShadowName) { MatchingRule polyMatchingRule = new MatchingRule() { @@ -287,14 +258,14 @@ public PolyString normalize(PolyString original) throws SchemaException { if (ocDef.getSecondaryIdentifiers().isEmpty()) { ResourceAttributeDefinition idDef = ocDef.getPrimaryIdentifiers().iterator().next(); PrismProperty idProp = attributesContainer.findProperty(idDef.getItemName()); - assertNotNull("No primary identifier ("+idDef.getItemName()+") attribute in shadow for "+username, idProp); + assertNotNull("No primary identifier (" + idDef.getItemName() + ") attribute in shadow for " + username, idProp); if (nameMatchingRule == null) { - assertEquals("Unexpected primary identifier in shadow for "+username, username, idProp.getRealValue()); + assertEquals("Unexpected primary identifier in shadow for " + username, username, idProp.getRealValue()); } else { if (requireNormalizedIdentfiers) { - assertEquals("Unexpected primary identifier in shadow for "+username, nameMatchingRule.normalize(username), idProp.getRealValue()); + assertEquals("Unexpected primary identifier in shadow for " + username, nameMatchingRule.normalize(username), idProp.getRealValue()); } else { - PrismAsserts.assertEquals("Unexpected primary identifier in shadow for "+username, nameMatchingRule, username, idProp.getRealValue()); + PrismAsserts.assertEquals("Unexpected primary identifier in shadow for " + username, nameMatchingRule, username, idProp.getRealValue()); } } } else { @@ -304,10 +275,10 @@ public PolyString normalize(PolyString original) throws SchemaException { expected = nameMatchingRule.normalize(username); } List wasValues = new ArrayList<>(); - for (ResourceAttributeDefinition idSecDef: ocDef.getSecondaryIdentifiers()) { + for (ResourceAttributeDefinition idSecDef : ocDef.getSecondaryIdentifiers()) { PrismProperty idProp = attributesContainer.findProperty(idSecDef.getItemName()); wasValues.addAll(idProp.getRealValues()); - assertNotNull("No secondary identifier ("+idSecDef.getItemName()+") attribute in shadow for "+username, idProp); + assertNotNull("No secondary identifier (" + idSecDef.getItemName() + ") attribute in shadow for " + username, idProp); if (nameMatchingRule == null) { if (username.equals(idProp.getRealValue())) { found = true; @@ -326,7 +297,7 @@ public PolyString normalize(PolyString original) throws SchemaException { } } if (!found) { - fail("Unexpected secondary identifier in shadow for "+username+", expected "+expected+" but was "+wasValues); + fail("Unexpected secondary identifier in shadow for " + username + ", expected " + expected + " but was " + wasValues); } } } @@ -337,17 +308,17 @@ protected void assertShadowSecondaryIdentifier(PrismObject shadow, S ResourceAttributeDefinition idSecDef = ocDef.getSecondaryIdentifiers().iterator().next(); PrismContainer attributesContainer = shadow.findContainer(ShadowType.F_ATTRIBUTES); PrismProperty idProp = attributesContainer.findProperty(idSecDef.getItemName()); - assertNotNull("No secondary identifier ("+idSecDef.getItemName()+") attribute in shadow for "+expectedIdentifier, idProp); + assertNotNull("No secondary identifier (" + idSecDef.getItemName() + ") attribute in shadow for " + expectedIdentifier, idProp); if (nameMatchingRule == null) { - assertEquals("Unexpected secondary identifier in shadow for "+expectedIdentifier, expectedIdentifier, idProp.getRealValue()); + assertEquals("Unexpected secondary identifier in shadow for " + expectedIdentifier, expectedIdentifier, idProp.getRealValue()); } else { - PrismAsserts.assertEquals("Unexpected secondary identifier in shadow for "+expectedIdentifier, nameMatchingRule, expectedIdentifier, idProp.getRealValue()); + PrismAsserts.assertEquals("Unexpected secondary identifier in shadow for " + expectedIdentifier, nameMatchingRule, expectedIdentifier, idProp.getRealValue()); } } protected void assertShadowName(PrismObject shadow, String expectedName) { - PrismAsserts.assertEqualsPolyString("Shadow name is wrong in "+shadow, expectedName, shadow.asObjectable().getName()); + PrismAsserts.assertEqualsPolyString("Shadow name is wrong in " + shadow, expectedName, shadow.asObjectable().getName()); } protected void assertShadowName(ShadowType shadowType, String expectedName) { @@ -372,9 +343,9 @@ protected PrismObjectDefinition getShadowDefinition() { // objectClassName may be null protected RefinedAttributeDefinition getAttributeDefinition(ResourceType resourceType, - ShadowKindType kind, - QName objectClassName, - String attributeLocalName) throws SchemaException { + ShadowKindType kind, + QName objectClassName, + String attributeLocalName) throws SchemaException { RefinedResourceSchema refinedResourceSchema = RefinedResourceSchemaImpl.getRefinedSchema(resourceType); RefinedObjectClassDefinition refinedObjectClassDefinition = refinedResourceSchema.findRefinedDefinitionByObjectClassQName(kind, objectClassName); @@ -383,26 +354,25 @@ protected RefinedAttributeDefinition getAttributeDefinition(ResourceType resourc protected void assertFilter(ObjectFilter filter, Class expectedClass) { if (expectedClass == null) { - assertNull("Expected that filter is null, but it was "+filter, filter); + assertNull("Expected that filter is null, but it was " + filter, filter); } else { - assertNotNull("Expected that filter is of class "+expectedClass.getName()+", but it was null", filter); + assertNotNull("Expected that filter is of class " + expectedClass.getName() + ", but it was null", filter); if (!(expectedClass.isAssignableFrom(filter.getClass()))) { - AssertJUnit.fail("Expected that filter is of class "+expectedClass.getName()+", but it was "+filter); + AssertJUnit.fail("Expected that filter is of class " + expectedClass.getName() + ", but it was " + filter); } } } - protected void assertActivationAdministrativeStatus(PrismObject shadow, ActivationStatusType expectedStatus) { ActivationType activationType = shadow.asObjectable().getActivation(); if (activationType == null) { if (expectedStatus == null) { return; } else { - AssertJUnit.fail("Expected activation administrative status of "+shadow+" to be "+expectedStatus+", but there was no activation administrative status"); + AssertJUnit.fail("Expected activation administrative status of " + shadow + " to be " + expectedStatus + ", but there was no activation administrative status"); } } else { - assertEquals("Wrong activation administrative status of "+shadow, expectedStatus, activationType.getAdministrativeStatus()); + assertEquals("Wrong activation administrative status of " + shadow, expectedStatus, activationType.getAdministrativeStatus()); } } @@ -412,10 +382,10 @@ protected void assertShadowLockout(PrismObject shadow, LockoutStatus if (expectedStatus == null) { return; } else { - AssertJUnit.fail("Expected lockout status of "+shadow+" to be "+expectedStatus+", but there was no lockout status"); + AssertJUnit.fail("Expected lockout status of " + shadow + " to be " + expectedStatus + ", but there was no lockout status"); } } else { - assertEquals("Wrong lockout status of "+shadow, expectedStatus, activationType.getLockoutStatus()); + assertEquals("Wrong lockout status of " + shadow, expectedStatus, activationType.getLockoutStatus()); } } @@ -425,10 +395,10 @@ protected void assertUserLockout(PrismObject user, LockoutStatusType e if (expectedStatus == null) { return; } else { - AssertJUnit.fail("Expected lockout status of "+user+" to be "+expectedStatus+", but there was no lockout status"); + AssertJUnit.fail("Expected lockout status of " + user + " to be " + expectedStatus + ", but there was no lockout status"); } } else { - assertEquals("Wrong lockout status of "+user, expectedStatus, activationType.getLockoutStatus()); + assertEquals("Wrong lockout status of " + user, expectedStatus, activationType.getLockoutStatus()); } } @@ -446,12 +416,12 @@ protected ItemPath getExtensionPath(QName propName) { protected void assertNumberOfAttributes(PrismObject shadow, Integer expectedNumberOfAttributes) { PrismContainer attributesContainer = shadow.findContainer(ShadowType.F_ATTRIBUTES); - assertNotNull("No attributes in repo shadow "+shadow, attributesContainer); - Collection> attributes = attributesContainer.getValue().getItems(); + assertNotNull("No attributes in repo shadow " + shadow, attributesContainer); + Collection> attributes = attributesContainer.getValue().getItems(); - assertFalse("Empty attributes in repo shadow "+shadow, attributes.isEmpty()); + assertFalse("Empty attributes in repo shadow " + shadow, attributes.isEmpty()); if (expectedNumberOfAttributes != null) { - assertEquals("Unexpected number of attributes in repo shadow "+shadow, (int)expectedNumberOfAttributes, attributes.size()); + assertEquals("Unexpected number of attributes in repo shadow " + shadow, (int) expectedNumberOfAttributes, attributes.size()); } } @@ -491,7 +461,6 @@ protected PrismObject instantiateObject(Class type) return getPrismContext().getSchemaRegistry().findObjectDefinitionByCompileTimeClass(type).instantiate(); } - protected PrismObject parseObject(File file) throws SchemaException, IOException { return getPrismContext().parseObject(file); } @@ -560,10 +529,6 @@ public static void display(String title, Containerable value) { IntegrationTestTools.display(title, value); } - public static void display(String title, Throwable e) { - IntegrationTestTools.display(title, e); - } - public static void displayPrismValuesCollection(String message, Collection collection) { IntegrationTestTools.displayPrismValuesCollection(message, collection); } @@ -649,7 +614,7 @@ protected void assertTestResourceNotApplicable(OperationResult testResult, Conne protected void assertAttribute(PrismObject resource, ShadowType shadow, QName attrQname, T... expectedValues) { List actualValues = ShadowUtil.getAttributeValues(shadow, attrQname); - PrismAsserts.assertSets("attribute "+attrQname+" in " + shadow, actualValues, expectedValues); + PrismAsserts.assertSets("attribute " + attrQname + " in " + shadow, actualValues, expectedValues); } protected void assertAttribute(ResourceType resourceType, ShadowType shadowType, String attrName, @@ -671,7 +636,7 @@ protected void assertAttribute(PrismObject resource, ShadowTyp protected void assertAttribute(PrismObject resource, ShadowType shadow, MatchingRule matchingRule, QName attrQname, T... expectedValues) throws SchemaException { List actualValues = ShadowUtil.getAttributeValues(shadow, attrQname); - PrismAsserts.assertSets("attribute "+attrQname+" in " + shadow, matchingRule, actualValues, expectedValues); + PrismAsserts.assertSets("attribute " + attrQname + " in " + shadow, matchingRule, actualValues, expectedValues); } protected void assertNoAttribute(PrismObject resource, ShadowType shadow, ItemName attrQname) { @@ -680,7 +645,7 @@ protected void assertNoAttribute(PrismObject resource, ShadowType return; } PrismProperty attribute = attributesContainer.findProperty(attrQname); - assertNull("Unexpected attribute "+attrQname+" in "+shadow+": "+attribute, attribute); + assertNull("Unexpected attribute " + attrQname + " in " + shadow + ": " + attribute, attribute); } protected void assertNoAttribute(PrismObject resource, ShadowType shadow, String attrName) { @@ -691,14 +656,14 @@ protected void assertNoAttribute(PrismObject resource, ShadowType protected void assertLinks(PrismObject focus, int expectedNumLinks) throws ObjectNotFoundException, SchemaException { PrismReference linkRef = focus.findReference(FocusType.F_LINK_REF); if (linkRef == null) { - assert expectedNumLinks == 0 : "Expected "+expectedNumLinks+" but "+focus+" has no linkRef"; + assert expectedNumLinks == 0 : "Expected " + expectedNumLinks + " but " + focus + " has no linkRef"; return; } assertEquals("Wrong number of links in " + focus, expectedNumLinks, linkRef.size()); } protected void assertObjectOids(String message, Collection> objects, String... oids) { - List objectOids = objects.stream().map( o -> o.getOid()).collect(Collectors.toList()); + List objectOids = objects.stream().map(o -> o.getOid()).collect(Collectors.toList()); PrismAsserts.assertEqualsCollectionUnordered(message, objectOids, oids); } @@ -707,7 +672,7 @@ protected S_FilterEntryOrEmpty queryFor(Class queryClas } protected void assertMessageContains(String message, String string) { - assert message.contains(string) : "Expected message to contain '"+string+"' but it does not; message: " + message; + assert message.contains(string) : "Expected message to contain '" + string + "' but it does not; message: " + message; } protected void assertExceptionUserFriendly(CommonException e, String expectedMessage) { diff --git a/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/AbstractIntegrationTest.java b/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/AbstractIntegrationTest.java index 566c8f46e18..d0e36720c11 100644 --- a/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/AbstractIntegrationTest.java +++ b/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/AbstractIntegrationTest.java @@ -1900,14 +1900,6 @@ public static void display(String title, Containerable value) { IntegrationTestTools.display(title, value); } - public static void display(String title, Throwable e) { - IntegrationTestTools.display(title, e); - } - - public static void displayExpectedException(Throwable e) { - IntegrationTestTools.displayExpectedException(e); - } - public static void displayPrismValuesCollection(String message, Collection collection) { IntegrationTestTools.displayPrismValuesCollection(message, collection); } diff --git a/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/IntegrationTestTools.java b/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/IntegrationTestTools.java index a47d322560a..1f4a46bb24d 100644 --- a/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/IntegrationTestTools.java +++ b/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/IntegrationTestTools.java @@ -8,15 +8,12 @@ import static org.testng.AssertJUnit.*; -import java.io.IOException; -import java.io.RandomAccessFile; import java.util.*; import java.util.stream.Collectors; import javax.xml.namespace.QName; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang.StringUtils; -import org.apache.commons.lang.exception.ExceptionUtils; import org.opends.server.types.Entry; import org.opends.server.types.SearchResultEntry; import org.testng.AssertJUnit; @@ -525,25 +522,6 @@ public static void display(String title, Containerable value) { } } - /** - * Displays throwable with title including full stacktrace. - * Use for "bad" exceptions, for expected exceptions use {@link #displayExpectedException}. - */ - public static void display(String title, Throwable e) { - String stackTrace = ExceptionUtils.getStackTrace(e); - println(OBJECT_TITLE_OUT_PREFIX + title + ": " + e.getClass() + " " + e.getMessage()); - println(stackTrace); - LOGGER.debug("{}{}: {} {}\n{}", OBJECT_TITLE_LOG_PREFIX, title, e.getClass(), e.getMessage(), stackTrace); - } - - /** - * Displays expected exception without stacktrace (seeing it is rather confusing/disturbing). - */ - public static void displayExpectedException(Throwable e) { - println(OBJECT_TITLE_OUT_PREFIX + "Expected exception: " + e.getClass() + " " + e.getMessage()); - LOGGER.debug("{}Expected exception: {} {}", OBJECT_TITLE_LOG_PREFIX, e.getClass(), e.getMessage()); - } - public static void displayPrismValuesCollection(String message, Collection collection) { println(OBJECT_TITLE_OUT_PREFIX + message); LOGGER.debug(OBJECT_TITLE_LOG_PREFIX + message); @@ -843,7 +821,7 @@ public static void assertExtensionProperty( PrismAsserts.assertPropertyValue(extension, ItemName.fromQName(propertyName), expectedValues); } - public static void assertNoExtensionProperty( + public static void assertNoExtensionProperty( PrismObject object, QName propertyName) { PrismContainer extension = object.getExtension(); PrismAsserts.assertNoItem(extension, ItemName.fromQName(propertyName)); @@ -1091,13 +1069,6 @@ public static void assertConnectorSchemaSanity(PrismSchema schema, String connec } } - public static void clearLog() throws IOException { - RandomAccessFile file = new RandomAccessFile("target/test.log", "rw"); - file.setLength(0); - file.close(); - println("Log cleared."); - } - public static void assertProtectedString(String message, String expectedClearValue, ProtectedStringType actualValue, CredentialsStorageTypeType storageType, Protector protector) throws EncryptionException, SchemaException { switch (storageType) { diff --git a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestServiceAccounts.java b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestServiceAccounts.java index aa7f246ef52..20a451fa14c 100644 --- a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestServiceAccounts.java +++ b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestServiceAccounts.java @@ -152,7 +152,7 @@ serviceAccountShadowOid, getDummyResourceController().getAttributeFullnamePath() } catch (UnsupportedOperationException e) { // THEN then(); - display("expected exception", e); + displayException("expected exception", e); } assertFailure(result); @@ -197,7 +197,7 @@ public void test104DeleteServiceAccount() throws Exception { } catch (UnsupportedOperationException e) { // THEN then(); - display("expected exception", e); + displayException("expected exception", e); } assertFailure(result); @@ -373,7 +373,7 @@ public void test140CreateServiceAccount() throws Exception { } catch (UnsupportedOperationException e) { // THEN then(); - display("expected exception", e); + displayException("expected exception", e); } assertFailure(result); diff --git a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestUnix.java b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestUnix.java index 1c6c00f45c9..c4e58ea5f1d 100644 --- a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestUnix.java +++ b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestUnix.java @@ -1447,7 +1447,7 @@ public void test300AddUserCapsizeUnixFail() throws Exception { AssertJUnit.fail("Unexpected success"); } catch (ExpressionEvaluationException e) { - display("Expected exception", e); + displayException("Expected exception", e); // this is expected } diff --git a/tools/test-ng/src/main/java/com/evolveum/midpoint/tools/testng/MidpointTestMixin.java b/tools/test-ng/src/main/java/com/evolveum/midpoint/tools/testng/MidpointTestMixin.java index 8bc0017cfaa..1730cac578a 100644 --- a/tools/test-ng/src/main/java/com/evolveum/midpoint/tools/testng/MidpointTestMixin.java +++ b/tools/test-ng/src/main/java/com/evolveum/midpoint/tools/testng/MidpointTestMixin.java @@ -32,6 +32,10 @@ public interface MidpointTestMixin { String TEST_LOG_SECTION_PREFIX = "----- "; String TEST_LOG_SECTION_SUFFIX = " --------------------------------------"; + String DISPLAY_OUT_PREFIX = "\n*** "; + String DISPLAY_LOG_FORMAT1 = "*** {}"; + String DISPLAY_LOG_FORMAT2 = "*** {}:\n{}"; + /** * Context name is {@link #getTestName()} if test method context is available, * otherwise it is just a simple name of the test class. @@ -139,8 +143,27 @@ default void display(String text) { * Displays */ default void displayValue(String title, Object value) { - System.out.println("\n*** " + title + "\n" + value); - logger().debug("*** {}\n{}", title, value); + System.out.println(DISPLAY_OUT_PREFIX + title + "\n" + value); + logger().debug(DISPLAY_LOG_FORMAT2, title, value); + } + + /** + * Displays throwable with title including full stacktrace. + * Use for "bad" exceptions, for expected exceptions use {@link #displayExpectedException}. + */ + default void displayException(String title, Throwable e) { + System.out.println(DISPLAY_OUT_PREFIX + title); + e.printStackTrace(); + logger().debug(DISPLAY_LOG_FORMAT1, title, e); + } + + /** + * Displays expected exception without stacktrace (seeing it is rather confusing/disturbing). + */ + default void displayExpectedException(Throwable e) { + String expectedExceptionWithClass = "Expected exception " + e.getClass(); + System.out.println(DISPLAY_OUT_PREFIX + expectedExceptionWithClass + ":\n" + e.getMessage()); + logger().debug(DISPLAY_LOG_FORMAT2, expectedExceptionWithClass, e.getMessage()); } /** From 85332b33446a93005c192f891ef7bc44ed6fb1d3 Mon Sep 17 00:00:00 2001 From: Richard Richter Date: Tue, 17 Mar 2020 00:19:54 +0100 Subject: [PATCH 20/21] displayExpectedException() applied across tests where appropriate --- .../midpoint/prism/TestPrismParsingXml.java | 8 +- .../common/expression/TestExpression.java | 11 +- .../expression/script/AbstractScriptTest.java | 3 +- .../model/impl/lens/TestDependencies.java | 4 +- .../lens/TestPasswordPolicyProcessor.java | 3 +- .../model/impl/lens/TestPolicyRules2.java | 19 ++-- .../model/impl/lens/TestProjector.java | 4 +- .../TestAbstractAuthenticationEvaluator.java | 101 ++++-------------- .../intest/TestModelServiceContract.java | 6 +- .../model/intest/TestPreviewChanges.java | 3 +- .../model/intest/TestStrangeCases.java | 9 +- .../intest/archetypes/TestArchetypes.java | 3 +- .../intest/gensync/TestRoleEntitlement.java | 4 +- .../model/intest/multi/TestMultiResource.java | 12 +-- .../intest/negative/TestAssignmentErrors.java | 3 +- .../intest/negative/TestBrokenResources.java | 17 ++- .../model/intest/orgstruct/TestOrgStruct.java | 3 +- .../intest/password/AbstractPasswordTest.java | 6 +- .../intest/persona/TestPersonaPassword.java | 3 +- .../midpoint/model/intest/rbac/TestRbac.java | 18 ++-- .../intest/security/TestSecurityBasic.java | 13 +-- .../provisioning/impl/dummy/TestDummy.java | 15 +-- .../impl/dummy/TestDummyConsistency.java | 12 +-- .../impl/dummy/TestDummyNegative.java | 20 ++-- .../impl/dummy/TestDummySecurity.java | 7 +- .../provisioning/impl/opendj/TestOpenDj.java | 18 ++-- .../impl/opendj/TestOpenDjNegative.java | 45 +++----- .../testing/story/TestServiceAccounts.java | 9 +- .../midpoint/testing/story/TestUnix.java | 3 +- 29 files changed, 117 insertions(+), 265 deletions(-) diff --git a/infra/prism-impl/src/test/java/com/evolveum/midpoint/prism/TestPrismParsingXml.java b/infra/prism-impl/src/test/java/com/evolveum/midpoint/prism/TestPrismParsingXml.java index e6079a44141..0ba23b8a640 100644 --- a/infra/prism-impl/src/test/java/com/evolveum/midpoint/prism/TestPrismParsingXml.java +++ b/infra/prism-impl/src/test/java/com/evolveum/midpoint/prism/TestPrismParsingXml.java @@ -87,11 +87,9 @@ public void testPrismParseXxe() throws Exception { AssertJUnit.fail("Unexpected success"); } catch (IllegalStateException e) { - // THEN - System.out.println("Expected exception: "+e); + displayExpectedException(e); assertTrue("Unexpected exception message: "+e.getMessage(), e.getMessage().contains("DOCTYPE")); } - } @Test @@ -102,10 +100,8 @@ public void testPrismParseDomXxe() { AssertJUnit.fail("Unexpected success"); } catch (IllegalStateException e) { - // THEN - System.out.println("Expected exception: "+e); + displayExpectedException(e); assertTrue("Unexpected exception message: "+e.getMessage(), e.getMessage().contains("DOCTYPE")); } - } } diff --git a/model/model-common/src/test/java/com/evolveum/midpoint/model/common/expression/TestExpression.java b/model/model-common/src/test/java/com/evolveum/midpoint/model/common/expression/TestExpression.java index c01530effb7..521db481531 100644 --- a/model/model-common/src/test/java/com/evolveum/midpoint/model/common/expression/TestExpression.java +++ b/model/model-common/src/test/java/com/evolveum/midpoint/model/common/expression/TestExpression.java @@ -425,23 +425,18 @@ protected void evaluateExpressi expressionContext.getContextDescription(), expressionContext.getTask(), result); } catch (SecurityViolationException e) { - // Exception may happen here, or it may happen later. - // Expected - logger.debug("Expected exception", e); + displayExpectedException(e); assertTrue("Wrong exception message: " + e.getMessage(), e.getMessage().contains("Access to script language")); return; } logger.debug("Starting evaluation of expression (expecting security violation): {}", expression); try { - expression.evaluate(expressionContext, result); AssertJUnit.fail("Unexpected success of expression evaluation"); - } catch (SecurityViolationException e) { - // Expected - logger.debug("Expected exception", e); + displayExpectedException(e); assertTrue("Wrong exception message: " + e.getMessage(), e.getMessage().contains("Access to expression evaluator") || e.getMessage().contains("Access to Groovy method")); @@ -499,7 +494,7 @@ protected ExpressionProfile compileExpressionProfile(String profileName) throws ExpressionProfiles profiles = compiler.compile(expressions); ExpressionProfile profile = profiles.getProfile(profileName); if (profile == null) { - throw new SchemaException("Profile '" + profile + "' not found in system config"); + throw new SchemaException("Profile '" + profileName + "' not found in system config"); } return profile; } diff --git a/model/model-common/src/test/java/com/evolveum/midpoint/model/common/expression/script/AbstractScriptTest.java b/model/model-common/src/test/java/com/evolveum/midpoint/model/common/expression/script/AbstractScriptTest.java index 150554d70ce..86890526077 100644 --- a/model/model-common/src/test/java/com/evolveum/midpoint/model/common/expression/script/AbstractScriptTest.java +++ b/model/model-common/src/test/java/com/evolveum/midpoint/model/common/expression/script/AbstractScriptTest.java @@ -380,8 +380,7 @@ protected void evaluateAndAssertStringScalarExpressionRestricted( List> expressionResultList = evaluateStringExpression(fileName, testName, variables); AssertJUnit.fail("Expression " + testName + ": unexpected success, result value: " + expressionResultList); } catch (SecurityViolationException e) { - System.out.println("Expected exception: " + e); - logger.debug("Expected exception", e); + displayExpectedException(e); } } diff --git a/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestDependencies.java b/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestDependencies.java index 99e7d0d4cc0..6c16a321a21 100644 --- a/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestDependencies.java +++ b/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestDependencies.java @@ -372,10 +372,8 @@ public void test300SortToWavesXYZCircular() throws Exception { AssertJUnit.fail("Unexpected success"); } catch (PolicyViolationException e) { - // This is expected - displayException("Expected exception", e); + displayExpectedException(e); } - } private LensProjectionContext fillContextWithDummyElaineAccount( diff --git a/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestPasswordPolicyProcessor.java b/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestPasswordPolicyProcessor.java index fe5d0a27b51..93fafed1871 100644 --- a/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestPasswordPolicyProcessor.java +++ b/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestPasswordPolicyProcessor.java @@ -179,8 +179,7 @@ private void doTestModifyPasswordExpectFailure(String password) throws Exception fail("Expected PolicyViolationException but didn't get one."); } catch (PolicyViolationException ex) { - // this is expected - displayException("expected exception", ex); + displayExpectedException(ex); result.computeStatus(); TestUtil.assertFailure(result); } diff --git a/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestPolicyRules2.java b/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestPolicyRules2.java index 7f7a05da74c..0fa915f0450 100644 --- a/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestPolicyRules2.java +++ b/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestPolicyRules2.java @@ -626,7 +626,6 @@ public void test200AddUnresolvable() throws Exception { assertFocusModificationSanity(context); - // WHEN when(); try { clockwork.run(context, task, result); @@ -634,8 +633,7 @@ public void test200AddUnresolvable() throws Exception { fail("unexpected success"); } catch (ObjectNotFoundException e) { then(); - System.out.println("Expected exception: " + e); - e.printStackTrace(System.out); + displayExpectedException(e); if (!e.getMessage().contains("No policy constraint named 'unresolvable' could be found")) { fail("Exception message was not as expected: " + e.getMessage()); } @@ -662,8 +660,7 @@ public void test210AddCyclic() throws Exception { fail("unexpected success"); } catch (SchemaException e) { then(); - System.out.println("Expected exception: " + e); - e.printStackTrace(System.out); + displayExpectedException(e); if (!e.getMessage().contains("Trying to resolve cyclic reference to constraint")) { fail("Exception message was not as expected: " + e.getMessage()); } @@ -747,8 +744,7 @@ public void test230AddAmbiguous() throws Exception { fail("unexpected success"); } catch (SchemaException e) { then(); - System.out.println("Expected exception: " + e); - e.printStackTrace(System.out); + displayExpectedException(e); if (!e.getMessage().contains("Conflicting definitions of 'constraint-B'")) { fail("Exception message was not as expected: " + e.getMessage()); } @@ -779,8 +775,7 @@ public void test300ModifyInducement() throws Exception { fail("unexpected success"); } catch (PolicyViolationException e) { then(); - System.out.println("Expected exception: " + e); - e.printStackTrace(System.out); + displayExpectedException(e); if (!getTranslatedMessage(e).contains("Role \"Immutable inducements\" is to be modified")) { fail("Exception message was not as expected: " + getTranslatedMessage(e)); } @@ -859,8 +854,7 @@ public void test330AddInducement() throws Exception { fail("unexpected success"); } catch (PolicyViolationException e) { then(); - System.out.println("Expected exception: " + e); - e.printStackTrace(System.out); + displayExpectedException(e); if (!getTranslatedMessage(e).contains("Role \"No inducements add or delete\" is to be modified")) { fail("Exception message was not as expected: " + getTranslatedMessage(e)); } @@ -891,8 +885,7 @@ public void test340AddInducementViaExpression() throws Exception { fail("unexpected success"); } catch (PolicyViolationException e) { then(); - System.out.println("Expected exception: " + e); - e.printStackTrace(System.out); + displayExpectedException(e); if (!getTranslatedMessage(e).contains("Role \"No inducements add or delete (expression)\" is to be modified")) { fail("Exception message was not as expected: " + getTranslatedMessage(e)); } diff --git a/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestProjector.java b/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestProjector.java index d07349c7c5c..daa86fe6402 100644 --- a/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestProjector.java +++ b/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestProjector.java @@ -633,9 +633,7 @@ public void test269DeleteBarbossaDummyAccount() throws Exception { "there is no focus context"; assert false : "The operation was successful but it should throw expcetion"; } catch (PolicyViolationException e) { - // THEN: success - // this is expected - displayException("Expected exception", e); + displayExpectedException(e); } } diff --git a/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/security/TestAbstractAuthenticationEvaluator.java b/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/security/TestAbstractAuthenticationEvaluator.java index 6ce37afe69a..97a57603dce 100644 --- a/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/security/TestAbstractAuthenticationEvaluator.java +++ b/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/security/TestAbstractAuthenticationEvaluator.java @@ -208,11 +208,8 @@ public void test101PasswordLoginBadPasswordJack() throws Exception { AssertJUnit.fail("Unexpected success"); } catch (BadCredentialsException e) { - // This is expected - - // THEN then(); - displayException("expected exception", e); + displayExpectedException(e); assertBadPasswordException(e); } XMLGregorianCalendar endTs = clock.currentTimeXMLGregorianCalendar(); @@ -239,11 +236,8 @@ public void test102PasswordLoginNullPasswordJack() throws Exception { AssertJUnit.fail("Unexpected success"); } catch (BadCredentialsException e) { - // This is expected - - // THEN then(); - displayException("expected exception", e); + displayExpectedException(e); assertPasswordEncodingException(e); } @@ -269,11 +263,8 @@ public void test103PasswordLoginEmptyPasswordJack() throws Exception { AssertJUnit.fail("Unexpected success"); } catch (BadCredentialsException e) { - // This is expected - - // THEN then(); - displayException("expected exception", e); + displayExpectedException(e); assertPasswordEncodingException(e); } @@ -298,11 +289,8 @@ public void test105PasswordLoginNullUsernameNullPassword() { AssertJUnit.fail("Unexpected success"); } catch (BadCredentialsException e) { - // This is expected - - // THEN then(); - displayException("expected exception", e); + displayExpectedException(e); assertPasswordEncodingException(e); } @@ -323,14 +311,10 @@ public void test106PasswordLoginEmptyUsernameBadPassword() { AssertJUnit.fail("Unexpected success"); } catch (UsernameNotFoundException e) { - // This is expected - - // THEN then(); - displayException("expected exception", e); + displayExpectedException(e); assertNoUserException(e); } - } @Test @@ -348,14 +332,10 @@ public void test107PasswordLoginBadUsernameBadPassword() { AssertJUnit.fail("Unexpected success"); } catch (UsernameNotFoundException e) { - // This is expected - - // THEN then(); - displayException("expected exception", e); + displayExpectedException(e); assertNoUserException(e); } - } /** @@ -384,7 +364,7 @@ public void test125PasswordLoginBadPasswordJackAfterLockoutFailedAttemptsDuratio // THEN then(); - displayException("expected exception", e); + displayExpectedException(e); assertBadPasswordException(e); } XMLGregorianCalendar endTs = clock.currentTimeXMLGregorianCalendar(); @@ -411,9 +391,7 @@ public void test130PasswordLoginLockout() throws Exception { AssertJUnit.fail("Unexpected success"); } catch (BadCredentialsException e) { - // This is expected - - displayException("expected exception", e); + displayExpectedException(e); assertBadPasswordException(e); } @@ -428,9 +406,7 @@ public void test130PasswordLoginLockout() throws Exception { AssertJUnit.fail("Unexpected success"); } catch (BadCredentialsException e) { - // This is expected - - displayException("expected exception", e); + displayExpectedException(e); assertBadPasswordException(e); } @@ -460,11 +436,8 @@ public void test132PasswordLoginLockedoutGoodPassword() throws Exception { AssertJUnit.fail("Unexpected success"); } catch (LockedException e) { - // This is expected - - // THEN then(); - displayException("expected exception", e); + displayExpectedException(e); assertLockedException(e); } @@ -487,14 +460,11 @@ public void test133PasswordLoginLockedoutBadPassword() throws Exception { AssertJUnit.fail("Unexpected success"); } catch (LockedException e) { - // This is expected - - // THEN then(); - displayException("expected exception", e); + displayExpectedException(e); - // this is important. The exception should give no indication whether the password is - // good or bad + // This is important. + // The exception should give no indication whether the password is good or bad. assertLockedException(e); } @@ -542,11 +512,8 @@ public void test136PasswordLoginLockoutAgain() throws Exception { AssertJUnit.fail("Unexpected success"); } catch (BadCredentialsException e) { - // This is expected - - // THEN then(); - displayException("expected exception", e); + displayExpectedException(e); assertBadPasswordException(e); } @@ -561,11 +528,8 @@ public void test136PasswordLoginLockoutAgain() throws Exception { AssertJUnit.fail("Unexpected success"); } catch (BadCredentialsException e) { - // This is expected - - // THEN then(); - displayException("expected exception", e); + displayExpectedException(e); assertBadPasswordException(e); } @@ -580,11 +544,8 @@ public void test136PasswordLoginLockoutAgain() throws Exception { AssertJUnit.fail("Unexpected success"); } catch (BadCredentialsException e) { - // This is expected - - // THEN then(); - displayException("expected exception", e); + displayExpectedException(e); assertBadPasswordException(e); } @@ -611,11 +572,8 @@ public void test137PasswordLoginLockedoutGoodPasswordAgain() throws Exception { AssertJUnit.fail("Unexpected success"); } catch (LockedException e) { - // This is expected - - // THEN then(); - displayException("expected exception", e); + displayExpectedException(e); assertLockedException(e); } @@ -681,12 +639,8 @@ public void test139TryToLockByModelService() throws Exception { AssertJUnit.fail("Unexpected success"); } catch (SchemaException e) { - // This is expected - - // THEN then(); - displayException("expected exception", e); - + displayExpectedException(e); } PrismObject userAfter = getUser(USER_JACK_OID); @@ -879,11 +833,8 @@ public void test202UserGuybrushPasswordLoginBadPassword() throws Exception { AssertJUnit.fail("Unexpected success"); } catch (BadCredentialsException e) { - // This is expected - - // THEN then(); - displayException("expected exception", e); + displayExpectedException(e); assertBadPasswordException(e); } XMLGregorianCalendar endTs = clock.currentTimeXMLGregorianCalendar(); @@ -934,11 +885,8 @@ public void test210UserGuybrushPasswordLoginGoodPasswordExpired() throws Excepti AssertJUnit.fail("Unexpected success"); } catch (CredentialsExpiredException e) { - // This is expected - - // THEN then(); - displayException("expected exception", e); + displayExpectedException(e); assertExpiredException(e); } @@ -1065,14 +1013,11 @@ private void loginJackGoodPasswordExpectDenied() throws ObjectNotFoundException, AssertJUnit.fail("Unexpected success"); } catch (DisabledException e) { - // This is expected - - // THEN then(); - displayException("expected exception", e); + displayExpectedException(e); - // this is important. The exception should give no indication whether the password is - // good or bad + // This is important. + // The exception should give no indication whether the password is good or bad. assertDisabledException(e); } diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestModelServiceContract.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestModelServiceContract.java index d3e2a7edde7..947b02b96f5 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestModelServiceContract.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestModelServiceContract.java @@ -161,9 +161,8 @@ public void test099ModifyUserAddAccountFailing() throws Exception { assertNotReached(); } catch (UnsupportedOperationException e) { - // THEN then(); - displayException("Expected exception", e); + displayExpectedException(e); } assertFailure(result); @@ -2055,8 +2054,7 @@ public void test180ModifyUserAddAccountFullEnforcement() throws Exception { AssertJUnit.fail("Unexpected executeChanges success"); } catch (PolicyViolationException e) { - // This is expected - displayException("Expected exception", e); + displayExpectedException(e); } // THEN diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestPreviewChanges.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestPreviewChanges.java index 3a0d8a11dce..a04e4c86439 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestPreviewChanges.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestPreviewChanges.java @@ -329,8 +329,7 @@ private void doPreviewFail( modelInteractionService.previewChanges(deltas, new ModelExecuteOptions(), task, result); AssertJUnit.fail("Expected exception, but it haven't come"); } catch (SchemaException e) { - // This is expected - displayException("Expected exception", e); + displayExpectedException(e); } result.computeStatus(); diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestStrangeCases.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestStrangeCases.java index 7c935ba9d2a..59aee222e6b 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestStrangeCases.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestStrangeCases.java @@ -204,8 +204,7 @@ public void test050AddRoleRecursionAssignment() throws Exception { assertNotReached(); } catch (PolicyViolationException e) { - // This is expected - displayException("Expected exception", e); + displayExpectedException(e); } // THEN @@ -279,8 +278,7 @@ public void test100ModifyUserGuybrushAddAccountDummyRedNoAttributesConflict() th AssertJUnit.fail("Unexpected executeChanges success"); } catch (ObjectAlreadyExistsException e) { - // This is expected - displayException("Expected exception", e); + displayExpectedException(e); } //TODO: this is not yet expected.. there is a checking code in the ProjectionValueProcessor.. @@ -910,8 +908,7 @@ public void test332AssignDeGhoulashRecursion() throws Exception { assertNotReached(); } catch (PolicyViolationException e) { - // This is expected - displayException("Expected exception", e); + displayExpectedException(e); } // THEN diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/archetypes/TestArchetypes.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/archetypes/TestArchetypes.java index f0de021b365..0e0bd37d5ec 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/archetypes/TestArchetypes.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/archetypes/TestArchetypes.java @@ -765,8 +765,7 @@ public void test162AddFraudster() throws Exception { assertNotReached(); } catch (PolicyViolationException e) { - // Expected - displayException("Expected exception", e); + displayExpectedException(e); } // THEN diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/gensync/TestRoleEntitlement.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/gensync/TestRoleEntitlement.java index 7a98c07e36c..0bd26cc53b7 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/gensync/TestRoleEntitlement.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/gensync/TestRoleEntitlement.java @@ -243,9 +243,7 @@ public void test108ModifyRoleAddEntitlementAgain() throws Exception { // THEN assert false : "Expected executeChanges operation to fail but it has obviously succeeded"; } catch (SchemaException e) { - // This is expected - e.printStackTrace(); - // THEN + displayExpectedException(e); String message = e.getMessage(); assertMessageContains(message, "already contains entitlement"); assertMessageContains(message, "group"); diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/multi/TestMultiResource.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/multi/TestMultiResource.java index 4e567158282..e59db83100c 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/multi/TestMultiResource.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/multi/TestMultiResource.java @@ -263,8 +263,7 @@ public void test121JackTryDeleteAccount() throws Exception { AssertJUnit.fail("Unexpected success"); } catch (PolicyViolationException e) { - // This is expected - displayException("Expected exception", e); + displayExpectedException(e); } } @@ -1318,8 +1317,7 @@ public void test350AddAccountLavender() throws Exception { AssertJUnit.fail("Unexpected success"); } catch (PolicyViolationException e) { - // this is expected - displayException("Expected exception", e); + displayExpectedException(e); } // THEN @@ -1441,8 +1439,7 @@ public void test370DeleteAccountDummy() throws Exception { AssertJUnit.fail("Unexpected success"); } catch (PolicyViolationException e) { - // this is expected - displayException("Expected exception", e); + displayExpectedException(e); } // THEN @@ -1476,8 +1473,7 @@ public void test372UnlinkAccountDummy() throws Exception { AssertJUnit.fail("Unexpected success"); } catch (PolicyViolationException e) { - // this is expected - displayException("Expected exception", e); + displayExpectedException(e); } // THEN diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/negative/TestAssignmentErrors.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/negative/TestAssignmentErrors.java index 562991a9041..8eab91cb89b 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/negative/TestAssignmentErrors.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/negative/TestAssignmentErrors.java @@ -319,9 +319,8 @@ public void test210UserSharptoothAssignAccountBrokenGeneric() throws Exception { assertNotReached(); } catch (GenericConnectorException e) { - // THEN then(); - displayException("Expected exception", e); + displayExpectedException(e); } assertFailure(result); diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/negative/TestBrokenResources.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/negative/TestBrokenResources.java index 12d69564af1..75bd636c477 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/negative/TestBrokenResources.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/negative/TestBrokenResources.java @@ -200,8 +200,7 @@ public void test100GetAccountMurray() throws Exception { display("Account (unexpected)", account); AssertJUnit.fail("Expected SystemException but the operation was successful"); } catch (SystemException e) { - // This is expected - displayException("Expected exception", e); + displayExpectedException(e); result.computeStatus(); display("getObject result", result); TestUtil.assertFailure("getObject result", result); @@ -785,9 +784,8 @@ public void test401AssignTwoResourcesBroken() throws Exception { assertNotReached(); } catch (GenericConnectorException e) { - // THEN then(); - displayException("Expected exception", e); + displayExpectedException(e); } result.computeStatus(); @@ -926,9 +924,8 @@ public void test510AssignResourceBlackError() throws Exception { assertNotReached(); } catch (GenericConnectorException e) { - // THEN then(); - displayException("Expected exception", e); + displayExpectedException(e); } assertFailure(result); @@ -993,9 +990,8 @@ public void test514ModifyUserEmployeeNumberRuntime() throws Exception { assertNotReached(); } catch (RuntimeException e) { - // THEN then(); - displayException("Expected exception", e); + displayExpectedException(e); assertEquals("Wrong exception message", "Booom! PowerFail script failed (runtime)", e.getMessage()); } @@ -1031,9 +1027,8 @@ public void test518UnassignResourceBlack() throws Exception { assertNotReached(); } catch (RuntimeException e) { - // THEN then(); - displayException("Expected exception", e); + displayExpectedException(e); assertEquals("Wrong exception message", "Booom! PowerFail script failed (runtime)", e.getMessage()); } @@ -1215,7 +1210,7 @@ public void test600GuybrushAssignAccountDummyViolet() throws Exception { assertNotReached(); } catch (ExpressionEvaluationException e) { - displayException("Expected exception", e); + displayExpectedException(e); } // THEN diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/orgstruct/TestOrgStruct.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/orgstruct/TestOrgStruct.java index ad10c8c8f8e..89fbc097c62 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/orgstruct/TestOrgStruct.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/orgstruct/TestOrgStruct.java @@ -798,9 +798,8 @@ public void test310JackConflictParentOrgRefAndAssignmentsAddOrg() throws Excepti assertNotReached(); } catch (PolicyViolationException e) { - // THEN then(); - displayException("Expected exception", e); + displayExpectedException(e); assertFailure(result); } diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/password/AbstractPasswordTest.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/password/AbstractPasswordTest.java index 18c3d0f8327..e7ecc2f99c0 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/password/AbstractPasswordTest.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/password/AbstractPasswordTest.java @@ -1188,8 +1188,7 @@ public void test222ModifyUserJackPasswordBadContainer() throws Exception { AssertJUnit.fail("Unexpected success"); } catch (PolicyViolationException e) { - // This is expected - displayException("Expected exception", e); + displayExpectedException(e); } // THEN @@ -1400,8 +1399,7 @@ public void test300TwoParentOrgRefs() throws Exception { AssertJUnit.fail("Unexpected success"); } catch (PolicyViolationException e) { - // This is expected - displayException("Expected exception", e); + displayExpectedException(e); } // THEN diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/persona/TestPersonaPassword.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/persona/TestPersonaPassword.java index 808477a42bd..18989a73226 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/persona/TestPersonaPassword.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/persona/TestPersonaPassword.java @@ -86,8 +86,7 @@ public void test145ModifyPersonaPasswordBack() throws Exception { assertNotReached(); } catch (PolicyViolationException e) { - // expected - displayException("expected exception", e); + displayExpectedException(e); } // THEN diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/rbac/TestRbac.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/rbac/TestRbac.java index 0874a0b83b1..78d1ad8a20f 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/rbac/TestRbac.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/rbac/TestRbac.java @@ -1627,8 +1627,7 @@ public void test602JackAssignRolePirate() throws Exception { AssertJUnit.fail("Unexpected success"); } catch (PolicyViolationException e) { - // this is expected - displayException("Expected exception", e); + displayExpectedException(e); assertMessage(e, "Violation of SoD policy: Role \"Judge\" excludes role \"Pirate\", they cannot be assigned at the same time"); } @@ -1752,8 +1751,7 @@ public void test612JackAssignRoleGovernor() throws Exception { AssertJUnit.fail("Unexpected success"); } catch (PolicyViolationException e) { - // this is expected - displayException("Expected exception", e); + displayExpectedException(e); assertMessage(e, "Role \"Governor\" requires at most 1 assignees with the relation of \"default\". The operation would result in 2 assignees."); } @@ -1786,8 +1784,7 @@ public void test613JackAssignRoleGovernorAsApprover() throws Exception { AssertJUnit.fail("Unexpected success"); } catch (PolicyViolationException e) { - // this is expected - displayException("Expected exception", e); + displayExpectedException(e); assertMessage(e, "Role \"Governor\" requires at most 0 assignees with the relation of \"approver\". The operation would result in 1 assignees."); } @@ -1911,8 +1908,7 @@ public void test625BignoseAssignRoleCanibal() throws Exception { AssertJUnit.fail("Unexpected success"); } catch (PolicyViolationException e) { - // this is expected - displayException("Expected exception", e); + displayExpectedException(e); assertMessage(e, "Role \"Cannibal\" requires at most 3 assignees with the relation of \"default\". The operation would result in 4 assignees."); } @@ -1966,8 +1962,7 @@ public void test628RedskullUnassignRoleCanibal() throws Exception { AssertJUnit.fail("Unexpected success"); } catch (PolicyViolationException e) { - // this is expected - displayException("Expected exception", e); + displayExpectedException(e); assertMessage(e, "Role \"Cannibal\" requires at least 2 assignees with the relation of \"default\". The operation would result in 1 assignees."); } @@ -2034,8 +2029,7 @@ public void test632RappUnassignRoleCannibalAsOwner() throws Exception { AssertJUnit.fail("Unexpected success"); } catch (PolicyViolationException e) { - // this is expected - displayException("Expected exception", e); + displayExpectedException(e); assertMessage(e, "Role \"Cannibal\" requires at least 1 assignees with the relation of \"owner\". The operation would result in 0 assignees."); } diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/security/TestSecurityBasic.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/security/TestSecurityBasic.java index 859dd85f987..d631c9818df 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/security/TestSecurityBasic.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/security/TestSecurityBasic.java @@ -1532,7 +1532,7 @@ private void assertJack24xManager(boolean fullControl) throws Exception { addObject(ORG_CHEATERS_FILE, task, result); // MID-3874 assertNotReached(); } catch (PolicyViolationException e) { - displayException("Expected exception", e); + displayExpectedException(e); assertFailure(result); } @@ -1577,14 +1577,11 @@ private void assertJack24xManager(boolean fullControl) throws Exception { // assertSearch(ShadowType.class, query, 2); try { - modelService.searchObjects(ShadowType.class, query, null, task, result); AssertJUnit.fail("unexpected success"); - } catch (SchemaException e) { - // This is expected. The authorizations will mix on-resource and off-resource search. - displayException("Expected exception", e); + displayExpectedException(e); } result.computeStatus(); TestUtil.assertFailure(result); @@ -1661,15 +1658,13 @@ private void assertJack24xManagerDefense(boolean fullControl) throws Exception { // assertSearch(ShadowType.class, query, 2); try { - modelService.searchObjects(ShadowType.class, query, null, task, result); AssertJUnit.fail("unexpected success"); - } catch (SchemaException e) { - // This is expected. The authorizations will mix on-resource and off-resource search. - displayException("Expected exception", e); + displayExpectedException(e); } + assertFailure(result); assertSearch(UserType.class, null, 5); diff --git a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummy.java b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummy.java index 095b840dcd7..5abae446ac5 100644 --- a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummy.java +++ b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummy.java @@ -229,9 +229,8 @@ public void test107AGetModifiedAccountFromCacheMax() throws Exception { assertNotReached(); } catch (ConfigurationException e) { - // Caching is disabled, this is expected. then(); - displayException("Expected exception", e); + displayExpectedException(e); assertFailure(result); } @@ -1996,8 +1995,7 @@ public boolean handle(PrismObject object, OperationResult parentResu AssertJUnit.fail("unexpected success"); } catch (SchemaException e) { - // This is expected - displayException("Expected exception", e); + displayExpectedException(e); } // THEN @@ -3739,8 +3737,7 @@ public void test502ModifyProtectedAccountShadowAttributes() throws Exception { provisioningService.modifyObject(ShadowType.class, ACCOUNT_DAEMON_OID, modifications, null, null, task, result); AssertJUnit.fail("Expected security exception while modifying 'daemon' account"); } catch (SecurityViolationException e) { - // This is expected - displayException("Expected exception", e); + displayExpectedException(e); } result.computeStatus(); @@ -3800,9 +3797,8 @@ public void test509DeleteProtectedAccountShadow() throws Exception { AssertJUnit.fail("Expected security exception while deleting 'daemon' account"); } catch (SecurityViolationException e) { - // This is expected then(); - displayException("Expected exception", e); + displayExpectedException(e); } assertFailure(result); @@ -3949,9 +3945,8 @@ public void test600AddAccountAlreadyExist() throws Exception { assertNotReached(); } catch (ObjectAlreadyExistsException e) { - // This is expected then(); - displayException("Expected exception", e); + displayExpectedException(e); } // THEN diff --git a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummyConsistency.java b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummyConsistency.java index 6a91ea7d6fd..f0bb8726a77 100644 --- a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummyConsistency.java +++ b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummyConsistency.java @@ -1417,7 +1417,7 @@ public void test800AddAccountMorganAlreadyExists() throws Exception { assertNotReached(); } catch (ObjectAlreadyExistsException e) { then(); - displayException("expected exception", e); + displayExpectedException(e); } // THEN @@ -1495,7 +1495,7 @@ public void test802AddAccountMorganAlreadyExistsAgain() throws Exception { assertNotReached(); } catch (ObjectAlreadyExistsException e) { then(); - displayException("expected exception", e); + displayExpectedException(e); } // THEN @@ -1614,7 +1614,7 @@ public void test806RenameAccountElizabethAlreadyExists() throws Exception { assertNotReached(); } catch (ObjectAlreadyExistsException e) { then(); - displayException("expected exception", e); + displayExpectedException(e); } // THEN @@ -1692,7 +1692,7 @@ public void test808RenameAccountElizabethAlreadyExistsAgain() throws Exception { assertNotReached(); } catch (ObjectAlreadyExistsException e) { then(); - displayException("expected exception", e); + displayExpectedException(e); } // THEN @@ -1852,7 +1852,7 @@ public void test812ModifyAccountWillNotFound() throws Exception { assertNotReached(); } catch (ObjectNotFoundException e) { then(); - displayException("expected exception", e); + displayExpectedException(e); } // THEN @@ -1991,7 +1991,7 @@ public void test816AddAccountElizabethAfterDeathAlreadyExists() throws Exception provisioningService.addObject(account, null, null, task, result); } catch (ObjectAlreadyExistsException e) { then(); - displayException("expected exception", e); + displayExpectedException(e); } // THEN diff --git a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummyNegative.java b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummyNegative.java index 696a95ec261..56363517a0c 100644 --- a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummyNegative.java +++ b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummyNegative.java @@ -136,8 +136,7 @@ public void test200AddAccountNullAttributes() throws Exception { assertNotReached(); } catch (SchemaException e) { - // This is expected - displayException("Expected exception", e); + displayExpectedException(e); } then(); @@ -165,8 +164,7 @@ public void test201AddAccountEmptyAttributes() throws Exception { AssertJUnit.fail("The addObject operation was successful. But expecting an exception."); } catch (SchemaException e) { - // This is expected - displayException("Expected exception", e); + displayExpectedException(e); } syncServiceMock.assertNotifyFailureOnly(); @@ -195,8 +193,7 @@ public void test210AddAccountNoObjectClass() throws Exception { AssertJUnit.fail("The addObject operation was successful. But expecting an exception."); } catch (SchemaException e) { - // This is expected - displayException("Expected exception", e); + displayExpectedException(e); } syncServiceMock.assertNotifyFailureOnly(); @@ -223,8 +220,7 @@ public void test220AddAccountNoResourceRef() throws Exception { AssertJUnit.fail("The addObject operation was successful. But expecting an exception."); } catch (SchemaException e) { - // This is expected - displayException("Expected exception", e); + displayExpectedException(e); } //FIXME: not sure, if this check is needed..if the resource is not specified, provisioning probably will be not called. @@ -251,10 +247,8 @@ public void test221DeleteAccountResourceNotFound() throws Exception { String oid = repositoryService.addObject(account, null, result); ProvisioningOperationOptions options = ProvisioningOperationOptions.createForce(true); provisioningService.deleteObject(ShadowType.class, oid, options, null, task, result); -// AssertJUnit.fail("The addObject operation was successful. But expecting an exception."); } catch (SchemaException e) { - // This is expected - displayException("Expected exception", e); + displayExpectedException(e); } //FIXME: is this really notify failure? the resource does not exist but shadow is deleted. maybe other case of notify? @@ -287,12 +281,10 @@ public void test230GetAccountDeletedShadow() throws Exception { assertNotReached(); } catch (ObjectNotFoundException e) { - // this is expected - displayException("Expected exception", e); + displayExpectedException(e); result.computeStatus(); display("Result", result); TestUtil.assertFailure(result); - } syncServiceMock.assertNoNotifyChange(); diff --git a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummySecurity.java b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummySecurity.java index 8462325d10b..0a6f86fc537 100644 --- a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummySecurity.java +++ b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummySecurity.java @@ -69,8 +69,7 @@ public void test100AddAccountDrink() throws Exception { AssertJUnit.fail("Unexpected success"); } catch (SecurityViolationException e) { - // This is expected - displayException("Expected exception", e); + displayExpectedException(e); } } @@ -188,10 +187,8 @@ public void test210ModifyAccountQuote() throws Exception { new OperationProvisioningScriptsType(), null, task, result); AssertJUnit.fail("Unexpected success"); - } catch (SecurityViolationException e) { - // This is expected - displayException("Expected exception", e); + displayExpectedException(e); } } diff --git a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/opendj/TestOpenDj.java b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/opendj/TestOpenDj.java index 0f43f688692..5c113ffd5c8 100644 --- a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/opendj/TestOpenDj.java +++ b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/opendj/TestOpenDj.java @@ -740,7 +740,7 @@ public void test111GetObjectNotFoundRepo() throws Exception { provisioningService.getObject(ObjectType.class, NON_EXISTENT_OID, null, task, result).asObjectable(); Assert.fail("Expected exception, but haven't got one"); } catch (ObjectNotFoundException e) { - // This is expected + displayExpectedException(e); // Just to close the top-level result. result.recordFatalError("Error :-)"); @@ -884,7 +884,7 @@ public void test130AddDeleteAccountSparrow() throws Exception { provisioningService.getObject(ShadowType.class, ACCOUNT_SPARROW_OID, null, task, result); Assert.fail("Expected exception ObjectNotFoundException, but haven't got one."); } catch (ObjectNotFoundException ex) { - displayException("Expected exception", ex); + displayExpectedException(ex); } try { @@ -892,7 +892,7 @@ public void test130AddDeleteAccountSparrow() throws Exception { // objType = container.getObject(); Assert.fail("Expected exception, but haven't got one."); } catch (ObjectNotFoundException ex) { - displayException("Expected exception", ex); + displayExpectedException(ex); assertTrue(ex.getMessage().contains(ACCOUNT_SPARROW_OID)); } @@ -2010,8 +2010,7 @@ public void test300AddObjectObjectAlreadyExistResource() throws Exception { AssertJUnit.fail("Expected addObject operation to fail but it was successful"); } catch (ObjectAlreadyExistsException e) { - // This is expected - displayException("Expected exception", e); + displayExpectedException(e); // The exception should originate from the LDAP layers IntegrationTestTools.assertInMessageRecursive(e, "LDAP"); @@ -2036,8 +2035,7 @@ public void test310AddObjectNoSn() throws Exception { AssertJUnit.fail("Expected addObject operation to fail but it was successful"); } catch (SchemaException e) { - // This is expected - displayException("Expected exception", e); + displayExpectedException(e); // This error should be detectable before it reaches a resource. Therefore we check that the // cause was not a LDAP exception @@ -2157,7 +2155,7 @@ public void test329DeleteAccountPosix() throws Exception { provisioningService.getObject(ShadowType.class, ACCOUNT_POSIX_MCMUTTON_OID, null, task, result); Assert.fail("Expected exception ObjectNotFoundException, but haven't got one."); } catch (ObjectNotFoundException ex) { - displayException("Expected exception", ex); + displayExpectedException(ex); } try { @@ -2165,7 +2163,7 @@ public void test329DeleteAccountPosix() throws Exception { // objType = container.getObject(); Assert.fail("Expected exception, but haven't got one."); } catch (ObjectNotFoundException ex) { - displayException("Expected exception", ex); + displayExpectedException(ex); assertTrue(ex.getMessage().contains(ACCOUNT_POSIX_MCMUTTON_OID)); } @@ -2546,7 +2544,7 @@ public void test429DeleteAccountMorgan() throws Exception { null, task, result).asObjectable(); Assert.fail("Expected exception ObjectNotFoundException, but haven't got one."); } catch (ObjectNotFoundException ex) { - System.out.println("Catched ObjectNotFoundException."); + displayExpectedException(ex); assertNull(objType); } diff --git a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/opendj/TestOpenDjNegative.java b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/opendj/TestOpenDjNegative.java index 9d7039376e3..4bc255ff639 100644 --- a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/opendj/TestOpenDjNegative.java +++ b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/opendj/TestOpenDjNegative.java @@ -158,8 +158,7 @@ public void test110GetObjectNoShadow() throws Exception { AssertJUnit.fail("getObject succeeded unexpectedly"); } catch (ObjectNotFoundException e) { - // This is expected - displayException("Expected exception", e); + displayExpectedException(e); } result.computeStatus(); @@ -181,10 +180,8 @@ public void test111GetObjectShadow() throws Exception { null, taskManager.createTaskInstance(), result).asObjectable(); AssertJUnit.fail("getObject succeeded unexpectedly"); -// } catch (CommunicationException e) { } catch (ConfigurationException e) { - // This is expected - displayException("Expected exception", e); + displayExpectedException(e); } result.computeStatus(); @@ -203,8 +200,7 @@ public void test120ListResourceObjects() throws Exception { AssertJUnit.fail("listResourceObjects succeeded unexpectedly"); } catch (ConfigurationException e) { - // This is expected - displayException("Expected exception", e); + displayExpectedException(e); } result.computeStatus(); @@ -228,8 +224,7 @@ public void test121SearchAccounts() throws Exception { AssertJUnit.fail("searchObjectsIterative succeeded unexpectedly"); } catch (ConfigurationException e) { - // This is expected - displayException("Expected exception", e); + displayExpectedException(e); } result.computeStatus(); @@ -263,8 +258,7 @@ public boolean handle(PrismObject prismObject, OperationResult paren AssertJUnit.fail("searchObjectsIterative succeeded unexpectedly"); } catch (ConfigurationException e) { - // This is expected - displayException("Expected exception", e); + displayExpectedException(e); } result.computeStatus(); @@ -286,8 +280,7 @@ public void test130AddAccountWill() throws Exception { AssertJUnit.fail("addObject succeeded unexpectedly"); } catch (ConfigurationException e) { - // This is expected - displayException("Expected exception", e); + displayExpectedException(e); } result.computeStatus(); @@ -305,8 +298,7 @@ public void test140AddDeleteAccountSparrow() throws Exception { AssertJUnit.fail("addObject succeeded unexpectedly"); } catch (ConfigurationException e) { - // This is expected - displayException("Expected exception", e); + displayExpectedException(e); } result.computeStatus(); @@ -330,8 +322,7 @@ public void test150ModifyObject() throws Exception { AssertJUnit.fail("addObject succeeded unexpectedly"); } catch (ConfigurationException e) { - // This is expected - displayException("Expected exception", e); + displayExpectedException(e); } result.computeStatus(); @@ -353,8 +344,7 @@ public void test190Synchronize() throws Exception { AssertJUnit.fail("addObject succeeded unexpectedly"); } catch (CommunicationException e) { - // This is expected - displayException("Expected exception", e); + displayExpectedException(e); } result.computeStatus(); @@ -397,8 +387,7 @@ public void test510GetObjectNoShadow() throws Exception { AssertJUnit.fail("getObject succeeded unexpectedly"); } catch (ObjectNotFoundException e) { - // This is expected - displayException("Expected exception", e); + displayExpectedException(e); } result.computeStatus(); @@ -448,8 +437,7 @@ public void test520ListResourceObjects() throws Exception { AssertJUnit.fail("listResourceObjects succeeded unexpectedly"); } catch (CommunicationException e) { - // This is expected - displayException("Expected exception", e); + displayExpectedException(e); } assertFailure(result); @@ -473,8 +461,7 @@ public void test521SearchAccounts() throws SchemaException, ObjectNotFoundExcept AssertJUnit.fail("searchObjectsIterative succeeded unexpectedly"); } catch (CommunicationException e) { - // This is expected - displayException("Expected exception", e); + displayExpectedException(e); } result.computeStatus(); @@ -506,8 +493,7 @@ public boolean handle(PrismObject prismObject, OperationResult paren AssertJUnit.fail("searchObjectsIterative succeeded unexpectedly"); } catch (CommunicationException e) { - // This is expected - displayException("Expected exception", e); + displayExpectedException(e); } assertFailure(result); @@ -549,7 +535,7 @@ public void test530AddAccountWill() throws Exception { assertNotReached(); } catch (GenericConnectorException e) { - displayException("expected exception", e); + displayExpectedException(e); } Collection> options = SelectorOptions.createCollection(GetOperationOptions.createPointInTimeType(PointInTimeType.FUTURE)); @@ -653,8 +639,7 @@ public void test590Synchronize() throws Exception { AssertJUnit.fail("addObject succeeded unexpectedly"); } catch (CommunicationException e) { - // This is expected - displayException("Expected exception", e); + displayExpectedException(e); } assertFailure(result); diff --git a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestServiceAccounts.java b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestServiceAccounts.java index 20a451fa14c..aaacb439532 100644 --- a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestServiceAccounts.java +++ b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestServiceAccounts.java @@ -150,9 +150,8 @@ serviceAccountShadowOid, getDummyResourceController().getAttributeFullnamePath() assertNotReached(); } catch (UnsupportedOperationException e) { - // THEN then(); - displayException("expected exception", e); + displayExpectedException(e); } assertFailure(result); @@ -195,9 +194,8 @@ public void test104DeleteServiceAccount() throws Exception { assertNotReached(); } catch (UnsupportedOperationException e) { - // THEN then(); - displayException("expected exception", e); + displayExpectedException(e); } assertFailure(result); @@ -371,9 +369,8 @@ public void test140CreateServiceAccount() throws Exception { assertNotReached(); } catch (UnsupportedOperationException e) { - // THEN then(); - displayException("expected exception", e); + displayExpectedException(e); } assertFailure(result); diff --git a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestUnix.java b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestUnix.java index c4e58ea5f1d..eddfac505d9 100644 --- a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestUnix.java +++ b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestUnix.java @@ -1447,8 +1447,7 @@ public void test300AddUserCapsizeUnixFail() throws Exception { AssertJUnit.fail("Unexpected success"); } catch (ExpressionEvaluationException e) { - displayException("Expected exception", e); - // this is expected + displayExpectedException(e); } // THEN From c8e01fb8a3e79ec5e006013bd60a1b0a4c56f58d Mon Sep 17 00:00:00 2001 From: Richard Richter Date: Tue, 17 Mar 2020 00:24:01 +0100 Subject: [PATCH 21/21] MiscUtils: code cleanup --- .../com/evolveum/midpoint/util/MiscUtil.java | 156 +++++++----------- 1 file changed, 56 insertions(+), 100 deletions(-) diff --git a/infra/util/src/main/java/com/evolveum/midpoint/util/MiscUtil.java b/infra/util/src/main/java/com/evolveum/midpoint/util/MiscUtil.java index 3f4e8bb9494..0f32e5eea89 100644 --- a/infra/util/src/main/java/com/evolveum/midpoint/util/MiscUtil.java +++ b/infra/util/src/main/java/com/evolveum/midpoint/util/MiscUtil.java @@ -6,21 +6,9 @@ */ package com.evolveum.midpoint.util; -import com.evolveum.midpoint.util.exception.CommonException; -import com.evolveum.midpoint.util.exception.SystemException; -import com.evolveum.midpoint.util.exception.TunnelException; -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang.StringUtils; -import org.jetbrains.annotations.NotNull; - -import com.evolveum.midpoint.util.logging.Trace; -import com.evolveum.midpoint.util.logging.TraceManager; -import org.jetbrains.annotations.Nullable; +import static java.util.Collections.emptySet; +import static java.util.Collections.singleton; -import javax.xml.datatype.DatatypeConfigurationException; -import javax.xml.datatype.DatatypeConstants; -import javax.xml.datatype.DatatypeFactory; -import javax.xml.datatype.XMLGregorianCalendar; import java.io.*; import java.lang.management.ManagementFactory; import java.lang.management.ThreadInfo; @@ -41,21 +29,28 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; +import javax.xml.datatype.DatatypeConfigurationException; +import javax.xml.datatype.DatatypeConstants; +import javax.xml.datatype.DatatypeFactory; +import javax.xml.datatype.XMLGregorianCalendar; -import static java.util.Collections.emptySet; -import static java.util.Collections.singleton; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.StringUtils; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import com.evolveum.midpoint.util.exception.CommonException; +import com.evolveum.midpoint.util.exception.SystemException; +import com.evolveum.midpoint.util.exception.TunnelException; /** * @author semancik - * */ public class MiscUtil { private static final int BUFFER_SIZE = 2048; - private static final Trace LOGGER = TraceManager.getTrace(MiscUtil.class); - - private static DatatypeFactory df = null; + private static DatatypeFactory df; static { try { @@ -68,7 +63,7 @@ public class MiscUtil { @NotNull public static Collection union(Collection... sets) { Set resultSet = new HashSet<>(); - for (Collection set: sets) { + for (Collection set : sets) { if (set != null) { resultSet.addAll(set); } @@ -78,7 +73,7 @@ public static Collection union(Collection... sets) { public static Collection unionExtends(Collection... sets) { Set resultSet = new HashSet<>(); - for (Collection set: sets) { + for (Collection set : sets) { if (set != null) { resultSet.addAll(set); } @@ -86,24 +81,6 @@ public static Collection unionExtends(Collection.. return resultSet; } - public static boolean listEquals(List a, List b) { - if (a == null && b == null) { - return true; - } - if (a == null || b == null) { - return false; - } - if (a.size() != b.size()) { - return false; - } - for (int i = 0; i < a.size(); i++) { - if (!a.get(i).equals(b.get(i))) { - return false; - } - } - return true; - } - public static boolean unorderedCollectionEquals(Collection a, Collection b) { return unorderedCollectionEquals(a, b, (xa, xb) -> xa.equals(xb)); } @@ -122,9 +99,9 @@ public static boolean unorderedCollectionCompare(Collection a, Collection /** * Only zero vs non-zero value of comparator is important. */ - public static boolean unorderedCollectionEquals(Collection a, Collection b, HeteroComparator comparator) { + public static boolean unorderedCollectionEquals(Collection a, Collection b, HeteroComparator comparator) { if (a == null && b == null) { - return true; + return true; } if (a == null || b == null) { return false; @@ -134,10 +111,10 @@ public static boolean unorderedCollectionEquals(Collection a, Collectio } Collection outstanding = new ArrayList<>(b.size()); outstanding.addAll(b); - for (A ao: a) { + for (A ao : a) { boolean found = false; Iterator iterator = outstanding.iterator(); - while(iterator.hasNext()) { + while (iterator.hasNext()) { B oo = iterator.next(); if (comparator.isEquivalent(ao, oo)) { iterator.remove(); @@ -156,12 +133,7 @@ public static boolean unorderedCollectionEquals(Collection a, Collectio } public static boolean unorderedArrayEquals(T[] a, T[] b) { - Comparator comparator = new Comparator() { - @Override - public int compare(T o1, T o2) { - return o1.equals(o2) ? 0 : 1; - } - }; + Comparator comparator = (o1, o2) -> o1.equals(o2) ? 0 : 1; return unorderedArrayEquals(a, b, comparator); } @@ -179,10 +151,10 @@ public static boolean unorderedArrayEquals(T[] a, T[] b, Comparator compa return false; } List outstanding = Arrays.asList(b); - for (T ao: a) { + for (T ao : a) { boolean found = false; Iterator iterator = outstanding.iterator(); - while(iterator.hasNext()) { + while (iterator.hasNext()) { T oo = iterator.next(); if (comparator.compare(ao, oo) == 0) { iterator.remove(); @@ -202,7 +174,7 @@ public static boolean unorderedArrayEquals(T[] a, T[] b, Comparator compa public static int unorderedCollectionHashcode(Collection collection, Predicate filter) { // Stupid implmentation, just add all the hashcodes int hashcode = 0; - for (T item: collection) { + for (T item : collection) { if (filter != null && !filter.test(item)) { continue; } @@ -216,8 +188,8 @@ public static String readFile(File file) throws IOException { StringBuilder fileData = new StringBuilder(BUFFER_SIZE); BufferedReader reader = new BufferedReader(new FileReader(file)); char[] buf = new char[BUFFER_SIZE]; - int numRead=0; - while((numRead=reader.read(buf)) != -1){ + int numRead; + while ((numRead = reader.read(buf)) != -1) { String readData = String.valueOf(buf, 0, numRead); fileData.append(readData); buf = new char[BUFFER_SIZE]; @@ -231,31 +203,18 @@ public static void copyFile(File sourceFile, File destFile) throws IOException { destFile.createNewFile(); } - FileChannel source = null; - FileChannel destination = null; - try { - source = new FileInputStream(sourceFile).getChannel(); - destination = new FileOutputStream(destFile).getChannel(); + try (FileChannel source = new FileInputStream(sourceFile).getChannel(); + FileChannel destination = new FileOutputStream(destFile).getChannel()) { destination.transferFrom(source, 0, source.size()); - } finally { - if (source != null) { - source.close(); - } - if (destination != null) { - destination.close(); - } } } /** * Copy a directory and its contents. * - * @param src - * The name of the directory to copy. - * @param dst - * The name of the destination directory. - * @throws IOException - * If the directory could not be copied. + * @param src The name of the directory to copy. + * @param dst The name of the destination directory. + * @throws IOException If the directory could not be copied. */ public static void copyDirectory(File src, File dst) throws IOException { if (src.isDirectory()) { @@ -276,9 +235,7 @@ public static void copyDirectory(File src, File dst) throws IOException { @SafeVarargs public static Collection createCollection(T... items) { Collection collection = new ArrayList<>(items.length); - for (T item: items) { - collection.add(item); - } + Collections.addAll(collection, items); return collection; } @@ -287,7 +244,7 @@ public static Collection createCollection(T... items) { */ public static Boolean and(Boolean... operands) { Boolean result = null; - for (Boolean operand: operands) { + for (Boolean operand : operands) { if (operand == null) { continue; } @@ -314,8 +271,8 @@ public static boolean equals(Object a, Object b) { * * @param date Instance of java.util.Date or a null reference * @return XMLGregorianCalendar instance whose value is based upon the - * value in the date parameter. If the date parameter is null then - * this method will simply return null. + * value in the date parameter. If the date parameter is null then + * this method will simply return null. */ public static XMLGregorianCalendar asXMLGregorianCalendar(java.util.Date date) { if (date == null) { @@ -342,8 +299,8 @@ public static XMLGregorianCalendar asXMLGregorianCalendar(Long timeInMilis) { * * @param xgc Instance of XMLGregorianCalendar or a null reference * @return java.util.Date instance whose value is based upon the - * value in the xgc parameter. If the xgc parameter is null then - * this method will simply return null. + * value in the xgc parameter. If the xgc parameter is null then + * this method will simply return null. */ public static java.util.Date asDate(XMLGregorianCalendar xgc) { if (xgc == null) { @@ -376,7 +333,7 @@ public static void carthesian(Collection> dimensions, Processo private static void carthesian(List items, List> dimensions, int dimensionNum, Processor> processor) { Collection myDimension = dimensions.get(dimensionNum); - for (T item: myDimension) { + for (T item : myDimension) { items.add(item); if (dimensionNum < dimensions.size() - 1) { carthesian(items, dimensions, dimensionNum + 1, processor); @@ -389,14 +346,14 @@ private static void carthesian(List items, List> dimensions public static String concat(Collection stringCollection) { StringBuilder sb = new StringBuilder(); - for (String s: stringCollection) { + for (String s : stringCollection) { sb.append(s); } return sb.toString(); } public static boolean isAllNull(Collection collection) { - for (Object o: collection) { + for (Object o : collection) { if (o != null) { return false; } @@ -408,7 +365,7 @@ public static String getValueWithClass(Object object) { if (object == null) { return "null"; } - return "("+object.getClass().getSimpleName() + ")" + object; + return "(" + object.getClass().getSimpleName() + ")" + object; } public static String getClass(Object object) { @@ -455,12 +412,12 @@ public static boolean hasNoValue(Collection collection) { /** * Shallow clone */ - public static Map cloneMap(Map orig) { + public static Map cloneMap(Map orig) { if (orig == null) { return null; } - Map clone = new HashMap<>(); - for (Entry origEntry: orig.entrySet()) { + Map clone = new HashMap<>(); + for (Entry origEntry : orig.entrySet()) { clone.put(origEntry.getKey(), origEntry.getValue()); } return clone; @@ -477,7 +434,7 @@ public static List splitLines(String string) { List lines = new ArrayList<>(); Scanner scanner = new Scanner(string); while (scanner.hasNextLine()) { - lines.add(scanner.nextLine()); + lines.add(scanner.nextLine()); } return lines; } @@ -488,7 +445,7 @@ public static boolean isBetween(XMLGregorianCalendar date, XMLGregorianCalendar } public static boolean contains(T element, T[] array) { - for (T aElement: array) { + for (T aElement : array) { if (equals(element, aElement)) { return true; } @@ -508,7 +465,7 @@ public static Collection getValuesFromDisplayableValues(Collection out = new ArrayList<>(disps.size()); - for (DisplayableValue disp: disps) { + for (DisplayableValue disp : disps) { out.add(disp.getValue()); } return out; @@ -524,9 +481,9 @@ public static String binaryToHex(byte[] bytes) { public static byte[] hexToBinary(String hex) { int l = hex.length(); - byte[] bytes = new byte[l/2]; + byte[] bytes = new byte[l / 2]; for (int i = 0; i < l; i += 2) { - bytes[i/2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4) + bytes[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4) + Character.digit(hex.charAt(i + 1), 16)); } return bytes; @@ -540,7 +497,7 @@ public static void addAllIfNotPresent(List receivingList, List supplyi if (supplyingList == null) { return; } - for (T supplyingElement: supplyingList) { + for (T supplyingElement : supplyingList) { addIfNotPresent(receivingList, supplyingElement); } } @@ -668,7 +625,7 @@ public static String nullIfEmpty(String s) { */ public static boolean hasDuplicates(Collection collection) { Set set = new HashSet<>(); - for (T e: collection) { + for (T e : collection) { if (!set.add(e)) { return true; } @@ -698,8 +655,7 @@ private static String formatExceptionMessage(Throwable t) { } @SuppressWarnings("unchecked") - private static void throwException(Throwable exception) throws T - { + private static void throwException(Throwable exception) throws T { throw (T) exception; } @@ -794,10 +750,10 @@ public static String takeThreadDump(@Nullable Thread thread) { return dump.toString(); } - public static Map paramsToMap(Object[] params) { + public static Map paramsToMap(Object[] params) { Map map = new HashMap<>(); - for (int i=0; i < params.length; i+=2) { - map.put((K)params[i], (V)params[i+1]); + for (int i = 0; i < params.length; i += 2) { + map.put((K) params[i], (V) params[i + 1]); } return map; }