Skip to content

Commit

Permalink
Fix activity tree overview structure
Browse files Browse the repository at this point in the history
The tree overview structure is now aligned with the needs of GUI:
it contains things to be displayed in the task list. So we no longer
have to retrieve the whole task tree to be able to display progress,
errors, and overall status of a task tree.

Properties added:
 - simplified bucket-related progress,
 - per-task entry carrying task state and items-related progress.

Related changes:
 - Fixed working with task-level statistics in activity-based tasks.
 - Renamed legacy progress-related methods in Task API.
 - Removed obsolete items from StatisticsCollectionStrategy.

Fixes MID-7184.
  • Loading branch information
mederly committed Sep 9, 2021
1 parent edac637 commit 82c2b72
Show file tree
Hide file tree
Showing 106 changed files with 2,826 additions and 1,028 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/
package com.evolveum.midpoint.schema.result;

import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.Nullable;

import com.evolveum.midpoint.xml.ns._public.common.common_3.OperationResultStatusType;
Expand Down Expand Up @@ -100,6 +101,7 @@ public enum OperationResultStatus {
}
}

@Contract("null -> null; !null -> !null")
public static @Nullable OperationResultStatusType createStatusType(
@Nullable OperationResultStatus status) {
if (status == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,12 @@
package com.evolveum.midpoint.schema.statistics;

import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.schema.util.task.ActivityPath;
import com.evolveum.midpoint.util.annotation.Experimental;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ActivityItemProcessingStatisticsType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType;

import org.jetbrains.annotations.NotNull;

import java.util.List;

// TODO consider renaming?
@Deprecated
@Deprecated // TODO migrate to activity reporting, see MID-7209
public interface IterativeOperationCollector {

/**
Expand Down Expand Up @@ -48,13 +43,4 @@ default IterationInformation.Operation recordIterativeOperationStart(PrismObject
* Resets iterative task information collection, starting from a given value.
*/
void resetIterativeTaskInformation(ActivityItemProcessingStatisticsType value, boolean collectExecutions);

/**
* Returns last N failures. Deprecated.
*/
@NotNull
@Experimental
@Deprecated
List<String> getLastFailures();

}
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,12 @@

import org.jetbrains.annotations.NotNull;

import com.evolveum.midpoint.schema.util.task.ActivityProgressInformationBuilder.InformationSource;
import com.evolveum.midpoint.util.DebugDumpable;
import com.evolveum.midpoint.util.DebugUtil;
import com.evolveum.midpoint.util.exception.ObjectNotFoundException;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.util.logging.LoggingUtils;
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.evolveum.midpoint.xml.ns._public.common.common_3.ActivityRealizationStateType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ActivitySimplifiedRealizationStateType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.TaskType;

/**
* Summarized representation of a progress of an activity and its sub-activities.
Expand All @@ -36,8 +34,6 @@
*/
public class ActivityProgressInformation implements DebugDumpable, Serializable {

private static final Trace LOGGER = TraceManager.getTrace(ActivityProgressInformation.class);

/**
* Activity identifier.
*/
Expand Down Expand Up @@ -66,9 +62,9 @@ public class ActivityProgressInformation implements DebugDumpable, Serializable
*/
private final ItemsProgressInformation itemsProgress;

@NotNull private final List<ActivityProgressInformation> children = new ArrayList<>();
@NotNull final List<ActivityProgressInformation> children = new ArrayList<>();

private ActivityProgressInformation(String activityIdentifier, @NotNull ActivityPath activityPath,
ActivityProgressInformation(String activityIdentifier, @NotNull ActivityPath activityPath,
RealizationState realizationState, BucketsProgressInformation bucketsProgress,
ItemsProgressInformation itemsProgress) {
this.activityIdentifier = activityIdentifier;
Expand All @@ -78,106 +74,26 @@ private ActivityProgressInformation(String activityIdentifier, @NotNull Activity
this.itemsProgress = itemsProgress;
}

private static @NotNull ActivityProgressInformation unknown(String activityIdentifier, ActivityPath activityPath) {
static @NotNull ActivityProgressInformation unknown(String activityIdentifier, ActivityPath activityPath) {
return new ActivityProgressInformation(activityIdentifier, activityPath, RealizationState.UNKNOWN, null, null);
}

/**
* Prepares the information from a root task. The task may or may not have its children resolved.
*/
public static @NotNull ActivityProgressInformation fromRootTask(@NotNull TaskType task, @NotNull TaskResolver resolver) {
return fromTask(task, ActivityPath.empty(), resolver);
}

public static @NotNull ActivityProgressInformation fromTask(@NotNull TaskType task, @NotNull ActivityPath activityPath,
public static @NotNull ActivityProgressInformation fromRootTask(@NotNull TaskType task,
@NotNull TaskResolver resolver) {
TaskActivityStateType globalState = task.getActivityState();
if (globalState == null) {
return unknown(null, activityPath); // TODO or "no progress"?
}
ActivityStateType rootActivityState = globalState.getActivity();
if (rootActivityState == null) {
return unknown(null, activityPath); // TODO or "no progress"?
}
return fromDelegatableActivityState(rootActivityState, activityPath, task, resolver);
}

private static @NotNull ActivityProgressInformation fromDelegatableActivityState(@NotNull ActivityStateType state,
@NotNull ActivityPath activityPath, @NotNull TaskType task, @NotNull TaskResolver resolver) {
if (ActivityStateUtil.isDelegated(state)) {
return fromDelegatedActivityState(state.getIdentifier(), activityPath, getDelegatedTaskRef(state), task, resolver);
} else {
return fromNotDelegatedActivityState(state, activityPath, task, resolver);
}
}

private static ObjectReferenceType getDelegatedTaskRef(ActivityStateType state) {
AbstractActivityWorkStateType workState = state.getWorkState();
return workState instanceof DelegationWorkStateType ? ((DelegationWorkStateType) workState).getTaskRef() : null;
}

private static @NotNull ActivityProgressInformation fromDelegatedActivityState(String activityIdentifier,
@NotNull ActivityPath activityPath, ObjectReferenceType delegateTaskRef,
@NotNull TaskType task, @NotNull TaskResolver resolver) {
TaskType delegateTask = getSubtask(delegateTaskRef, task, resolver);
if (delegateTask != null) {
return fromTask(delegateTask, activityPath, resolver);
} else {
return unknown(activityIdentifier, activityPath);
}
}

private static TaskType getSubtask(ObjectReferenceType subtaskRef, TaskType task, TaskResolver resolver) {
String subTaskOid = subtaskRef != null ? subtaskRef.getOid() : null;
if (subTaskOid == null) {
return null;
}
TaskType inTask = TaskTreeUtil.findChildIfResolved(task, subTaskOid);
if (inTask != null) {
return inTask;
}
try {
return resolver.resolve(subTaskOid);
} catch (ObjectNotFoundException | SchemaException e) {
LoggingUtils.logException(LOGGER, "Couldn't retrieve subtask {} of {}", e, subTaskOid, task);
return null;
}
}

private static @NotNull ActivityProgressInformation fromNotDelegatedActivityState(@NotNull ActivityStateType state,
@NotNull ActivityPath activityPath, @NotNull TaskType task, @NotNull TaskResolver resolver) {
String identifier = state.getIdentifier();
RealizationState realizationState = getRealizationState(state);
BucketsProgressInformation bucketsProgress = BucketsProgressInformation.fromActivityState(state);
ItemsProgressInformation itemsProgress = getItemsProgress(state, activityPath, task, resolver);

ActivityProgressInformation info
= new ActivityProgressInformation(identifier, activityPath, realizationState, bucketsProgress, itemsProgress);
for (ActivityStateType childState : state.getActivity()) {
info.children.add(
fromDelegatableActivityState(childState, activityPath.append(childState.getIdentifier()), task, resolver));
}
return info;
return fromTask(task, ActivityPath.empty(), resolver);
}

private static ItemsProgressInformation getItemsProgress(@NotNull ActivityStateType state,
@NotNull ActivityPath activityPath, @NotNull TaskType task, @NotNull TaskResolver resolver) {
if (BucketingUtil.isCoordinator(state)) {
return ItemsProgressInformation.fromBucketingCoordinator(state, activityPath, task, resolver);
} else {
return ItemsProgressInformation.fromActivityState(state);
}
public static @NotNull ActivityProgressInformation fromRootTask(@NotNull TaskType task,
@NotNull InformationSource source) {
return ActivityProgressInformationBuilder.fromTask(task, ActivityPath.empty(), TaskResolver.empty(), source);
}

private static RealizationState getRealizationState(ActivityStateType state) {
ActivityRealizationStateType rawState = state.getRealizationState();
if (rawState == null) {
return null;
} else if (rawState == ActivityRealizationStateType.COMPLETE) {
return RealizationState.COMPLETE;
} else {
return RealizationState.IN_PROGRESS;
}
public static @NotNull ActivityProgressInformation fromTask(@NotNull TaskType task, @NotNull ActivityPath activityPath,
@NotNull TaskResolver resolver) {
return ActivityProgressInformationBuilder.fromTask(task, activityPath, resolver, InformationSource.FULL_STATE_ONLY);
}

public String getActivityIdentifier() {
Expand Down Expand Up @@ -272,22 +188,22 @@ private boolean shouldUseBucketForProgressReporting() {
return bucketsProgress.getExpectedBuckets() > 1;
} else {
// We don't know how many buckets to expect. So let's guess according to buckets completed so far.
return bucketsProgress.getCompletedBuckets() > 1;
return bucketsProgress.getCompleteBuckets() > 1;
}
}

private String toHumanReadableStringForBucketed(boolean longForm) {
float percentage = bucketsProgress.getPercentage();
if (Float.isNaN(percentage)) {
if (longForm) {
return bucketsProgress.getCompletedBuckets() + " buckets";
return bucketsProgress.getCompleteBuckets() + " buckets";
} else {
return bucketsProgress.getCompletedBuckets() + " buckets"; // at least temporarily until we find something better
return bucketsProgress.getCompleteBuckets() + " buckets"; // at least temporarily until we find something better
}
}
if (longForm) {
return String.format("%.1f%% (%d of %d buckets)", percentage * 100,
bucketsProgress.getCompletedBuckets(), bucketsProgress.getExpectedBuckets());
bucketsProgress.getCompleteBuckets(), bucketsProgress.getExpectedBuckets());
} else {
return String.format("%.1f%%", percentage * 100);
}
Expand Down Expand Up @@ -384,6 +300,31 @@ public enum RealizationState {
/**
* The state and progress of the activity is unknown. For example, the task it was delegated to is no longer available.
*/
UNKNOWN
UNKNOWN;

static RealizationState fromOverview(ActivitySimplifiedRealizationStateType state) {
if (state == null) {
return null;
}
switch (state) {
case IN_PROGRESS:
return IN_PROGRESS;
case COMPLETE:
return COMPLETE;
default:
throw new AssertionError(state);
}
}

static RealizationState fromFullState(ActivityRealizationStateType state) {
if (state == null) {
return null;
} else if (state == ActivityRealizationStateType.COMPLETE) {
return RealizationState.COMPLETE;
} else {
// Variants of "in progress" (local, delegated, distributed)
return RealizationState.IN_PROGRESS;
}
}
}
}
Loading

0 comments on commit 82c2b72

Please sign in to comment.