Skip to content

Commit

Permalink
Improve applySchemasAndSecurity perf test
Browse files Browse the repository at this point in the history
The test is now more realistic, as there's an archetype plus template
with some definition overriding. Moreover, we introduced three modes
of definition updating: NONE, ROOT_ONLY, and FULL. The first two would
allow use pre-computed definitions for archetypes without the need
to touch the objects (except for cloning immutable ones!). Hence,
we'll aim for NONE definition update mode, if possible.
  • Loading branch information
mederly committed Apr 20, 2023
1 parent 0ffb46f commit 20302b0
Show file tree
Hide file tree
Showing 8 changed files with 323 additions and 68 deletions.
@@ -0,0 +1,39 @@
/*
* Copyright (c) 2010-2017 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.schema;

import com.evolveum.midpoint.util.annotation.Experimental;

/**
* Should be definitions updated after an object is retrieved via model API?
* See `applySchemasAndSecurity` method.
*
* Applicable only on the root level.
*
* TEMPORARY, mainly for the purposes of experiments with various approaches during midPoint 4.8 development.
*/
@Experimental
public enum DefinitionUpdateOption {

/**
* The object or container definition is not to be updated at all.
*/
NONE,

/**
* Only the definition at the root level (object or container) is updated.
* Definitions of the child items (if any) are not touched.
* For example, the client may apply the root definition if needed.
*/
ROOT_ONLY,

/**
* Updated definition is propagated onto all items in the returned structure.
*/
DEEP;
}
Expand Up @@ -212,6 +212,14 @@ public class GetOperationOptions extends AbstractOptions implements Serializable
*/
private DefinitionProcessingOption definitionProcessing;

/**
* Probably temporary. Default is {@link DefinitionUpdateOption#NONE}.
*
* @see DefinitionUpdateOption
*/
@Experimental
private DefinitionUpdateOption definitionUpdate;

