Skip to content

Commit

Permalink
Clean up synchronization-related code
Browse files Browse the repository at this point in the history
This is a preparation for giant leaps in the area of resource
configuration changes planned in weeks to come.

1. Separated shadow tag generation from the shadow classification
(just to be precise in the use of terms).

2. Made further fields SynchronizationContext final. This makes
the data flow during context loading much cleaner.

3. Migrate from the use of kind/intent to use of object type definition.
This may be too brave, but hopefully reasonable. We don't want to deal
with messy combinations of account/unknown and similar classifications.

4. ResourceObjectClassifierImpl is now stand-alone component, not using
SynchronizationContext anymore.

5. Introduced lightweight ResourceObjectProcessingContext to be used
throughout synchronization-related code.

6. Added model expression environment for tag generation.

Work in progress. Some tests may fail.
  • Loading branch information
mederly committed Apr 13, 2022
1 parent 79b9423 commit 5e84141
Show file tree
Hide file tree
Showing 34 changed files with 1,167 additions and 725 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@

import com.evolveum.midpoint.prism.PrismContext;

import com.evolveum.midpoint.schema.util.ShadowUtil;

import com.google.common.base.Preconditions;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
Expand Down Expand Up @@ -107,6 +110,10 @@ private ResourceObjectTypeSynchronizationPolicy(
public static @Nullable ResourceObjectTypeSynchronizationPolicy forKindAndIntent(
@NotNull ShadowKindType kind, @NotNull String intent, @NotNull ResourceType resource)
throws SchemaException, ConfigurationException {

Preconditions.checkArgument(ShadowUtil.isKnown(kind), "kind is not known: %s", kind);
Preconditions.checkArgument(ShadowUtil.isKnown(intent), "intent is not known: %s", intent);

ResourceSchema schema = ResourceSchemaFactory.getCompleteSchemaRequired(resource);
ResourceObjectTypeSynchronizationPolicy embeddedPolicy = getEmbeddedPolicyIfPresent(kind, intent, schema);
if (embeddedPolicy != null) {
Expand All @@ -116,6 +123,16 @@ private ResourceObjectTypeSynchronizationPolicy(
}
}

/** Temporary implementation. */
public static @Nullable ResourceObjectTypeSynchronizationPolicy forTypeDefinition(
@NotNull ResourceObjectTypeDefinition definition, @NotNull ResourceType resource)
throws SchemaException, ConfigurationException {
return forKindAndIntent(
definition.getKind(),
definition.getIntent(),
resource);
}

private static @Nullable ResourceObjectTypeSynchronizationPolicy getEmbeddedPolicyIfPresent(
@NotNull ShadowKindType kind, @NotNull String intent, @NotNull ResourceSchema schema) {
ResourceObjectDefinition definition = schema.findObjectDefinition(kind, intent);
Expand Down Expand Up @@ -209,15 +226,15 @@ private ResourceObjectTypeSynchronizationPolicy(
}

/**
* Compares the policy to given discriminator (containing kind & intent).
* Returns true if the policy is applicable to given synchronization discriminator (sorter result):
* compares its kind and intent.
*/
public boolean isApplicableToDiscriminator(@NotNull ObjectSynchronizationDiscriminatorType discriminator)
throws SchemaException {
public boolean isApplicableToSynchronizationDiscriminator(@NotNull ObjectSynchronizationDiscriminatorType discriminator) {
ShadowKindType kind = discriminator.getKind();
String intent = discriminator.getIntent();
if (kind == null && intent == null) { // shouldn't be "||" here?
throw new SchemaException(
"Illegal state, object synchronization discriminator must have kind/intent specified. "
if (kind == null || intent == null) {
throw new IllegalArgumentException(
"Object synchronization discriminator must have both kind and intent specified. "
+ "Current values are: kind=" + kind + ", intent=" + intent);
}
return isApplicableTo(null, kind, intent, false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

package com.evolveum.midpoint.schema.processor;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
Expand All @@ -21,6 +22,8 @@
import com.evolveum.midpoint.util.exception.ConfigurationException;
import com.evolveum.midpoint.util.exception.SchemaException;

import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
import com.evolveum.midpoint.xml.ns._public.common.common_3.*;

import com.google.common.annotations.VisibleForTesting;
Expand Down Expand Up @@ -58,6 +61,8 @@
*/
public interface ResourceSchema extends PrismSchema, Cloneable, LayeredDefinition {

Trace LOGGER = TraceManager.getTrace(ResourceSchema.class);

/** Returns definitions for all the object classes. */
default @NotNull Collection<ResourceObjectClassDefinition> getObjectClassDefinitions() {
return getDefinitions(ResourceObjectClassDefinition.class);
Expand Down Expand Up @@ -177,6 +182,19 @@ public interface ResourceSchema extends PrismSchema, Cloneable, LayeredDefinitio
return (ResourceObjectTypeDefinition) definition;
}

/**
* Sometimes we need _type_ definition (not object class definition).
*/
default @Nullable ResourceObjectTypeDefinition findObjectTypeDefinition(
@NotNull ShadowKindType kind, @NotNull String intent) {
ResourceObjectDefinition definition = findObjectDefinition(kind, intent);
if (definition instanceof ResourceObjectTypeDefinition) {
return (ResourceObjectTypeDefinition) definition;
} else {
return null;
}
}

/**
* Determines object definition (type or class level) when only kind is specified (i.e. intent is null).
* Optional filtering using object class name is available.
Expand Down Expand Up @@ -420,8 +438,42 @@ private boolean matchesAnyIntent(@NotNull ResourceObjectTypeDefinition def, @Not

/**
* Returns true if the schema contains no "refined" (type) definitions.
*
* BEWARE! Even schemas obtained via {@link ResourceSchemaFactory#getCompleteSchema(ResourceType)} method
* may seem raw, if there's no `schemaHandling` section. This should be perhaps fixed.
*/
default boolean isRaw() {
return getObjectTypeDefinitions().isEmpty();
}

/**
* TEMPORARY CODE
*/
default Collection<ResourceObjectTypeSynchronizationPolicy> getAllSynchronizationPolicies(ResourceType resource) {

List<ResourceObjectTypeSynchronizationPolicy> policies = new ArrayList<>();

for (ResourceObjectTypeDefinition typeDef : getObjectTypeDefinitions()) {
ObjectSynchronizationType syncDef = typeDef.getDefinitionBean().getSynchronization();
if (syncDef != null) {
policies.add(ResourceObjectTypeSynchronizationPolicy.forEmbedded(typeDef, syncDef));
}
}

SynchronizationType synchronization = resource.getSynchronization();
if (synchronization != null) {
for (ObjectSynchronizationType synchronizationBean : synchronization.getObjectSynchronization()) {
ResourceObjectTypeSynchronizationPolicy policy =
ResourceObjectTypeSynchronizationPolicy.forStandalone(synchronizationBean, this);
if (policy != null) {
policies.add(policy);
} else {
LOGGER.warn("Synchronization configuration {} cannot be connected to resource object definition in {}",
synchronizationBean, resource);
}
}
}

return policies;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -895,6 +895,11 @@ public static boolean isNotKnown(String intent) {
return !isKnown(intent);
}

public static boolean isClassified(ShadowType shadow) {
// We want to be explicit here: no defaults (like kind=account, intent=default) are accepted!
return isKnown(shadow.getKind()) && isKnown(shadow.getIntent());
}

public static void removeAllAttributesExceptPrimaryIdentifier(PrismObject<ShadowType> shadow,
ResourceObjectDefinition objDef) {
ResourceAttributeContainer attributesContainer = getAttributesContainer(shadow);
Expand Down Expand Up @@ -947,7 +952,7 @@ public static void setCorrelatorState(@NotNull ShadowType shadow, @Nullable Abst
return;
} else {
shadow.setCorrelation(
new ShadowCorrelationStateType(PrismContext.get()));
new ShadowCorrelationStateType());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import javax.annotation.PreDestroy;

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;
Expand All @@ -24,9 +25,7 @@
import com.evolveum.midpoint.repo.api.CacheRegistry;
import com.evolveum.midpoint.repo.api.Cache;
import com.evolveum.midpoint.repo.api.RepositoryService;
import com.evolveum.midpoint.schema.GetOperationOptions;
import com.evolveum.midpoint.schema.SearchResultList;
import com.evolveum.midpoint.schema.SelectorOptions;
import com.evolveum.midpoint.schema.expression.ExpressionProfile;
import com.evolveum.midpoint.schema.expression.ExpressionProfiles;
import com.evolveum.midpoint.schema.result.OperationResult;
Expand All @@ -37,6 +36,7 @@
import com.evolveum.midpoint.xml.ns._public.common.common_3.*;

import static com.evolveum.midpoint.schema.GetOperationOptions.createReadOnlyCollection;
import static com.evolveum.midpoint.schema.util.ObjectTypeUtil.asObjectable;

/**
* Cache for system object such as SystemConfigurationType. This is a global cache,
Expand Down Expand Up @@ -96,7 +96,13 @@ private long getSecurityPolicyExpirationMillis() {
return 1000;
}

public synchronized PrismObject<SystemConfigurationType> getSystemConfiguration(OperationResult result) throws SchemaException {
public @Nullable SystemConfigurationType getSystemConfigurationBean(OperationResult result) throws SchemaException {
return asObjectable(
getSystemConfiguration(result));
}

public synchronized @Nullable PrismObject<SystemConfigurationType> getSystemConfiguration(OperationResult result)
throws SchemaException {
try {
if (!hasValidSystemConfiguration(result)) {
LOGGER.trace("Cache MISS: reading system configuration from the repository: {}, version {}",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
import com.evolveum.midpoint.model.common.ModelCommonBeans;

import com.evolveum.midpoint.model.common.SystemObjectCache;
import com.evolveum.midpoint.model.impl.classification.ResourceObjectClassifierImpl;
import com.evolveum.midpoint.model.impl.classification.ShadowTagGeneratorImpl;
import com.evolveum.midpoint.model.impl.correlator.BuiltInResultCreator;
import com.evolveum.midpoint.model.impl.correlation.CorrelationCaseManager;
import com.evolveum.midpoint.model.impl.lens.*;
Expand All @@ -28,13 +30,13 @@
import com.evolveum.midpoint.model.impl.lens.projector.policy.scriptExecutor.PolicyRuleScriptExecutor;
import com.evolveum.midpoint.model.impl.migrator.Migrator;
import com.evolveum.midpoint.model.impl.security.SecurityHelper;
import com.evolveum.midpoint.model.impl.sync.SynchronizationExpressionsEvaluator;
import com.evolveum.midpoint.model.impl.sync.SynchronizationService;
import com.evolveum.midpoint.model.impl.sync.tasks.SyncTaskHelper;
import com.evolveum.midpoint.prism.crypto.Protector;
import com.evolveum.midpoint.provisioning.api.EventDispatcher;
import com.evolveum.midpoint.provisioning.api.ProvisioningService;

import com.evolveum.midpoint.provisioning.api.ResourceObjectClassifier;
import com.evolveum.midpoint.repo.common.expression.ExpressionFactory;
import com.evolveum.midpoint.schema.SchemaService;

Expand Down Expand Up @@ -130,5 +132,7 @@ public static ModelBeans get() {
@Autowired public CorrelationCaseManager correlationCaseManager;
@Autowired public CorrelationService correlationService;
@Autowired public BuiltInResultCreator builtInResultCreator;
@Autowired public ResourceObjectClassifier resourceObjectClassifier;
@Autowired public ResourceObjectClassifierImpl resourceObjectClassifier;
@Autowired public ShadowTagGeneratorImpl shadowTagGenerator;
@Autowired public SynchronizationExpressionsEvaluator synchronizationExpressionsEvaluator;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* Copyright (C) 2010-2022 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;

import com.evolveum.midpoint.model.api.correlator.CorrelationContext;
import com.evolveum.midpoint.model.impl.sync.SynchronizationContext;
import com.evolveum.midpoint.model.impl.util.ModelImplUtils;
import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.prism.delta.ObjectDelta;
import com.evolveum.midpoint.provisioning.api.ResourceObjectClassifier;
import com.evolveum.midpoint.provisioning.api.ResourceObjectShadowChangeDescription;
import com.evolveum.midpoint.schema.expression.VariablesMap;
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.util.annotation.Experimental;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.SystemConfigurationType;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

/**
* A context generally useful for the manipulation of a shadow - classification, correlation, synchronization.
*
* We use it to avoid repeating the contained data throughout various "context" classes
* ({@link SynchronizationContext}, {@link CorrelationContext}, ...).
*/
@Experimental
public interface ResourceObjectProcessingContext {

/**
* Returns shadowed resource object, or - at least - so-called "combined object" in the sense
* used in {@link ResourceObjectClassifier}.
*/
@NotNull ShadowType getShadowedResourceObject();

@Nullable ObjectDelta<ShadowType> getResourceObjectDelta();

@NotNull ResourceType getResource();

default @NotNull PrismObject<ResourceType> getResourcePrismObject() {
return getResource().asPrismObject();
}

@Nullable SystemConfigurationType getSystemConfiguration();

/**
* Returns the channel relevant to the current operation.
*
* It may be a channel from {@link ResourceObjectShadowChangeDescription} or from a task.
*/
@Nullable String getChannel();

@NotNull Task getTask();

/**
* Returns {@link VariablesMap} relevant for the current context.
*/
default @NotNull VariablesMap createVariablesMap() {
return createDefaultVariablesMap();
}

/** To be used in implementations of {@link #createVariablesMap()}. */
default @NotNull VariablesMap createDefaultVariablesMap() {
return ModelImplUtils.getDefaultVariablesMap(null, getShadowedResourceObject(), getResource(), getSystemConfiguration());
}

/** Useful Spring beans. */
@NotNull ModelBeans getBeans();
}

0 comments on commit 5e84141

Please sign in to comment.