/*
* Copyright (c) 2010-2013 Evolveum
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.evolveum.midpoint.web.page.admin.server.dto;
import com.evolveum.midpoint.gui.api.page.PageBase;
import com.evolveum.midpoint.gui.api.util.WebComponentUtil;
import com.evolveum.midpoint.gui.api.util.WebModelServiceUtils;
import com.evolveum.midpoint.model.api.ModelInteractionService;
import com.evolveum.midpoint.model.api.ModelPublicConstants;
import com.evolveum.midpoint.model.api.ModelService;
import com.evolveum.midpoint.model.api.TaskService;
import com.evolveum.midpoint.model.api.context.ModelContext;
import com.evolveum.midpoint.model.api.visualizer.Scene;
import com.evolveum.midpoint.prism.PrismContext;
import com.evolveum.midpoint.prism.PrismProperty;
import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.prism.polystring.PolyString;
import com.evolveum.midpoint.prism.xml.XmlTypeConverter;
import com.evolveum.midpoint.schema.GetOperationOptions;
import com.evolveum.midpoint.schema.ObjectTreeDeltas;
import com.evolveum.midpoint.schema.SelectorOptions;
import com.evolveum.midpoint.schema.constants.ObjectTypes;
import com.evolveum.midpoint.schema.constants.SchemaConstants;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.schema.result.OperationResultStatus;
import com.evolveum.midpoint.task.api.*;
import com.evolveum.midpoint.util.MiscUtil;
import com.evolveum.midpoint.util.exception.*;
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.web.component.data.column.InlineMenuable;
import com.evolveum.midpoint.web.component.menu.cog.InlineMenuItem;
import com.evolveum.midpoint.web.component.model.operationStatus.ModelOperationStatusDto;
import com.evolveum.midpoint.web.component.prism.show.SceneDto;
import com.evolveum.midpoint.web.component.prism.show.SceneUtil;
import com.evolveum.midpoint.web.component.util.Selectable;
import com.evolveum.midpoint.web.page.admin.server.handlers.HandlerDtoFactory;
import com.evolveum.midpoint.web.page.admin.server.handlers.dto.HandlerDto;
import com.evolveum.midpoint.web.page.admin.server.handlers.dto.ResourceRelatedHandlerDto;
import com.evolveum.midpoint.web.page.admin.workflow.dto.ProcessInstanceDto;
import com.evolveum.midpoint.web.page.admin.workflow.dto.WorkItemDto;
import com.evolveum.midpoint.web.security.MidPointApplication;
import com.evolveum.midpoint.wf.api.WorkflowManager;
import com.evolveum.midpoint.wf.util.ApprovalUtils;
import com.evolveum.midpoint.wf.util.ChangesByState;
import com.evolveum.midpoint.xml.ns._public.common.common_3.*;
import com.evolveum.prism.xml.ns._public.query_3.QueryType;
import com.evolveum.prism.xml.ns._public.types_3.ObjectDeltaType;
import org.apache.commons.lang.Validate;
import org.apache.wicket.Application;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.xml.datatype.XMLGregorianCalendar;
import javax.xml.namespace.QName;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import static com.evolveum.midpoint.schema.GetOperationOptions.createRetrieve;
import static com.evolveum.midpoint.schema.SelectorOptions.createCollection;
/**
* @author lazyman
* @author mederly
*/
public class TaskDto extends Selectable implements InlineMenuable {
public static final String CLASS_DOT = TaskDto.class.getName() + ".";
public static final String OPERATION_NEW = CLASS_DOT + "new";
private static final transient Trace LOGGER = TraceManager.getTrace(TaskDto.class);
public static final String F_MODEL_OPERATION_STATUS = "modelOperationStatus";
public static final String F_SUBTASKS = "subtasks";
public static final String F_NAME = "name";
public static final String F_DESCRIPTION = "description";
public static final String F_CATEGORY = "category";
public static final String F_PARENT_TASK_NAME = "parentTaskName";
public static final String F_PARENT_TASK_OID = "parentTaskOid";
public static final String F_OWNER_NAME = "ownerName";
public static final String F_OWNER_OID = "ownerOid";
@Deprecated public static final String F_WORKFLOW_DELTAS_IN = "workflowDeltasIn";
@Deprecated public static final String F_WORKFLOW_DELTAS_OUT = "workflowDeltasOut";
public static final String F_CHANGE_BEING_APPROVED = "changesBeingApproved";
public static final String F_IDENTIFIER = "identifier";
public static final String F_HANDLER_URI_LIST = "handlerUriList";
public static final String F_TASK_OPERATION_RESULT = "taskOperationResult";
public static final String F_PROGRESS_DESCRIPTION = "progressDescription";
public static final String F_WORKER_THREADS = "workerThreads";
public static final String F_OP_RESULT = "opResult";
public static final String F_WORKFLOW_CONTEXT = "workflowContext";
public static final String F_WORK_ITEMS = "workItems";
public static final String F_WORKFLOW_REQUESTS = "workflowRequests";
public static final String F_RECURRING = "recurring";
public static final String F_BOUND = "bound";
public static final String F_INTERVAL = "interval";
public static final String F_CRON_SPECIFICATION = "cronSpecification";
public static final String F_NOT_START_BEFORE = "notStartBefore";
public static final String F_NOT_START_AFTER = "notStartAfter";
public static final String F_MISFIRE_ACTION = "misfireActionType";
public static final String F_OBJECT_REF_NAME = "objectRefName";
public static final String F_OBJECT_TYPE = "objectType";
public static final String F_OBJECT_QUERY = "objectQuery";
public static final String F_OBJECT_DELTA = "objectDelta";
public static final String F_SCRIPT = "script";
public static final String F_EXECUTE_IN_RAW_MODE = "executeInRawMode";
public static final String F_PROCESS_INSTANCE_ID = "processInstanceId";
public static final String F_HANDLER_DTO = "handlerDto";
public static final long RUNS_CONTINUALLY = -1L;
public static final long ALREADY_PASSED = -2L;
public static final long NOW = 0L;
private TaskType taskType;
private TaskEditableState currentEditableState = new TaskEditableState();
private TaskEditableState originalEditableState;
// simple computed properties (optimization)
private List<String> handlerUriList;
private List<OperationResult> opResult;
private OperationResult taskOperationResult;
private ModelOperationStatusDto modelOperationStatusDto;
private List<TaskChangesDto> changesCategorizationList;
private List<ProcessInstanceDto> workflowRequests;
private List<SceneDto> workflowDeltasIn, workflowDeltasOut;
private TaskChangesDto changesBeingApproved;
// related objects
private TaskType parentTaskType;
private ObjectTypes objectRefType;
private String objectRefName;
private ObjectReferenceType objectRef;
private List<TaskDto> subtasks = new ArrayList<>(); // only persistent subtasks are here
private List<TaskDto> transientSubtasks = new ArrayList<>(); // transient ones are here
// other
private List<InlineMenuItem> menuItems;
private HandlerDto handlerDto;
//region Construction
public TaskDto(TaskType taskType, ModelService modelService, TaskService taskService, ModelInteractionService modelInteractionService,
TaskManager taskManager, WorkflowManager workflowManager, TaskDtoProviderOptions options,
Task opTask, OperationResult parentResult, PageBase pageBase) throws SchemaException, ObjectNotFoundException {
Validate.notNull(taskType, "Task must not be null.");
Validate.notNull(modelService);
Validate.notNull(taskService);
Validate.notNull(modelInteractionService);
Validate.notNull(taskManager);
Validate.notNull(parentResult);
Validate.notNull(pageBase);
this.taskType = taskType;
this.currentEditableState.name = taskType.getName() != null ? taskType.getName().getOrig() : null;
this.currentEditableState.description = taskType.getDescription();
fillInScheduleAttributes(taskType);
OperationResult thisOpResult = parentResult.createMinorSubresult(OPERATION_NEW);
fillInHandlerUriList(taskType);
fillInObjectRefAttributes(taskType, options, pageBase, opTask, thisOpResult);
fillInParentTaskAttributes(taskType, taskService, options, thisOpResult);
fillInOperationResultAttributes(taskType);
if (options.isRetrieveModelContext()) {
fillInModelContext(taskType, modelInteractionService, opTask, thisOpResult);
}
if (options.isRetrieveWorkflowContext()) {
// TODO fill-in "cheap" wf attributes not only when this option is set
fillInWorkflowAttributes(taskType, modelInteractionService, workflowManager, pageBase.getPrismContext(), opTask, thisOpResult);
}
thisOpResult.computeStatusIfUnknown();
fillFromExtension();
for (TaskType child : taskType.getSubtask()) {
addChildTaskDto(new TaskDto(child, modelService, taskService, modelInteractionService, taskManager,
workflowManager, options, opTask, parentResult, pageBase));
}
if (options.isCreateHandlerDto()) {
handlerDto = HandlerDtoFactory.instance().createDtoForTask(this, pageBase, opTask, thisOpResult);
} else {
handlerDto = new HandlerDto(this); // just to avoid NPEs
}
currentEditableState.handlerSpecificState = handlerDto.getEditableState();
originalEditableState = currentEditableState.clone();
}
@Override
public List<InlineMenuItem> getMenuItems() {
if (menuItems == null) {
menuItems = new ArrayList<>();
}
return menuItems;
}
private void fillFromExtension() {
PrismProperty<Integer> workerThreadsItem = getExtensionProperty(SchemaConstants.MODEL_EXTENSION_WORKER_THREADS);
if (workerThreadsItem != null) {
currentEditableState.workerThreads = workerThreadsItem.getRealValue();
}
}
private Long xgc2long(XMLGregorianCalendar gc) {
return gc != null ? XmlTypeConverter.toMillis(gc) : null;
}
private void fillInHandlerUriList(TaskType taskType) {
handlerUriList = new ArrayList<>();
if (taskType.getHandlerUri() != null) {
handlerUriList.add(taskType.getHandlerUri());
} else {
handlerUriList.add("-"); // todo separate presentation from model
}
if (taskType.getOtherHandlersUriStack() != null) {
List<UriStackEntry> stack = taskType.getOtherHandlersUriStack().getUriStackEntry();
for (int i = stack.size()-1; i >= 0; i--) {
handlerUriList.add(stack.get(i).getHandlerUri());
}
}
}
private void fillInScheduleAttributes(TaskType taskType) {
this.currentEditableState.recurring = taskType.getRecurrence() == TaskRecurrenceType.RECURRING;
this.currentEditableState.bound = taskType.getBinding() == TaskBindingType.TIGHT;
this.currentEditableState.threadStopActionType = taskType.getThreadStopAction();
if (taskType.getSchedule() != null) {
currentEditableState.interval = taskType.getSchedule().getInterval();
currentEditableState.cronSpecification = taskType.getSchedule().getCronLikePattern();
if (taskType.getSchedule().getMisfireAction() == null){
currentEditableState.misfireActionType = MisfireActionType.EXECUTE_IMMEDIATELY;
} else {
currentEditableState.misfireActionType = taskType.getSchedule().getMisfireAction();
}
currentEditableState.notStartBefore = MiscUtil.asDate(taskType.getSchedule().getEarliestStartTime());
currentEditableState.notStartAfter = MiscUtil.asDate(taskType.getSchedule().getLatestStartTime());
}
}
private void fillInObjectRefAttributes(TaskType taskType, TaskDtoProviderOptions options, PageBase pageBase, Task opTask, OperationResult thisOpResult) {
if (taskType.getObjectRef() != null) {
if (taskType.getObjectRef().getType() != null) {
this.objectRefType = ObjectTypes.getObjectTypeFromTypeQName(taskType.getObjectRef().getType());
}
if (options.isResolveObjectRef()) {
this.objectRefName = getTaskObjectName(taskType, pageBase, opTask, thisOpResult);
}
this.objectRef = taskType.getObjectRef();
}
}
public String getTaskObjectName(TaskType taskType, PageBase pageBase, Task opTask, OperationResult thisOpResult) {
return WebModelServiceUtils.resolveReferenceName(taskType.getObjectRef(), pageBase, opTask, thisOpResult);
}
private void fillInParentTaskAttributes(TaskType taskType, TaskService taskService, TaskDtoProviderOptions options, OperationResult thisOpResult) {
if (options.isGetTaskParent() && taskType.getParent() != null) {
try {
Collection<SelectorOptions<GetOperationOptions>> getOptions =
options.isRetrieveSiblings() ? createCollection(TaskType.F_SUBTASK, createRetrieve()) : null;
parentTaskType = taskService.getTaskByIdentifier(taskType.getParent(), getOptions, thisOpResult).asObjectable();
} catch (SchemaException|ObjectNotFoundException|SecurityViolationException|ConfigurationException e) {
LoggingUtils.logUnexpectedException(LOGGER, "Couldn't retrieve parent task for task {}", e, taskType.getOid());
}
}
}
private void fillInOperationResultAttributes(TaskType taskType) {
opResult = new ArrayList<OperationResult>();
if (taskType.getResult() != null) {
taskOperationResult = OperationResult.createOperationResult(taskType.getResult());
opResult.add(taskOperationResult);
opResult.addAll(taskOperationResult.getSubresults());
}
}
private void fillInModelContext(TaskType taskType, ModelInteractionService modelInteractionService, Task opTask, OperationResult result) throws ObjectNotFoundException {
ModelContext ctx = unwrapModelContext(taskType, modelInteractionService, opTask, result);
if (ctx != null) {
modelOperationStatusDto = new ModelOperationStatusDto(ctx, modelInteractionService, opTask, result);
}
}
private ModelContext unwrapModelContext(TaskType taskType, ModelInteractionService modelInteractionService, Task opTask, OperationResult result) throws ObjectNotFoundException {
LensContextType lensContextType = taskType.getModelOperationContext();
if (lensContextType != null) {
try {
return modelInteractionService.unwrapModelContext(lensContextType, result);
} catch (SchemaException | CommunicationException | ConfigurationException e) { // todo treat appropriately
throw new SystemException("Couldn't access model operation context in task: " + e.getMessage(), e);
}
} else {
return null;
}
}
private void fillInWorkflowAttributes(TaskType taskType, ModelInteractionService modelInteractionService, WorkflowManager workflowManager,
PrismContext prismContext, Task opTask,
OperationResult thisOpResult) throws SchemaException, ObjectNotFoundException {
workflowDeltasIn = retrieveDeltasToProcess(taskType, modelInteractionService, opTask, thisOpResult);
workflowDeltasOut = retrieveResultingDeltas(taskType, modelInteractionService, opTask, thisOpResult);
final TaskType rootTask;
if (parentTaskType == null) {
rootTask = taskType;
} else {
rootTask = parentTaskType;
}
WfContextType wfc = taskType.getWorkflowContext();
if (wfc != null && parentTaskType != null && (wfc.getProcessorSpecificState() instanceof WfPrimaryChangeProcessorStateType)) {
ChangesByState changesByState = workflowManager.getChangesByState(taskType, rootTask, modelInteractionService, prismContext, thisOpResult);
List<TaskChangesDto> changeCategories = computeChangesCategorizationList(changesByState, modelInteractionService, prismContext, opTask, thisOpResult);
if (changeCategories.size() > 1) {
throw new IllegalStateException("More than one task change category for task " + taskType + ": " + changeCategories);
} else if (changeCategories.size() == 1) {
changesBeingApproved = changeCategories.get(0);
}
}
workflowRequests = new ArrayList<>();
for (TaskType wfSubtask : rootTask.getSubtask()) {
final WfContextType subWfc = wfSubtask.getWorkflowContext();
if (subWfc != null && subWfc.getProcessInstanceId() != null) {
if (this.getOid() == null || !this.getOid().equals(wfSubtask.getOid())) {
workflowRequests.add(new ProcessInstanceDto(wfSubtask));
}
}
}
ChangesByState changesByState = workflowManager.getChangesByState(rootTask, modelInteractionService, prismContext, thisOpResult);
this.changesCategorizationList = computeChangesCategorizationList(changesByState, modelInteractionService, prismContext, opTask, thisOpResult);
}
@NotNull
private List<TaskChangesDto> computeChangesCategorizationList(ChangesByState changesByState, ModelInteractionService modelInteractionService,
PrismContext prismContext, Task opTask,
OperationResult thisOpResult) throws SchemaException {
List<TaskChangesDto> changes = new ArrayList<>();
if (!changesByState.getApplied().isEmpty()) {
changes.add(createTaskChangesDto("TaskDto.changesApplied", "box-solid box-success", changesByState.getApplied(), modelInteractionService, prismContext, opTask, thisOpResult));
}
if (!changesByState.getBeingApplied().isEmpty()) {
changes.add(createTaskChangesDto("TaskDto.changesBeingApplied", "box-solid box-info", changesByState.getBeingApplied(), modelInteractionService, prismContext, opTask, thisOpResult));
}
if (!changesByState.getWaitingToBeApplied().isEmpty()) {
changes.add(createTaskChangesDto("TaskDto.changesWaitingToBeApplied", "box-solid box-warning", changesByState.getWaitingToBeApplied(), modelInteractionService, prismContext, opTask, thisOpResult));
}
if (!changesByState.getWaitingToBeApproved().isEmpty()) {
changes.add(createChangesToBeApproved(changesByState.getWaitingToBeApproved(), modelInteractionService, prismContext, opTask, thisOpResult));
}
if (!changesByState.getRejected().isEmpty()) {
changes.add(createTaskChangesDto("TaskDto.changesRejected", "box-solid box-danger", changesByState.getRejected(), modelInteractionService, prismContext, opTask, thisOpResult));
}
if (!changesByState.getCanceled().isEmpty()) {
changes.add(createTaskChangesDto("TaskDto.changesCanceled", "box-solid box-danger", changesByState.getCanceled(), modelInteractionService, prismContext, opTask, thisOpResult));
}
return changes;
}
public static TaskChangesDto createChangesToBeApproved(ObjectTreeDeltas<?> deltas, ModelInteractionService modelInteractionService,
PrismContext prismContext, Task opTask, OperationResult thisOpResult) throws SchemaException {
return createTaskChangesDto("TaskDto.changesWaitingToBeApproved", "box-solid box-primary", deltas, modelInteractionService, prismContext, opTask, thisOpResult);
}
private static TaskChangesDto createTaskChangesDto(String titleKey, String boxClassOverride, ObjectTreeDeltas deltas, ModelInteractionService modelInteractionService,
PrismContext prismContext, Task opTask, OperationResult result) throws SchemaException {
ObjectTreeDeltasType deltasType = ObjectTreeDeltas.toObjectTreeDeltasType(deltas);
Scene scene = SceneUtil.visualizeObjectTreeDeltas(deltasType, titleKey, prismContext, modelInteractionService, opTask, result);
SceneDto sceneDto = new SceneDto(scene);
sceneDto.setBoxClassOverride(boxClassOverride);
return new TaskChangesDto(sceneDto);
}
private List<SceneDto> retrieveDeltasToProcess(TaskType taskType, ModelInteractionService modelInteractionService, Task opTask,
OperationResult thisOpResult) throws SchemaException {
WfContextType wfc = taskType.getWorkflowContext();
if (wfc == null || !(wfc.getProcessorSpecificState() instanceof WfPrimaryChangeProcessorStateType)) {
return null;
}
WfPrimaryChangeProcessorStateType pcps = (WfPrimaryChangeProcessorStateType) wfc.getProcessorSpecificState();
return objectTreeDeltasToDeltaDtoList(pcps.getDeltasToProcess(), taskType.asPrismObject().getPrismContext(), modelInteractionService, opTask, thisOpResult);
}
private SceneDto retrieveDeltaToProcess(TaskType taskType, ModelInteractionService modelInteractionService, Task opTask,
OperationResult thisOpResult) throws SchemaException {
WfContextType wfc = taskType.getWorkflowContext();
if (wfc == null || !(wfc.getProcessorSpecificState() instanceof WfPrimaryChangeProcessorStateType)) {
return null;
}
WfPrimaryChangeProcessorStateType pcps = (WfPrimaryChangeProcessorStateType) wfc.getProcessorSpecificState();
Scene scene = SceneUtil.visualizeObjectTreeDeltas(pcps.getDeltasToProcess(), "", taskType.asPrismObject().getPrismContext(),
modelInteractionService, opTask, thisOpResult);
return new SceneDto(scene);
}
private List<SceneDto> objectTreeDeltasToDeltaDtoList(ObjectTreeDeltasType deltas, PrismContext prismContext,
ModelInteractionService modelInteractionService, Task opTask, OperationResult thisOpResult) throws SchemaException {
List<SceneDto> retval = new ArrayList<>();
if (deltas == null) {
return retval;
}
Scene wrapperScene = SceneUtil.visualizeObjectTreeDeltas(deltas, "", prismContext, modelInteractionService, opTask, thisOpResult);
for (Scene scene : wrapperScene.getPartialScenes()) {
retval.add(new SceneDto(scene));
}
return retval;
}
private List<SceneDto> retrieveResultingDeltas(TaskType taskType, ModelInteractionService modelInteractionService, Task opTask,
OperationResult thisOpResult) throws SchemaException {
WfContextType wfc = taskType.getWorkflowContext();
if (wfc == null || !(wfc.getProcessorSpecificState() instanceof WfPrimaryChangeProcessorStateType)) {
return null;
}
WfPrimaryChangeProcessorStateType pcps = (WfPrimaryChangeProcessorStateType) wfc.getProcessorSpecificState();
return objectTreeDeltasToDeltaDtoList(pcps.getResultingDeltas(), taskType.asPrismObject().getPrismContext(), modelInteractionService, opTask,
thisOpResult);
}
//endregion
//region Getters and setters for read-write properties
public String getName() {
return currentEditableState.name;
}
public void setName(String name) {
this.currentEditableState.name = name;
}
public String getDescription() {
return currentEditableState.description;
}
public void setDescription(String description) {
this.currentEditableState.description = description;
}
public boolean isRecurring() {
return currentEditableState.recurring;
}
public void setRecurring(boolean recurring) {
this.currentEditableState.recurring = recurring;
}
public boolean isBound() {
return currentEditableState.bound;
}
public void setBound(boolean bound) {
this.currentEditableState.bound = bound;
}
public Integer getInterval() {
return currentEditableState.interval;
}
public void setInterval(Integer interval) {
this.currentEditableState.interval = interval;
}
public String getCronSpecification() {
return currentEditableState.cronSpecification;
}
public void setCronSpecification(String cronSpecification) {
this.currentEditableState.cronSpecification = cronSpecification;
}
public Date getNotStartBefore() {
return currentEditableState.notStartBefore;
}
public void setNotStartBefore(Date notStartBefore) {
this.currentEditableState.notStartBefore = notStartBefore;
}
public Date getNotStartAfter() {
return currentEditableState.notStartAfter;
}
public void setNotStartAfter(Date notStartAfter) {
this.currentEditableState.notStartAfter = notStartAfter;
}
public MisfireActionType getMisfireActionType() {
return currentEditableState.misfireActionType;
}
public void setMisfireActionType(MisfireActionType misfireActionType) {
this.currentEditableState.misfireActionType = misfireActionType;
}
public ThreadStopActionType getThreadStopActionType() {
return currentEditableState.threadStopActionType;
}
public void setThreadStopActionType(ThreadStopActionType threadStopActionType) {
this.currentEditableState.threadStopActionType = threadStopActionType;
}
public String getObjectRefName() {
return objectRefName;
}
public ObjectTypes getObjectRefType() {
return objectRefType;
}
public ObjectReferenceType getObjectRef() {
return objectRef;
}
// should contain the name
public void setObjectRef(@Nullable ObjectReferenceType objectRef) {
this.objectRef = objectRef;
if (objectRef != null) {
this.objectRefName = PolyString.getOrig(objectRef.getTargetName());
this.objectRefType = ObjectTypes.getObjectTypeFromTypeQName(objectRef.getType());
} else {
this.objectRefName = null;
this.objectRefType = null;
}
}
public Integer getWorkerThreads() { return currentEditableState.workerThreads; }
public void setWorkerThreads(Integer workerThreads) {
this.currentEditableState.workerThreads = workerThreads;
}
//endregion
//region Getters for read-only properties
public String getCategory() {
return taskType.getCategory();
}
public List<String> getHandlerUriList() {
return handlerUriList;
}
public Long getCurrentRuntime() {
if (isRunNotFinished()) {
if (isAliveClusterwide()) {
return System.currentTimeMillis() - getLastRunStartTimestampLong();
}
}
return null;
}
public TaskDtoExecutionStatus getExecution() {
return TaskDtoExecutionStatus.fromTaskExecutionStatus(taskType.getExecutionStatus(), taskType.getNodeAsObserved() != null);
}
public String getExecutingAt() {
return taskType.getNodeAsObserved();
}
public Long getProgress() {
return taskType.getProgress();
}
public Long getExpectedTotal() {
return taskType.getExpectedTotal();
}
public String getProgressDescription() {
return getProgressDescription(taskType.getProgress());
}
public String getProgressDescription(Long currentProgress) {
if (currentProgress == null && taskType.getExpectedTotal() == null) {
return ""; // the task handler probably does not report progress at all
} else {
StringBuilder sb = new StringBuilder();
if (currentProgress != null){
sb.append(currentProgress);
} else {
sb.append("0");
}
if (taskType.getExpectedTotal() != null) {
sb.append("/").append(taskType.getExpectedTotal());
}
return sb.toString();
}
}
public List<OperationResult> getResult() {
return opResult;
}
public Long getLastRunStartTimestampLong() {
return xgc2long(taskType.getLastRunStartTimestamp());
}
public Long getLastRunFinishTimestampLong() {
return xgc2long(taskType.getLastRunFinishTimestamp());
}
public String getOid() {
return taskType.getOid();
}
public String getIdentifier() {
return taskType.getTaskIdentifier();
}
public Long getNextRunStartTimeLong() {
return xgc2long(taskType.getNextRunStartTimestamp());
}
public Long getNextRetryTimeLong() {
return xgc2long(taskType.getNextRetryTimestamp());
}
public Long getRetryAfter() {
Long retryAt = getNextRetryTimeLong();
return retryAt != null ? retryAt - System.currentTimeMillis() : null;
}
public Long getScheduledToStartAgain() {
long current = System.currentTimeMillis();
if (getExecution() == TaskDtoExecutionStatus.RUNNING) {
if (!currentEditableState.recurring) {
return null;
} else if (currentEditableState.bound) {
return RUNS_CONTINUALLY; // runs continually; todo provide some information also in this case
}
}
Long nextRunStartTimeLong = getNextRunStartTimeLong();
if (nextRunStartTimeLong == null || nextRunStartTimeLong == 0) {
return null;
}
if (nextRunStartTimeLong > current + 1000) {
return nextRunStartTimeLong - System.currentTimeMillis();
} else if (nextRunStartTimeLong < current - 60000) {
return ALREADY_PASSED;
} else {
return NOW;
}
}
public OperationResultStatus getStatus() {
return taskOperationResult != null ? taskOperationResult.getStatus() : null;
}
private boolean isRunNotFinished() {
final Long lastRunStartTimestampLong = getLastRunStartTimestampLong();
final Long lastRunFinishTimestampLong = getLastRunFinishTimestampLong();
return lastRunStartTimestampLong != null &&
(lastRunFinishTimestampLong == null || lastRunStartTimestampLong > lastRunFinishTimestampLong);
}
private boolean isAliveClusterwide() {
return getExecutingAt() != null;
}
public TaskExecutionStatus getRawExecutionStatus() {
return TaskExecutionStatus.fromTaskType(taskType.getExecutionStatus());
}
public List<OperationResult> getOpResult() {
return opResult;
}
public Long getCompletionTimestamp() {
return xgc2long(taskType.getCompletionTimestamp());
}
public ModelOperationStatusDto getModelOperationStatus() {
return modelOperationStatusDto;
}
public TaskChangesDto getChangesForIndex(int index) {
int realIndex = index-1;
return realIndex < changesCategorizationList.size() ? changesCategorizationList.get(realIndex) : null;
}
public List<TaskChangesDto> getChangesCategorizationList() {
return changesCategorizationList;
}
public void addChildTaskDto(TaskDto taskDto) {
if (taskDto.getOid() != null) {
subtasks.add(taskDto);
} else {
transientSubtasks.add(taskDto);
}
}
public List<TaskDto> getSubtasks() {
return subtasks;
}
public List<TaskDto> getTransientSubtasks() {
return transientSubtasks;
}
public String getWorkflowProcessInstanceId() {
return taskType.getWorkflowContext() != null ? taskType.getWorkflowContext().getProcessInstanceId() : null;
}
public boolean isWorkflowProcessInstanceFinished() {
return taskType.getWorkflowContext() != null ?
taskType.getWorkflowContext().getEndTimestamp() != null : false;
}
@Deprecated
public List<SceneDto> getWorkflowDeltasIn() {
return workflowDeltasIn;
}
public TaskChangesDto getChangesBeingApproved() {
return changesBeingApproved;
}
@Deprecated
public List<SceneDto> getWorkflowDeltasOut() {
return workflowDeltasOut;
}
public String getParentTaskName() {
return parentTaskType != null ? WebComponentUtil.getName(parentTaskType.asPrismObject()) : null;
}
public String getParentTaskOid() {
return parentTaskType != null ? parentTaskType.getOid() : null;
}
public OperationResult getTaskOperationResult() {
return taskOperationResult;
}
public PrismProperty getExtensionProperty(QName propertyName) {
return taskType.asPrismObject().findProperty(new ItemPath(TaskType.F_EXTENSION, propertyName));
}
public <T> T getExtensionPropertyRealValue(QName propertyName, Class<T> clazz) {
PrismProperty<T> property = taskType.asPrismObject().findProperty(new ItemPath(TaskType.F_EXTENSION, propertyName));
return property != null ? property.getRealValue() : null;
}
public Long getStalledSince() {
return xgc2long(taskType.getStalledSince());
}
public TaskType getTaskType() {
return taskType;
}
public WfContextType getWorkflowContext() {
return taskType.getWorkflowContext();
}
public List<WorkItemDto> getWorkItems() {
List<WorkItemDto> rv = new ArrayList<>();
if (taskType.getWorkflowContext() != null) {
for (WorkItemType workItemType : taskType.getWorkflowContext().getWorkItem()) {
rv.add(new WorkItemDto(workItemType));
}
}
return rv;
}
public List<ProcessInstanceDto> getWorkflowRequests() {
return workflowRequests;
}
public String getObjectType() {
QName type = getExtensionPropertyRealValue(SchemaConstants.MODEL_EXTENSION_OBJECT_TYPE, QName.class);
return type != null ? type.getLocalPart() : null;
}
public String getObjectQuery() {
QueryType queryType = getExtensionPropertyRealValue(SchemaConstants.MODEL_EXTENSION_OBJECT_QUERY, QueryType.class);
PrismContext prismContext = ((MidPointApplication) Application.get()).getPrismContext();
try {
return prismContext.xmlSerializer().serializeAnyData(queryType, SchemaConstants.MODEL_EXTENSION_OBJECT_QUERY);
} catch (SchemaException e) {
throw new SystemException("Couldn't serialize query: " + e.getMessage(), e);
}
}
public String getObjectDelta() {
ObjectDeltaType objectDeltaType = getExtensionPropertyRealValue(SchemaConstants.MODEL_EXTENSION_OBJECT_DELTA, ObjectDeltaType.class);
PrismContext prismContext = ((MidPointApplication) Application.get()).getPrismContext();
try {
return prismContext.xmlSerializer().serializeAnyData(objectDeltaType, SchemaConstants.MODEL_EXTENSION_OBJECT_DELTA);
} catch (SchemaException e) {
throw new SystemException("Couldn't serialize delta: " + e.getMessage(), e);
}
}
public String getProcessInstanceId() {
WfContextType wfc = getWorkflowContext();
return wfc != null ? wfc.getProcessInstanceId() : null;
}
public Boolean isExecuteInRawMode() {
return getExtensionPropertyRealValue(SchemaConstants.MODEL_EXTENSION_OPTION_RAW, Boolean.class);
}
public String getRequestedBy() {
WfContextType wfc = getWorkflowContext();
return wfc != null ? WebComponentUtil.getName(wfc.getRequesterRef()) : null;
}
public Date getRequestedOn() {
WfContextType wfc = getWorkflowContext();
return wfc != null ? XmlTypeConverter.toDate(wfc.getStartTimestamp()) : null;
}
public Boolean getWorkflowOutcome() {
WfContextType wfc = getWorkflowContext();
return wfc != null ? ApprovalUtils.approvalBooleanValueFromUri(wfc.getOutcome()) : null;
}
public String getOwnerOid() {
return taskType.getOwnerRef() != null ? taskType.getOwnerRef().getOid() : null;
}
public String getOwnerName() {
return WebComponentUtil.getName(taskType.getOwnerRef());
}
public HandlerDto getHandlerDto() {
return handlerDto;
}
//endregion
public static List<String> getOids(List<TaskDto> taskDtoList) {
List<String> retval = new ArrayList<>();
for (TaskDto taskDto : taskDtoList) {
retval.add(taskDto.getOid());
}
return retval;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
TaskDto taskDto = (TaskDto) o;
if (taskType != null ? !taskType.equals(taskDto.taskType) : taskDto.taskType != null)
return false;
if (currentEditableState != null ? !currentEditableState.equals(taskDto.currentEditableState) : taskDto.currentEditableState != null)
return false;
if (originalEditableState != null ? !originalEditableState.equals(taskDto.originalEditableState) : taskDto.originalEditableState != null)
return false;
if (handlerUriList != null ? !handlerUriList.equals(taskDto.handlerUriList) : taskDto.handlerUriList != null)
return false;
if (opResult != null ? !opResult.equals(taskDto.opResult) : taskDto.opResult != null)
return false;
if (taskOperationResult != null ? !taskOperationResult.equals(taskDto.taskOperationResult) : taskDto.taskOperationResult != null)
return false;
if (modelOperationStatusDto != null ?
!modelOperationStatusDto.equals(taskDto.modelOperationStatusDto) :
taskDto.modelOperationStatusDto != null)
return false;
if (changesCategorizationList != null ?
!changesCategorizationList.equals(taskDto.changesCategorizationList) :
taskDto.changesCategorizationList != null)
return false;
if (workflowRequests != null ? !workflowRequests.equals(taskDto.workflowRequests) : taskDto.workflowRequests != null)
return false;
if (workflowDeltasIn != null ? !workflowDeltasIn.equals(taskDto.workflowDeltasIn) : taskDto.workflowDeltasIn != null)
return false;
if (workflowDeltasOut != null ? !workflowDeltasOut.equals(taskDto.workflowDeltasOut) : taskDto.workflowDeltasOut != null)
return false;
if (changesBeingApproved != null ? !changesBeingApproved.equals(taskDto.changesBeingApproved) : taskDto.changesBeingApproved != null)
return false;
if (parentTaskType != null ? !parentTaskType.equals(taskDto.parentTaskType) : taskDto.parentTaskType != null)
return false;
if (objectRefType != taskDto.objectRefType)
return false;
if (objectRefName != null ? !objectRefName.equals(taskDto.objectRefName) : taskDto.objectRefName != null)
return false;
if (objectRef != null ? !objectRef.equals(taskDto.objectRef) : taskDto.objectRef != null)
return false;
if (subtasks != null ? !subtasks.equals(taskDto.subtasks) : taskDto.subtasks != null)
return false;
if (transientSubtasks != null ? !transientSubtasks.equals(taskDto.transientSubtasks) : taskDto.transientSubtasks != null)
return false;
if (menuItems != null ? !menuItems.equals(taskDto.menuItems) : taskDto.menuItems != null)
return false;
return handlerDto != null ? handlerDto.equals(taskDto.handlerDto) : taskDto.handlerDto == null;
}
@Override
public int hashCode() {
int result = taskType != null ? taskType.hashCode() : 0;
result = 31 * result + (currentEditableState != null ? currentEditableState.hashCode() : 0);
result = 31 * result + (originalEditableState != null ? originalEditableState.hashCode() : 0);
result = 31 * result + (handlerUriList != null ? handlerUriList.hashCode() : 0);
result = 31 * result + (opResult != null ? opResult.hashCode() : 0);
result = 31 * result + (taskOperationResult != null ? taskOperationResult.hashCode() : 0);
result = 31 * result + (modelOperationStatusDto != null ? modelOperationStatusDto.hashCode() : 0);
result = 31 * result + (changesCategorizationList != null ? changesCategorizationList.hashCode() : 0);
result = 31 * result + (workflowRequests != null ? workflowRequests.hashCode() : 0);
result = 31 * result + (workflowDeltasIn != null ? workflowDeltasIn.hashCode() : 0);
result = 31 * result + (workflowDeltasOut != null ? workflowDeltasOut.hashCode() : 0);
result = 31 * result + (changesBeingApproved != null ? changesBeingApproved.hashCode() : 0);
result = 31 * result + (parentTaskType != null ? parentTaskType.hashCode() : 0);
result = 31 * result + (objectRefType != null ? objectRefType.hashCode() : 0);
result = 31 * result + (objectRefName != null ? objectRefName.hashCode() : 0);
result = 31 * result + (objectRef != null ? objectRef.hashCode() : 0);
result = 31 * result + (subtasks != null ? subtasks.hashCode() : 0);
result = 31 * result + (transientSubtasks != null ? transientSubtasks.hashCode() : 0);
result = 31 * result + (menuItems != null ? menuItems.hashCode() : 0);
result = 31 * result + (handlerDto != null ? handlerDto.hashCode() : 0);
return result;
}
@Override
public String toString() {
return "TaskDto{" +
"taskType=" + taskType +
'}';
}
public boolean isRunnableOrRunning() {
TaskDtoExecutionStatus exec = getExecution();
return exec == TaskDtoExecutionStatus.RUNNABLE || exec == TaskDtoExecutionStatus.RUNNING;
}
public boolean isRunnable() {
return getExecution() == TaskDtoExecutionStatus.RUNNABLE;
}
public boolean isRunning() {
return getExecution() == TaskDtoExecutionStatus.RUNNING;
}
public boolean isClosed() {
return getExecution() == TaskDtoExecutionStatus.CLOSED;
}
public boolean isWaiting() {
return getExecution() == TaskDtoExecutionStatus.WAITING;
}
public boolean isSuspended() {
return getExecution() == TaskDtoExecutionStatus.SUSPENDED;
}
public boolean isReconciliation() {
return TaskCategory.RECONCILIATION.equals(getCategory());
}
public boolean isImportAccounts() {
return TaskCategory.IMPORTING_ACCOUNTS.equals(getCategory());
}
public boolean isRecomputation() {
return TaskCategory.RECOMPUTATION.equals(getCategory());
}
public boolean isExecuteChanges() {
return TaskCategory.EXECUTE_CHANGES.equals(getCategory());
}
public boolean isWorkflowCategory() {
return TaskCategory.WORKFLOW.equals(getCategory());
}
public boolean isWorkflowChild() {
return isWorkflowCategory() && getWorkflowContext() != null && getWorkflowContext().getProcessInstanceId() != null;
}
public boolean isWorkflowParent() {
return isWorkflowCategory() && getParentTaskOid() == null;
}
public boolean isWorkflow() {
return isWorkflowChild() || isWorkflowParent(); // "task0" is not among these
}
public boolean isLiveSync() {
return TaskCategory.LIVE_SYNCHRONIZATION.equals(getCategory());
}
public boolean isShadowIntegrityCheck() {
return getHandlerUriList().contains(ModelPublicConstants.SHADOW_INTEGRITY_CHECK_TASK_HANDLER_URI);
}
public boolean isFocusValidityScanner() {
return getHandlerUriList().contains(ModelPublicConstants.FOCUS_VALIDITY_SCANNER_TASK_HANDLER_URI);
}
public boolean isJdbcPing() {
return getHandlerUriList().contains(TaskConstants.JDBC_PING_HANDLER_URI);
}
public boolean isTriggerScanner() {
return getHandlerUriList().contains(ModelPublicConstants.TRIGGER_SCANNER_TASK_HANDLER_URI);
}
public boolean isDelete() {
return getHandlerUriList().contains(ModelPublicConstants.DELETE_TASK_HANDLER_URI);
}
public boolean isBulkAction() {
return TaskCategory.BULK_ACTIONS.equals(getCategory());
}
public boolean isReportCreate() {
return TaskCategory.REPORT.equals(getCategory());
}
public boolean configuresWorkerThreads() {
return isReconciliation() || isImportAccounts() || isRecomputation() || isExecuteChanges() || isShadowIntegrityCheck() || isFocusValidityScanner() || isTriggerScanner();
}
public boolean configuresWorkToDo() {
return isLiveSync() || isReconciliation() || isImportAccounts() || isRecomputation() || isExecuteChanges() || isBulkAction() || isDelete() || isShadowIntegrityCheck();
}
public boolean configuresResourceCoordinates() {
return isLiveSync() || isReconciliation() || isImportAccounts();
}
public boolean configuresObjectType() {
return isRecomputation() || isExecuteChanges() || isDelete();
}
public boolean configuresObjectQuery() {
return isRecomputation() || isExecuteChanges() || isDelete() || isShadowIntegrityCheck();
}
public boolean configuresObjectDelta() {
return isExecuteChanges();
}
public boolean configuresScript() {
return isBulkAction();
}
public boolean configuresDryRun() {
return isLiveSync() || isReconciliation() || isImportAccounts() || isShadowIntegrityCheck();
}
public boolean configuresExecuteInRawMode() {
return isExecuteChanges();
}
// quite a hack (TODO think about this)
public boolean isDryRun() {
if (handlerDto instanceof ResourceRelatedHandlerDto) {
return ((ResourceRelatedHandlerDto) handlerDto).isDryRun();
} else {
return false;
}
}
public boolean isCleanup() {
return ModelPublicConstants.CLEANUP_TASK_HANDLER_URI.equals(taskType.getHandlerUri());
}
public boolean isNoOp() { // temporary implementation
return TaskCategory.DEMO.equals(getCategory());
}
public TaskEditableState getCurrentEditableState() {
return currentEditableState;
}
public TaskEditableState getOriginalEditableState() {
return originalEditableState;
}
}