Skip to content

Commit

Permalink
Support activities in their own subtasks
Browse files Browse the repository at this point in the history
Now we can delegate activity execution to a (physical) subtask
by specifying distribution/subtask item. This execution is handled
by special DelegatedActivityExecution (as opposed to newly created
LocalActivityExecution covering all the standard cases).

Also implemented overview of the whole tree execution status
in the root task ($task/activityState/treeOverview).
  • Loading branch information
mederly committed Jun 9, 2021
1 parent 28c2cfd commit 4584d29
Show file tree
Hide file tree
Showing 46 changed files with 1,697 additions and 274 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -108,4 +108,14 @@ public ActivityPath append(String identifier) {
union.add(identifier);
return ActivityPath.fromList(union);
}

public ActivityPathType toBean() {
ActivityPathType bean = new ActivityPathType();
bean.getIdentifier().addAll(identifiers);
return bean;
}

public boolean equalsBean(ActivityPathType bean) {
return bean != null && identifiers.equals(bean.getIdentifier());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
* Copyright (C) 2010-2021 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.util.task;

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

import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.xml.ns._public.common.common_3.*;

import org.jetbrains.annotations.NotNull;

import org.jetbrains.annotations.Nullable;

public class ActivityStateOverviewUtil {

public static final ItemPath ACTIVITY_TREE_STATE_OVERVIEW_PATH =
ItemPath.create(TaskType.F_ACTIVITY_STATE, TaskActivityStateType.F_TREE_OVERVIEW);

public static @NotNull ActivityStateOverviewType findOrCreateEntry(@NotNull ActivityStateOverviewType current,
@NotNull ActivityPath path) {
if (path.isEmpty()) {
return current;
}
return findOrCreateEntry(
findOrCreateEntry(current, path.first()),
path.rest());
}

public static @NotNull ActivityStateOverviewType findOrCreateEntry(@NotNull ActivityStateOverviewType current,
String identifier) {
List<ActivityStateOverviewType> matching = current.getActivity().stream()
.filter(a -> Objects.equals(a.getIdentifier(), identifier))
.collect(Collectors.toList());
if (matching.isEmpty()) {
ActivityStateOverviewType newEntry = new ActivityStateOverviewType()
.identifier(identifier);
current.getActivity().add(newEntry);
return newEntry;
} else if (matching.size() == 1) {
return matching.get(0);
} else {
throw new IllegalStateException("State overview entry " + current + " contains " + matching.size() + " entries " +
"for activity identifier '" + identifier + "': " + matching);
}
}

public static boolean containsFailedExecution(@NotNull TaskType task) {
return task.getActivityState() != null &&
containsFailedExecution(task.getActivityState().getTreeOverview());
}

public static boolean containsFailedExecution(@Nullable ActivityStateOverviewType stateOverview) {
return stateOverview != null &&
(isExecutionFailed(stateOverview) ||
stateOverview.getActivity().stream().anyMatch(ActivityStateOverviewUtil::containsFailedExecution));
}

private static boolean isExecutionFailed(@NotNull ActivityStateOverviewType stateOverview) {
return stateOverview.getExecutionState() == ActivityExecutionStateType.NOT_EXECUTING &&
(stateOverview.getResultStatus() == OperationResultStatusType.FATAL_ERROR ||
stateOverview.getResultStatus() == OperationResultStatusType.PARTIAL_ERROR);
}

@NotNull
public static ActivityStateOverviewType getOrCreateTreeOverview(@NotNull TaskType taskBean) {
return taskBean.getActivityState() != null && taskBean.getActivityState().getTreeOverview() != null ?
taskBean.getActivityState().getTreeOverview() : new ActivityStateOverviewType();
}

public static ActivityStateOverviewType getTreeOverview(@NotNull TaskType taskBean) {
return taskBean.getActivityState() != null ? taskBean.getActivityState().getTreeOverview() : null;
}

public static void clearFailedState(@NotNull ActivityStateOverviewType state) {
doClearFailedState(state);
state.getActivity().forEach(ActivityStateOverviewUtil::clearFailedState);
}

private static void doClearFailedState(@NotNull ActivityStateOverviewType state) {
if (isExecutionFailed(state)) {
state.setExecutionState(null);
state.setResultStatus(null);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2457,6 +2457,13 @@
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="delegated" type="xsd:boolean" minOccurs="0">
<xsd:annotation>
<xsd:documentation>
True if the execution of the local root activity was delegated to this task.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="activity" type="tns:ActivityStateType" minOccurs="0">
<xsd:annotation>
<xsd:documentation>
Expand All @@ -2469,6 +2476,14 @@
<xsd:documentation>
True if all the work is complete. This means that on next run the task should start from
the beginning. (We do not simply erase the whole state e.g. because of progress reporting needs.)
Present only on the root task.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="treeOverview" type="tns:ActivityStateOverviewType" minOccurs="0">
<xsd:annotation>
<xsd:documentation>
Overview of the state of the whole activity tree.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
Expand Down Expand Up @@ -2552,6 +2567,68 @@
<xsd:attribute name="id" type="xsd:long"/>
</xsd:complexType>

<xsd:complexType name="ActivityStateOverviewType">
<xsd:annotation>
<xsd:documentation>
Describes the overview of the state of an activity.
This information is maintained in the root task only,
and is an excerpt from state information distributed throughout
the tree. It is intentionally not a container.
</xsd:documentation>
<xsd:appinfo>
<a:since>4.4</a:since>
<a:experimental>true</a:experimental>
</xsd:appinfo>
</xsd:annotation>
<xsd:sequence>
<xsd:element name="identifier" type="xsd:string" minOccurs="0">
<xsd:annotation>
<xsd:documentation>
Identifier of the activity.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="realizationState" type="tns:ActivitySimplifiedRealizationStateType" minOccurs="0">
<xsd:annotation>
<xsd:documentation>
State of the activity processing: null (not started), in progress, complete.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="executionState" type="tns:ActivityExecutionStateType" minOccurs="0">
<xsd:annotation>
<xsd:documentation>
Is the activity really executing now?
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="resultStatus" type="tns:OperationResultStatusType" minOccurs="0">
<xsd:annotation>
<xsd:documentation>
Operation result status of this activity. TODO
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="taskRef" type="tns:ObjectReferenceType" minOccurs="0">
<xsd:annotation>
<xsd:documentation>
The task in which the activity execution takes place.
</xsd:documentation>
<xsd:appinfo>
<a:objectReferenceTargetType>tns:TaskType</a:objectReferenceTargetType>
</xsd:appinfo>
</xsd:annotation>
</xsd:element>
<xsd:element name="activity" type="tns:ActivityStateOverviewType" minOccurs="0" maxOccurs="unbounded">
<xsd:annotation>
<xsd:documentation>
Work state overview of child activities.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
</xsd:sequence>
</xsd:complexType>

<xsd:simpleType name="ActivityRealizationStateType">
<xsd:annotation>
<xsd:documentation>
Expand Down Expand Up @@ -2596,6 +2673,95 @@
</xsd:restriction>
</xsd:simpleType>

<xsd:simpleType name="ActivityExecutionStateType">
<xsd:annotation>
<xsd:documentation>
Execution state of an activity - to be used in activity overview.
</xsd:documentation>
<xsd:appinfo>
<a:since>4.4</a:since>
<a:experimental>true</a:experimental>
</xsd:appinfo>
</xsd:annotation>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="executing">
<xsd:annotation>
<xsd:documentation>
Activity is executing.
</xsd:documentation>
<xsd:appinfo>
<jaxb:typesafeEnumMember name="EXECUTING"/>
</xsd:appinfo>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="executingReduced">
<xsd:annotation>
<xsd:documentation>
Activity is executing, although the speed of execution may be reduced e.g. because of some
of the tasks or threads failed. NOT IMPLEMENTED YET.
</xsd:documentation>
<xsd:appinfo>
<jaxb:typesafeEnumMember name="EXECUTING_REDUCED"/>
</xsd:appinfo>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="notExecuting">
<xsd:annotation>
<xsd:documentation>
Activity execution was suspended or interrupted before the activity was complete.
</xsd:documentation>
<xsd:appinfo>
<jaxb:typesafeEnumMember name="NOT_EXECUTING"/>
</xsd:appinfo>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="complete">
<xsd:annotation>
<xsd:documentation>
Activity is complete.
</xsd:documentation>
<xsd:appinfo>
<jaxb:typesafeEnumMember name="COMPLETE"/>
</xsd:appinfo>
</xsd:annotation>
</xsd:enumeration>
</xsd:restriction>
</xsd:simpleType>

<xsd:simpleType name="ActivitySimplifiedRealizationStateType">
<xsd:annotation>
<xsd:documentation>
Realization state of an activity - simplified for the sake of activity overview.
</xsd:documentation>
<xsd:appinfo>
<a:since>4.4</a:since>
<a:experimental>true</a:experimental>
</xsd:appinfo>
</xsd:annotation>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="inProgress">
<xsd:annotation>
<xsd:documentation>
Activity is in progress.
</xsd:documentation>
<xsd:appinfo>
<jaxb:typesafeEnumMember name="IN_PROGRESS"/>
</xsd:appinfo>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="complete">
<xsd:annotation>
<xsd:documentation>
Activity is complete.
</xsd:documentation>
<xsd:appinfo>
<jaxb:typesafeEnumMember name="COMPLETE"/>
</xsd:appinfo>
</xsd:annotation>
</xsd:enumeration>
</xsd:restriction>
</xsd:simpleType>

<!--<xsd:simpleType name="ActivityExecutionResultType">-->
<!-- <xsd:annotation>-->
<!-- <xsd:documentation>-->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,10 @@ public static void debugDumpWithLabelLn(StringBuilder sb, String label, String v
sb.append("\n");
}

public static void debugDumpWithLabelLn(StringBuilder sb, String label, Enum val, int indent) {
debugDumpWithLabelLn(sb, label, String.valueOf(val), indent);
}

public static void debugDumpWithLabel(StringBuilder sb, String label, QName val, int indent) {
debugDumpLabel(sb, label, indent);
sb.append(" ");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public void test100FixDuplicatesWithDifferentObjectClasses() throws Exception {

// WHEN
when();
waitForTaskCloseOrSuspend(TASK_SHADOW_INTEGRITY_CHECK_OID);
waitForTaskCloseOrSuspendOrActivityFail(TASK_SHADOW_INTEGRITY_CHECK_OID);

// THEN
then();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1192,8 +1192,8 @@ public void test560StartTaskFromTemplate() throws Exception {
String oid1 = ((PrismObjectValue<?>) data.getData().get(0).getValue()).getOid();
String oid2 = ((PrismObjectValue<?>) data.getData().get(1).getValue()).getOid();

waitForTaskCloseOrSuspend(oid1, 20000);
waitForTaskCloseOrSuspend(oid2, 20000);
waitForTaskCloseOrSuspendOrActivityFail(oid1, 20000);
waitForTaskCloseOrSuspendOrActivityFail(oid2, 20000);

PrismObject<UserType> jack = getUser(USER_JACK_OID);
PrismObject<UserType> administrator = getUser(USER_ADMINISTRATOR_OID);
Expand Down

0 comments on commit 4584d29

Please sign in to comment.