/* * 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.wf.impl.processors.primary; import com.evolveum.midpoint.model.api.context.ModelProjectionContext; import com.evolveum.midpoint.model.impl.lens.LensContext; import com.evolveum.midpoint.model.impl.lens.LensFocusContext; import com.evolveum.midpoint.prism.delta.ObjectDelta; import com.evolveum.midpoint.schema.ObjectTreeDeltas; import com.evolveum.midpoint.schema.ResourceShadowDiscriminator; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.task.api.*; import com.evolveum.midpoint.task.api.TaskRunResult.TaskRunResultStatus; 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.wf.impl.tasks.WfTask; import com.evolveum.midpoint.wf.impl.tasks.WfTaskController; import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; import java.util.List; import java.util.Map; import java.util.Set; /** * This handler takes all changes from child tasks and puts them into model context of this task. * * @author mederly */ @Component public class WfPrepareRootOperationTaskHandler implements TaskHandler { public static final String HANDLER_URI = "http://midpoint.evolveum.com/xml/ns/public/workflow/prepare-root-operation/handler-3"; private static final Trace LOGGER = TraceManager.getTrace(WfPrepareRootOperationTaskHandler.class); //region Spring dependencies and initialization @Autowired private TaskManager taskManager; @Autowired private WfTaskController wfTaskController; @PostConstruct public void init() { LOGGER.trace("Registering with taskManager as a handler for " + HANDLER_URI); taskManager.registerHandler(HANDLER_URI, this); } //endregion //region run method @Override public TaskRunResult run(Task task) { TaskRunResultStatus status = TaskRunResultStatus.FINISHED; try { OperationResult result = task.getResult(); WfTask rootWfTask = wfTaskController.recreateRootWfTask(task); List<WfTask> children = rootWfTask.listChildren(result); LensContext rootContext = (LensContext) rootWfTask.retrieveModelContext(result); boolean changed = false; for (WfTask child : children) { if (child.getTaskExecutionStatus() != TaskExecutionStatus.CLOSED) { throw new IllegalStateException("Child task " + child + " is not in CLOSED state; its state is " + child.getTaskExecutionStatus()); } if (child.hasModelContext()) { if (LOGGER.isTraceEnabled()) { LOGGER.trace("Child job {} has model context present - skipping fetching deltas from it.", child); } } else { ObjectTreeDeltas deltas = child.retrieveResultingDeltas(); if (LOGGER.isTraceEnabled()) { LOGGER.trace("Child job {} returned {} deltas", child, deltas != null ? deltas.getDeltaList().size() : 0); } if (deltas != null) { LensFocusContext focusContext = rootContext.getFocusContext(); ObjectDelta focusDelta = deltas.getFocusChange(); if (focusDelta != null) { if (LOGGER.isTraceEnabled()) { LOGGER.trace("Adding delta from job {} to root model context; delta = {}", child, focusDelta.debugDump(0)); } if (focusContext.getPrimaryDelta() != null && !focusContext.getPrimaryDelta().isEmpty()) { focusContext.addPrimaryDelta(focusDelta); } else { focusContext.setPrimaryDelta(focusDelta); } changed = true; } Set<Map.Entry<ResourceShadowDiscriminator, ObjectDelta<ShadowType>>> entries = deltas.getProjectionChangeMapEntries(); for (Map.Entry<ResourceShadowDiscriminator, ObjectDelta<ShadowType>> entry : entries) { if (LOGGER.isTraceEnabled()) { LOGGER.trace("Adding projection delta from job {} to root model context; rsd = {}, delta = {}", child, entry.getKey(), entry.getValue().debugDump()); } ModelProjectionContext projectionContext = rootContext.findProjectionContext(entry.getKey()); if (projectionContext == null) { // TODO more liberal treatment? throw new IllegalStateException("No projection context for " + entry.getKey()); } if (projectionContext.getPrimaryDelta() != null && !projectionContext.getPrimaryDelta().isEmpty()) { projectionContext.addPrimaryDelta(entry.getValue()); } else { projectionContext.setPrimaryDelta(entry.getValue()); } changed = true; } } } } if (!rootContext.hasAnyPrimaryChange()) { rootContext = null; // deletes the model context changed = true; // regardless of whether rootContext was changed or not } if (changed) { rootWfTask.storeModelContext(rootContext); rootWfTask.commitChanges(result); } } catch (SchemaException e) { LoggingUtils.logUnexpectedException(LOGGER, "Couldn't aggregate resulting deltas from child workflow-monitoring tasks due to schema exception", e); status = TaskRunResultStatus.PERMANENT_ERROR; } catch (ObjectNotFoundException e) { LoggingUtils.logUnexpectedException(LOGGER, "Couldn't aggregate resulting deltas from child workflow-monitoring tasks", e); status = TaskRunResultStatus.PERMANENT_ERROR; } catch (ObjectAlreadyExistsException e) { LoggingUtils.logUnexpectedException(LOGGER, "Couldn't aggregate resulting deltas from child workflow-monitoring tasks", e); status = TaskRunResultStatus.PERMANENT_ERROR; } catch (CommunicationException e) { LoggingUtils.logUnexpectedException(LOGGER, "Couldn't aggregate resulting deltas from child workflow-monitoring tasks", e); status = TaskRunResultStatus.TEMPORARY_ERROR; } catch (ConfigurationException e) { LoggingUtils.logUnexpectedException(LOGGER, "Couldn't aggregate resulting deltas from child workflow-monitoring tasks", e); status = TaskRunResultStatus.PERMANENT_ERROR; } TaskRunResult runResult = new TaskRunResult(); runResult.setRunResultStatus(status); return runResult; } //endregion //region Other task handler stuff @Override public Long heartbeat(Task task) { return null; // null - as *not* to record progress (which would overwrite operationResult!) } @Override public void refreshStatus(Task task) { } @Override public String getCategoryName(Task task) { return TaskCategory.WORKFLOW; } @Override public List<String> getCategoryNames() { return null; //To change body of implemented methods use File | Settings | File Templates. } //endregion }