Skip to content

Commit

Permalink
Merge branch 'master' of github.com:Evolveum/midpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
1azyman committed Jun 23, 2022
2 parents d7073c7 + 3bca7ce commit 27c33fb
Show file tree
Hide file tree
Showing 46 changed files with 1,731 additions and 1,184 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import java.util.Collection;
import java.util.stream.Collectors;

import com.evolveum.midpoint.model.common.ArchetypeManager;
import com.evolveum.midpoint.model.common.archetypes.ArchetypeManager;

import com.evolveum.midpoint.util.exception.SchemaException;

Expand Down Expand Up @@ -59,7 +59,8 @@ protected LookupTableType getPredefinedValues(PrismProperty<String> item, Wrappe
handlers = getTaskManager().getHandlerUrisForArchetype(archetypeAssignment.getTargetRef().getOid(), true);
} else {
try {
PrismObject<ArchetypeType> archetype = archetypeManager.determineStructuralArchetype(task.asPrismObject(), ctx.getResult());
ArchetypeType archetype = archetypeManager.determineStructuralArchetype(task, ctx.getResult());
// TODO what if there's no archetype?
handlers = getTaskManager().getHandlerUrisForArchetype(archetype.getOid(), true);
} catch (SchemaException e) {
throw new UnsupportedOperationException("More than 1 structural archetype, this is not supported", e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,19 @@ default boolean matchesKind(@Nullable ShadowKindType kind) {
/** Archetype reference - not present in standalone definitions. */
@Nullable ObjectReferenceType getArchetypeRef();

/** Archetype OID - a convenience method. */
default @Nullable String getArchetypeOid() {
ObjectReferenceType archetypeRef = getArchetypeRef();
if (archetypeRef == null) {
return null;
}
String oid = archetypeRef.getOid();
if (oid != null) {
return oid;
}
throw new UnsupportedOperationException("Dynamic references are not supported for archetypeRef; in " + this);
}

/** Returns true if there is "synchronization reactions" definition section here (even if it's empty). */
boolean hasSynchronizationReactionsDefinition();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ public class SynchronizationPolicy {
SynchronizationPolicy(
@NotNull ShadowKindType kind,
@Nullable QName focusTypeName,
@Nullable ObjectReferenceType archetypeRef,
@Nullable String archetypeOid,
@NotNull QName objectClassName,
@NotNull CorrelationDefinitionType correlationDefinitionBean,
boolean synchronizationEnabled,
Expand All @@ -100,7 +100,7 @@ public class SynchronizationPolicy {
boolean hasLegacyConfiguration) {
this.kind = kind;
this.focusTypeName = Objects.requireNonNullElse(focusTypeName, UserType.COMPLEX_TYPE);
this.archetypeOid = getArchetypeOid(archetypeRef);
this.archetypeOid = archetypeOid;
this.objectClassName = objectClassName;
this.correlationDefinitionBean = correlationDefinitionBean;
this.synchronizationEnabled = synchronizationEnabled;
Expand All @@ -113,17 +113,6 @@ public class SynchronizationPolicy {
this.hasLegacyConfiguration = hasLegacyConfiguration;
}

public static String getArchetypeOid(@Nullable ObjectReferenceType archetypeRef) {
if (archetypeRef == null) {
return null;
}
String oid = archetypeRef.getOid();
if (oid != null) {
return oid;
}
throw new UnsupportedOperationException("Dynamic references are not supported for archetypeRef");
}

public @NotNull ShadowKindType getKind() {
return kind;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ private static boolean isEnabled(CorrelationCasesDefinitionType cases) {
return new SynchronizationPolicy(
typeDef.getKind(),
typeDef.getFocusTypeName(),
typeDef.getArchetypeRef(),
typeDef.getArchetypeOid(),
typeDef.getObjectClassName(),
java.util.Objects.requireNonNullElseGet(
typeDef.getCorrelationDefinitionBean(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,40 @@
*/
package com.evolveum.midpoint.schema.util;

import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.util.MiscUtil;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ArchetypeType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ArchetypeTypeType;

import org.jetbrains.annotations.NotNull;

public class ArchetypeTypeUtil {

public static PrismObject<ArchetypeType> getStructuralArchetype(List<PrismObject<ArchetypeType>> archetypes) throws SchemaException {
if (archetypes == null) {
return null;
}
List<PrismObject<ArchetypeType>> structuralArchetypes = archetypes.stream()
.filter(archetype -> archetype.asObjectable().getArchetypeType() == null || archetype.asObjectable().getArchetypeType() == ArchetypeTypeType.STRUCTURAL)
.collect(Collectors.toList());
if (structuralArchetypes.size() > 1) {
throw new SchemaException("Found " + structuralArchetypes + " structural archetypes, only one structural archetype supported.");
}
if (structuralArchetypes.isEmpty()) {
return null;
}
return structuralArchetypes.get(0);
public static ArchetypeType getStructuralArchetype(Collection<ArchetypeType> archetypes) throws SchemaException {
List<ArchetypeType> structuralArchetypes =
MiscUtil.emptyIfNull(archetypes).stream()
.filter(ArchetypeTypeUtil::isStructural)
.collect(Collectors.toList());
return MiscUtil.extractSingleton(
structuralArchetypes,
() -> new SchemaException(
"Found " + structuralArchetypes + " structural archetypes; only a single one is supported."));
}

public static ArchetypeTypeType getType(@NotNull ArchetypeType archetype) {
return Objects.requireNonNullElse(archetype.getArchetypeType(), ArchetypeTypeType.STRUCTURAL);
}

public static boolean isStructural(@NotNull ArchetypeType archetype) {
return getType(archetype) == ArchetypeTypeType.STRUCTURAL;
}

public static boolean isAuxiliary(@NotNull ArchetypeType archetype) {
return getType(archetype) == ArchetypeTypeType.AUXILIARY;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -143,17 +143,12 @@ public static ProtectedStringType getPasswordValue(UserType user) {
return passwd.getValue();
}

@NotNull // to eliminate the need for extensive NPE avoidance
public static <O extends ObjectType> List<String> determineSubTypes(O object) {
public static @NotNull List<String> determineSubTypes(ObjectType object) {
return object != null ? determineSubTypes(object.asPrismObject()) : emptyList();
}

@NotNull // to eliminate the need for extensive NPE avoidance
public static <O extends ObjectType> List<String> determineSubTypes(PrismObject<O> object) {
if (object == null) {
return emptyList();
}
return object.asObjectable().getSubtype();
public static @NotNull List<String> determineSubTypes(PrismObject<? extends ObjectType> object) {
return object != null ? object.asObjectable().getSubtype() : emptyList();
}

public static <O extends ObjectType> boolean hasSubtype(PrismObject<O> object, String subtype) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1079,6 +1079,10 @@ public static Class<? extends ObjectType> getTargetClassFromReference(@NotNull O
}
}

public static String getOid(ObjectType object) {
return object != null ? object.getOid() : null;
}

@FunctionalInterface
private interface ExtensionItemRemover {
// Removes item (known from the context) from the extension
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -932,19 +932,26 @@
<xsd:element name="archetypeRef" type="tns:ObjectReferenceType" minOccurs="0">
<xsd:annotation>
<xsd:documentation>
Focus archetype corresponding to this resource object type. If specified, the value is used during
correlation (i.e. we look for focus objects having specified archetype), as well as during creation
of new focuses.
Focus archetype corresponding to this resource object type. If specified, the value is enforced upon
focus objects that have a projection of this object type linked. It is also used during correlation,
i.e. when correlating a resource object of this type, midPoint looks for focus objects having
specified archetype.

Notes:

1. Archetypes of existing users are checked against this value: If an existing user has no archetype,
it is assigned this one. If it has a different one, an error is reported. This behavior may change in the
future.
1. The archetype must be a structural one (currently). In the future, we may consider allowing
multiple (i.e. structural and/or auxiliary) archetypes here.

2. In the future, we may consider allowing multiple archetypes here.
2. The enforcement means that if the focus has no archetype, the archetype is added to the focus.
If it has a different archetype, a policy violation exception is raised. This behavior may change in the
future, e.g. this behavior may become configurable.

TODO: implement Note 1.
3. The enforcement is done for _all_ projections, i.e. also the ones that are created by the clockwork.
But beware of the timing: if a projection is added during the clockwork run, and that projection enforces
an archetype, the effects of this enforcement may be limited during the current clockwork run.
For example, if the archetype induces some projections, they might not be created because of the
processing in waves. Generally speaking, it is safer to set the focus archetype explicitly (e.g. by
primary delta or in the object template) in these cases.
</xsd:documentation>
<xsd:appinfo>
<xsd:appinfo>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,8 @@
import com.evolveum.midpoint.cases.impl.helpers.CaseExpressionEvaluationHelper;
import com.evolveum.midpoint.cases.impl.helpers.CaseMiscHelper;
import com.evolveum.midpoint.common.Clock;
import com.evolveum.midpoint.model.common.ArchetypeManager;
import com.evolveum.midpoint.model.common.archetypes.ArchetypeManager;
import com.evolveum.midpoint.prism.PrismContext;
import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.repo.api.PreconditionViolationException;
import com.evolveum.midpoint.repo.api.RepositoryService;
import com.evolveum.midpoint.schema.result.OperationResult;
Expand Down Expand Up @@ -164,16 +163,19 @@ public void executeRequest(

private CaseEngineOperationImpl createOperation(String caseOid, Task task, OperationResult result)
throws SchemaException, ObjectNotFoundException, SecurityViolationException {
PrismObject<CaseType> caseObject = repositoryService.getObject(CaseType.class, caseOid, null, result);
CaseType aCase =
repositoryService
.getObject(CaseType.class, caseOid, null, result)
.asObjectable();
return new CaseEngineOperationImpl(
caseObject.asObjectable(),
determineEngineExtension(caseObject, result),
aCase,
determineEngineExtension(aCase, result),
task,
beans,
SecurityUtil.getPrincipalRequired());
}

private @NotNull EngineExtension determineEngineExtension(@NotNull PrismObject<CaseType> aCase, OperationResult result)
private @NotNull EngineExtension determineEngineExtension(@NotNull CaseType aCase, OperationResult result)
throws SchemaException {
String archetypeOid = getCaseArchetypeOid(aCase, result);
LOGGER.trace("Going to determine engine extension for {}, archetype: {}", aCase, archetypeOid);
Expand All @@ -193,16 +195,16 @@ private Optional<EngineExtension> findRegisteredExtension(@NotNull String archet
.findFirst();
}

private String getCaseArchetypeOid(@NotNull PrismObject<CaseType> aCase, OperationResult result) throws SchemaException {
PrismObject<ArchetypeType> structuralArchetype = archetypeManager.determineStructuralArchetype(aCase, result);
private String getCaseArchetypeOid(@NotNull CaseType aCase, OperationResult result) throws SchemaException {
ArchetypeType structuralArchetype = archetypeManager.determineStructuralArchetype(aCase, result);
if (structuralArchetype != null) {
LOGGER.trace("Structural archetype found: {}", structuralArchetype);
return structuralArchetype.getOid();
}

// If there's exactly single archetypeRef value, but the archetype object does not exist
// (e.g. in some tests), let's try that.
List<ObjectReferenceType> archetypeRef = aCase.asObjectable().getArchetypeRef();
List<ObjectReferenceType> archetypeRef = aCase.getArchetypeRef();
if (archetypeRef.size() == 1) {
String fromRef = archetypeRef.get(0).getOid();
LOGGER.trace("Using an OID from (single) archetypeRef: {}", fromRef);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,8 @@ TaskType submitTaskFromTemplate(String templateTaskOid, Map<QName, Object> exten
*/
<O extends AssignmentHolderType> ArchetypePolicyType determineArchetypePolicy(PrismObject<O> assignmentHolder, OperationResult result) throws SchemaException, ConfigurationException;

ArchetypePolicyType mergeArchetypePolicies(PrismObject<ArchetypeType> archetype, OperationResult result) throws SchemaException;
ArchetypePolicyType mergeArchetypePolicies(PrismObject<ArchetypeType> archetype, OperationResult result)
throws SchemaException, ConfigurationException;
/**
* Returns data structure that contains information about possible assignment targets for a particular holder object.
* <p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,17 @@ public interface ModelElementContext<O extends ObjectType> extends Serializable,
PrismObject<O> getObjectNew();

/**
* @return "Any" value of the object in this order: new, current, old; taking the first non-null one.
* It is used when we are not interested in the details but we want just "any" value, e.g. for reporting
* purposes.
* @return "Any" value of the object (new, current, old). It is used when we are not interested in the details
* but we want just "any" value, e.g. for reporting purposes.
*/
PrismObject<O> getObjectAny();
default PrismObject<O> getObjectAny() {
return getObjectNewOrCurrentOrOld();
}

/**
* @return The first non-null object of these: new, current, old. (Or null of all of them all null.)
*/
PrismObject<O> getObjectNewOrCurrentOrOld();

/**
* @return OID of the object. If not determined yet, it is obtained from available sources, like
Expand Down Expand Up @@ -141,15 +147,19 @@ public interface ModelElementContext<O extends ObjectType> extends Serializable,
/**
* @return List of all executed deltas (in fact, {@link ObjectDeltaOperation} objects).
*/
List<? extends ObjectDeltaOperation> getExecutedDeltas();
List<? extends ObjectDeltaOperation<?>> getExecutedDeltas();

/**
* TODO is this method ever used?
*
* @return Determined archetype of the object. Currently not supported for projections.
* Since 4.4 structural archetype is returned
*/
ArchetypeType getArchetype();

/**
* TODO is this method ever used?
*
* @return All archetypes (structural and auxiliary)
*/
List<ArchetypeType> getArchetypes();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,12 +107,7 @@ public CorrelationContext(
// 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();
if (typeDefinition == null) {
return null;
} else {
return SynchronizationPolicy.getArchetypeOid(
typeDefinition.getArchetypeRef());
}
return typeDefinition != null ? typeDefinition.getArchetypeOid() : null;
}

public @NotNull ResourceType getResource() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import com.evolveum.midpoint.schema.processor.ResourceAttributeDefinition;
import com.evolveum.midpoint.schema.util.WorkItemId;
import com.evolveum.midpoint.util.LocalizableMessage;
import com.evolveum.midpoint.util.MiscUtil;
import com.evolveum.midpoint.util.annotation.Experimental;
import com.evolveum.midpoint.util.logging.LoggingUtils;
import com.evolveum.midpoint.util.logging.Trace;
Expand Down Expand Up @@ -1328,16 +1327,23 @@ default <O extends ObjectType> boolean hasArchetype(O object, String archetypeOi
* Assumes single archetype. May throw error if used on object that has more than one archetype.
*/
@Deprecated
<O extends ObjectType> ArchetypeType getArchetype(O object) throws SchemaException, ConfigurationException;
@NotNull <O extends ObjectType> List<ArchetypeType> getArchetypes(O object) throws SchemaException, ConfigurationException;
<O extends ObjectType> ArchetypeType getArchetype(O object) throws SchemaException;

@NotNull <O extends ObjectType> List<ArchetypeType> getArchetypes(O object) throws SchemaException;

/**
* Assumes single archetype. May throw error if used on object that has more than one archetype.
*/
@Deprecated
<O extends ObjectType> String getArchetypeOid(O object) throws SchemaException, ConfigurationException;
<O extends ObjectType> String getArchetypeOid(O object) throws SchemaException;

@NotNull <O extends ObjectType> List<String> getArchetypeOids(O object);
/**
* Returns a list of archetype OIDs for given object.
*
* Currently, those OIDs are taken from archetype assignments and `archetypeRef` values.
* (Note that under normal conditions, these should be in sync!)
*/
@NotNull List<String> getArchetypeOids(ObjectType object);

default <O extends ObjectType> void addRecomputeTrigger(O object, Long timestamp)
throws ObjectAlreadyExistsException, SchemaException, ObjectNotFoundException {
Expand Down

0 comments on commit 27c33fb

Please sign in to comment.