Skip to content

Commit

Permalink
Decouple correlations from shadows, part one
Browse files Browse the repository at this point in the history
We plan to support correlation of (partial) focus objects to their
candidate matches. No shadows will be involved.

As a preparation, the CorrelationContext was made abstract, and two
children were created: Shadow and Focus. The latter is not finished.

Work in progress.
  • Loading branch information
mederly committed Jul 19, 2023
1 parent d5a6c0e commit aeda10f
Show file tree
Hide file tree
Showing 10 changed files with 182 additions and 95 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,28 +30,13 @@
*
* Not to be confused with {@link CorrelatorContext} which describes the context of the whole {@link Correlator} lifespan.
*/
public class CorrelationContext implements DebugDumpable, Cloneable {

/**
* Shadowed resource object to be correlated.
*/
@NotNull private final ShadowType resourceObject;
public abstract class CorrelationContext implements DebugDumpable, Cloneable {

/**
* Focus that was created using pre-mappings.
* May be empty (but not null) e.g. if there are no such mappings.
*/
@NotNull private final FocusType preFocus;

/**
* Resource on which the correlated shadow resides.
*/
@NotNull private final ResourceType resource;

/**
* Usually resource object type definition (~ schemaHandling section).
*/
@NotNull private final ResourceObjectDefinition resourceObjectDefinition;
@NotNull final FocusType preFocus;

/**
* System configuration to use during the correlation.
Expand All @@ -70,24 +55,14 @@ public class CorrelationContext implements DebugDumpable, Cloneable {
private AbstractCorrelatorStateType correlatorState;

public CorrelationContext(
@NotNull ShadowType resourceObject,
@NotNull FocusType preFocus,
@NotNull ResourceType resource,
@NotNull ResourceObjectDefinition objectDefinition,
@Nullable SystemConfigurationType systemConfiguration,
@NotNull Task task) {
this.resourceObject = resourceObject;
this.preFocus = preFocus;
this.resource = resource;
this.resourceObjectDefinition = objectDefinition;
this.systemConfiguration = systemConfiguration;
this.task = task;
}

public @NotNull ShadowType getResourceObject() {
return resourceObject;
}

public @NotNull FocusType getPreFocus() {
return preFocus;
}
Expand All @@ -96,20 +71,8 @@ public CorrelationContext(
return preFocus.getClass();
}

public @Nullable String getArchetypeOid() {
// Note that the archetype OID can be specified only on the object type. It is not supported
// for legacy synchronization definition. Therefore we may safely access it in the following way:
ResourceObjectTypeDefinition typeDefinition = resourceObjectDefinition.getTypeDefinition();
return typeDefinition != null ? typeDefinition.getArchetypeOid() : null;
}

public @NotNull ResourceType getResource() {
return resource;
}

public @NotNull ResourceObjectDefinition getResourceObjectDefinition() {
return resourceObjectDefinition;
}
/** Returns the archetype for focus objects that the candidate(s) must possess. Null means "no restrictions". */
public abstract @Nullable String getArchetypeOid();

public @Nullable SystemConfigurationType getSystemConfiguration() {
return systemConfiguration;
Expand All @@ -127,27 +90,23 @@ public void setCorrelatorState(AbstractCorrelatorStateType correlatorState) {
return task;
}

@Override
public String toString() {
return "CorrelationContext("
+ getFocusType().getSimpleName() + ", "
+ resourceObjectDefinition.getHumanReadableName() + "@" + resource
+ ')';
}

@Override
public String debugDump(int indent) {
StringBuilder sb = DebugUtil.createTitleStringBuilderLn(getClass(), indent);
DebugUtil.debugDumpWithLabelLn(sb, "resourceObject", resourceObject, indent + 1);
DebugUtil.debugDumpWithLabelLn(sb, "preFocus", preFocus, indent + 1);
DebugUtil.debugDumpWithLabelLn(sb, "focusType", getFocusType(), indent + 1);
DebugUtil.debugDumpWithLabelLn(sb, "resource", String.valueOf(resource), indent + 1);
DebugUtil.debugDumpWithLabelLn(sb, "resourceObjectDefinition", String.valueOf(resourceObjectDefinition), indent + 1);
debugDumpSpecific(sb, indent);
DebugUtil.debugDumpWithLabelLn(sb, "systemConfiguration", String.valueOf(systemConfiguration), indent + 1);
DebugUtil.debugDumpWithLabel(sb, "correlatorState", correlatorState, indent + 1);
return sb.toString();
}

void debugDumpSpecific(StringBuilder sb, int indent) {
// Nothing to do here. To be overridden by subclasses.
}

public @NotNull abstract Shadow asShadowCtx();

/**
* A simple shallow clone. Use with care.
*/
Expand All @@ -159,4 +118,119 @@ public CorrelationContext clone() {
throw new SystemException(e);
}
}

/** Returns the object (e.g. shadow or focus) that is being correlated. Currently for logging purposes. */
@NotNull public abstract ObjectType getPrimaryCorrelatedObject();

/** Context for correlating a shadow to a set of matching focuses. */
public static class Shadow extends CorrelationContext {

/**
* Shadowed resource object to be correlated.
*/
@NotNull private final ShadowType resourceObject;

/**
* Resource on which the correlated shadow resides.
*/
@NotNull private final ResourceType resource;

/**
* Usually resource object type definition (~ schemaHandling section).
*/
@NotNull private final ResourceObjectDefinition resourceObjectDefinition;

public Shadow(
@NotNull ShadowType resourceObject,
@NotNull ResourceType resource,
@NotNull ResourceObjectDefinition resourceObjectDefinition,
@NotNull FocusType preFocus,
@Nullable SystemConfigurationType systemConfiguration,
@NotNull Task task) {
super(preFocus, systemConfiguration, task);
this.resourceObject = resourceObject;
this.resource = resource;
this.resourceObjectDefinition = resourceObjectDefinition;
}

public @NotNull ShadowType getResourceObject() {
return resourceObject;
}

public @NotNull ResourceType getResource() {
return resource;
}

public @NotNull ResourceObjectDefinition getResourceObjectDefinition() {
return resourceObjectDefinition;
}

public @Nullable String getArchetypeOid() {
// Note that the archetype OID can be specified only on the object type. It is not supported
// for legacy synchronization definition. Therefore we may safely access it in the following way:
ResourceObjectTypeDefinition typeDefinition = resourceObjectDefinition.getTypeDefinition();
return typeDefinition != null ? typeDefinition.getArchetypeOid() : null;
}

@Override
public @NotNull Shadow asShadowCtx() {
return this;
}

@Override
public @NotNull ObjectType getPrimaryCorrelatedObject() {
return resourceObject;
}

@Override
public String toString() {
return "CorrelationContext.Shadow("
+ getFocusType().getSimpleName() + ", "
+ resourceObjectDefinition.getHumanReadableName() + "@" + resource
+ ')';
}

@Override
void debugDumpSpecific(StringBuilder sb, int indent) {
DebugUtil.debugDumpWithLabelLn(sb, "resourceObject", resourceObject, indent + 1);
DebugUtil.debugDumpWithLabelLn(sb, "resource", String.valueOf(resource), indent + 1);
DebugUtil.debugDumpWithLabelLn(sb, "resourceObjectDefinition", String.valueOf(resourceObjectDefinition), indent + 1);
}
}

/**
* Context for correlating a focus to a set of matching focuses.
*
* TODO finish this class
*/
public static class Focus extends CorrelationContext {

public Focus(
@NotNull FocusType preFocus, @Nullable SystemConfigurationType systemConfiguration, @NotNull Task task) {
super(preFocus, systemConfiguration, task);
}

@Override
public @NotNull Shadow asShadowCtx() {
throw new IllegalStateException("Focus context cannot be used as shadow context");
}

@Override
public @Nullable String getArchetypeOid() {
throw new UnsupportedOperationException(); // TODO implement
}

@Override
public @NotNull ObjectType getPrimaryCorrelatedObject() {
return preFocus;
}

@Override
public String toString() {
return "CorrelationContext.Focus("
+ getFocusType().getSimpleName() + ", "
+ preFocus
+ ')';
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ public boolean checkCandidateOwner(
CommunicationException, ConfigurationException, ObjectNotFoundException {
FocusType preFocus = computePreFocus(
shadowedResourceObject, resource, synchronizationPolicy, candidateOwner.getClass(), task, result);
CompleteContext ctx = new CompleteContext(
CompleteContext ctx = CompleteContext.forShadow(
shadowedResourceObject,
resource,
synchronizationPolicy.getObjectTypeDefinition(),
Expand Down Expand Up @@ -333,7 +333,8 @@ void resolve(
kind, intent, resource, shadow)));

FocusType preFocus = computePreFocus(shadow, resource, policy, policy.getFocusClass(), task, result);
return new CompleteContext(

return CompleteContext.forShadow(
shadow,
resource,
policy.getObjectTypeDefinition(),
Expand Down Expand Up @@ -408,12 +409,11 @@ public ObjectTemplateType determineObjectTemplate(
}

/** Contains both {@link CorrelatorContext} and {@link CorrelationContext}. Usually we create both of them together. */
private static class CompleteContext {

@NotNull final CorrelatorContext<?> correlatorContext;
@NotNull final CorrelationContext correlationContext;
private record CompleteContext(
@NotNull CorrelatorContext<?> correlatorContext,
@NotNull CorrelationContext correlationContext) {

CompleteContext(
static CompleteContext forShadow(
@NotNull ShadowType shadow,
@NotNull ResourceType resource,
@NotNull ResourceObjectDefinition resourceObjectDefinition,
Expand All @@ -423,19 +423,20 @@ private static class CompleteContext {
@Nullable SystemConfigurationType systemConfiguration,
@NotNull Task task)
throws SchemaException, ConfigurationException {
this.correlatorContext =
var correlatorContext =
CorrelatorContextCreator.createRootContext(
synchronizationPolicy.getCorrelationDefinition(),
objectTemplate,
systemConfiguration);
this.correlationContext =
new CorrelationContext(
var correlationContext =
new CorrelationContext.Shadow(
shadow,
preFocus,
resource,
resourceObjectDefinition,
preFocus,
systemConfiguration,
task);
return new CompleteContext(correlatorContext, correlationContext);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -197,10 +197,17 @@ protected abstract double checkCandidateOwnerInternal(
SecurityViolationException, ObjectNotFoundException;

protected @NotNull String getDefaultContextDescription(@NotNull CorrelationContext correlationContext) {
return (typeName + " correlator" +
(configurationBean.getName() != null ? " '" + configurationBean.getName() + "'" : ""))
+ " for " + correlationContext.getResourceObjectDefinition().getHumanReadableName()
+ " in " + correlationContext.getResource();
String prefix =
typeName + " correlator" +
(configurationBean.getName() != null ? " '" + configurationBean.getName() + "'" : "");
if (correlationContext instanceof CorrelationContext.Shadow shadowCtx) {
return prefix
+ " for " + shadowCtx.getResourceObjectDefinition().getHumanReadableName()
+ " in " + shadowCtx.getResource();
} else {
// TODO something for the focus-only correlation
return prefix;
}
}

protected @NotNull Correlator instantiateChild(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public static VariablesMap getVariablesMap(
VariablesMap variables = ModelImplUtils.getDefaultVariablesMap(
focus,
resourceObject,
correlationContext.getResource(),
correlationContext instanceof CorrelationContext.Shadow shadow ? shadow.getResource() : null,
correlationContext.getSystemConfiguration());
variables.put(ExpressionConstants.VAR_CORRELATION_CONTEXT, correlationContext, CorrelationContext.class);
variables.put(ExpressionConstants.VAR_CORRELATOR_STATE,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@
/**
* A correlator based on expressions that directly provide focal object(s) (or their references) for given resource object.
* Similar to synchronization sorter, but simpler - it treats only correlation, not the classification part.
*
* Currently supports only shadow-based correlations.
*/
class ExpressionCorrelator extends BaseCorrelator<ExpressionCorrelatorType> {

Expand All @@ -60,7 +62,7 @@ class ExpressionCorrelator extends BaseCorrelator<ExpressionCorrelatorType> {
throws SchemaException, ExpressionEvaluationException, CommunicationException, SecurityViolationException,
ConfigurationException, ObjectNotFoundException {

return new Correlation<>(correlationContext)
return new Correlation<>(correlationContext.asShadowCtx())
.execute(result);
}

Expand All @@ -82,14 +84,14 @@ private class Correlation<F extends FocusType> {
/** TODO: determine from the resource */
@Nullable private final ExpressionProfile expressionProfile = MiscSchemaUtil.getExpressionProfile();

Correlation(@NotNull CorrelationContext correlationContext) {
Correlation(@NotNull CorrelationContext.Shadow correlationContext) {
this.resourceObject = correlationContext.getResourceObject();
this.correlationContext = correlationContext;
this.task = correlationContext.getTask();
this.contextDescription = getDefaultContextDescription(correlationContext);
}

public CorrelationResult execute(OperationResult result)
CorrelationResult execute(OperationResult result)
throws SchemaException, ExpressionEvaluationException, CommunicationException, SecurityViolationException,
ConfigurationException, ObjectNotFoundException {
ObjectSet<F> candidateOwners = findCandidatesUsingExpressions(result);
Expand Down Expand Up @@ -158,8 +160,7 @@ private void addCandidateOwner(ObjectSet<F> allCandidates, PrismValue candidateV
//noinspection unchecked
candidateOwner = ((PrismObjectValue<F>) candidateValue).asObjectable();
checkOidPresent(candidateOwner.getOid(), candidateValue);
} else if (candidateValue instanceof PrismReferenceValue) {
PrismReferenceValue candidateOwnerRef = (PrismReferenceValue) candidateValue;
} else if (candidateValue instanceof PrismReferenceValue candidateOwnerRef) {
String oid = candidateOwnerRef.getOid();
checkOidPresent(oid, candidateValue);
if (allCandidates.containsOid(oid)) {
Expand Down

0 comments on commit aeda10f

Please sign in to comment.