/**
* Whether to override default iteration method (in searchObjectsIterative) configured for particular DBMS.
*
Expand Down Expand Up @@ -920,6 +928,23 @@ public static GetOperationOptions createDefinitionProcessing(DefinitionProcessin
return opts;
}

public DefinitionUpdateOption getDefinitionUpdate() {
return definitionUpdate;
}

public void setDefinitionUpdate(DefinitionUpdateOption value) {
this.definitionUpdate = value;
}

public GetOperationOptions definitionUpdate(DefinitionUpdateOption value) {
this.definitionUpdate = value;
return this;
}

public static DefinitionUpdateOption getDefinitionUpdate(GetOperationOptions options) {
return options != null ? options.definitionUpdate : null;
}

public IterationMethodType getIterationMethod() {
return iterationMethod;
}
Expand Down
Expand Up @@ -12,6 +12,7 @@
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import com.evolveum.midpoint.util.annotation.Experimental;

Expand Down Expand Up @@ -85,4 +86,10 @@ public boolean isEmpty() {
public Map<DefinitionProcessingOption, PathSet> getDefinitionProcessingMap() {
return SelectorOptions.extractOptionValues(originalCollection, (o) -> o.getDefinitionProcessing());
}

public @NotNull DefinitionUpdateOption getDefinitionUpdate() {
return Objects.requireNonNullElse(
GetOperationOptions.getDefinitionUpdate(getRootOptions()),
DefinitionUpdateOption.DEEP); // temporary default
}
}
Expand Up @@ -242,23 +242,31 @@ SearchResultList<C> applySchemasAndSecurityToContainers(

object = object.cloneIfImmutable(); // TODO clone only if really needed

DefinitionUpdateOption definitionUpdateOption = parsedOptions.getDefinitionUpdate();
boolean raw = GetOperationOptions.isRaw(rootOptions);

// we must determine the template before items are stripped off due to authorizations
ObjectTemplateType objectTemplate = !raw && definitionUpdateOption != DefinitionUpdateOption.NONE ?
determineObjectTemplate(object, result) : null;

if (!GetOperationOptions.isExecutionPhase(rootOptions)) {
applySchemasAndSecurityPhase(object, securityConstraints, AuthorizationPhaseType.REQUEST);
}
applySchemasAndSecurityPhase(object, securityConstraints, AuthorizationPhaseType.EXECUTION);

// TODO is this needed?
transform(object, new DefinitionsToTransformable());
if (definitionUpdateOption != DefinitionUpdateOption.NONE) {
// TODO is this needed?
transform(object, new DefinitionsToTransformable());

// we do not need to process object template when processing in raw mode
// TODO cache the definitions
if (!GetOperationOptions.isRaw(rootOptions)) {
ObjectTemplateType objectTemplate = determineObjectTemplate(object, result);
applyObjectTemplateToObject(object, objectTemplate, task, result);
}
// we do not need to process object template when processing in raw mode
// TODO cache the definitions
if (objectTemplate != null) {
applyObjectTemplateToObject(object, objectTemplate, definitionUpdateOption, task, result);
}

// TODO consider removing this as it shouldn't be needed after definitions caching is implemented
applyDefinitionProcessingOption(object, parsedOptions);
// TODO consider removing this as it shouldn't be needed after definitions caching is implemented
applyDefinitionProcessingOption(object, parsedOptions);
}
} catch (Throwable t) {
result.recordException(t);
throw t;
Expand Down Expand Up @@ -759,19 +767,20 @@ <O extends ObjectType> void applyObjectTemplateToDefinition(
applyObjectTemplateToDefinition(objectDefinition, subTemplate.asObjectable(), task, result);
}
for (ObjectTemplateItemDefinitionType templateItemDef: objectTemplate.getItem()) {
ItemPath itemPath = ItemRefinedDefinitionTypeUtil.getRef(templateItemDef);
ItemDefinition<?> itemDef = objectDefinition.findItemDefinition(itemPath);
if (itemDef != null) {
applyObjectTemplateItem(itemDef, templateItemDef, "item " + itemPath + " in object type " + objectDefinition.getTypeName() + " as specified in item definition in " + objectTemplate);
} else {
OperationResult subResult = result.createMinorSubresult(SchemaTransformer.class.getName() + ".applyObjectTemplateToDefinition");
subResult.recordPartialError("No definition for item " + itemPath + " in object type " + objectDefinition.getTypeName() + " as specified in item definition in " + objectTemplate);
}
ItemPath itemPath = ItemRefinedDefinitionTypeUtil.getRef(templateItemDef);
ItemDefinition<?> itemDef = objectDefinition.findItemDefinition(itemPath);
if (itemDef != null) {
applyObjectTemplateItem(itemDef, templateItemDef, "item " + itemPath + " in object type " + objectDefinition.getTypeName() + " as specified in item definition in " + objectTemplate);
} else {
OperationResult subResult = result.createMinorSubresult(SchemaTransformer.class.getName() + ".applyObjectTemplateToDefinition");
subResult.recordPartialError("No definition for item " + itemPath + " in object type " + objectDefinition.getTypeName() + " as specified in item definition in " + objectTemplate);
}
}
}

private <O extends ObjectType> void applyObjectTemplateToObject(
PrismObject<O> object, ObjectTemplateType objectTemplate, Task task, OperationResult result)
PrismObject<O> object, ObjectTemplateType objectTemplate, DefinitionUpdateOption option,
Task task, OperationResult result)
throws ObjectNotFoundException, SchemaException, ConfigurationException {
if (objectTemplate == null) {
return;
Expand All @@ -783,7 +792,7 @@ private <O extends ObjectType> void applyObjectTemplateToObject(
for (ObjectReferenceType includeRef: objectTemplate.getIncludeRef()) {
PrismObject<ObjectTemplateType> subTemplate = cacheRepositoryService.getObject(
ObjectTemplateType.class, includeRef.getOid(), createReadOnlyCollection(), result);
applyObjectTemplateToObject(object, subTemplate.asObjectable(), task, result);
applyObjectTemplateToObject(object, subTemplate.asObjectable(), option, task, result);
}
for (ObjectTemplateItemDefinitionType templateItemDef: objectTemplate.getItem()) {
ItemPath itemPath = ItemRefinedDefinitionTypeUtil.getRef(templateItemDef);
Expand All @@ -797,12 +806,14 @@ private <O extends ObjectType> void applyObjectTemplateToObject(
+ " as specified in item definition in " + objectTemplate);
continue;
}
Collection<Item<?, ?>> items = object.getAllItems(itemPath);
for (Item<?, ?> item : items) {
ItemDefinition<?> itemDef = item.getDefinition();
if (itemDef != itemDefFromObject) {
applyObjectTemplateItem(itemDef, templateItemDef, "item "+itemPath+" in " + object
+ " as specified in item definition in "+objectTemplate);
if (option == DefinitionUpdateOption.DEEP) {
Collection<Item<?, ?>> items = object.getAllItems(itemPath);
for (Item<?, ?> item : items) {
ItemDefinition<?> itemDef = item.getDefinition();
if (itemDef != itemDefFromObject) {
applyObjectTemplateItem(itemDef, templateItemDef, "item " + itemPath + " in " + object
+ " as specified in item definition in " + objectTemplate);
}
}
}
}
Expand Down

0 comments on commit 20302b0

Please sign in to comment.