/*
* 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;
/**
* @author mederly
*/
import com.evolveum.midpoint.model.api.context.ModelContext;
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.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.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* This handler prepares model operation to be executed within the context of child task:
* - prepares model operation context, filling it up with approved delta(s)
*
* @author mederly
*/
@Component
public class WfPrepareChildOperationTaskHandler implements TaskHandler {
public static final String HANDLER_URI = "http://midpoint.evolveum.com/xml/ns/public/workflow/prepare-child-operation/handler-3";
private static final Trace LOGGER = TraceManager.getTrace(WfPrepareChildOperationTaskHandler.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 Body
@SuppressWarnings("unchecked")
@Override
public TaskRunResult run(Task task) {
TaskRunResult.TaskRunResultStatus status = TaskRunResult.TaskRunResultStatus.FINISHED;
LOGGER.trace("WfPrepareChildOperationTaskHandler starting... task = {}", task);
try {
WfTask wfTask = wfTaskController.recreateWfTask(task);
OperationResult result = task.getResult();
ModelContext<?> modelContext = wfTask.retrieveModelContext(result);
if (modelContext == null) {
throw new IllegalStateException("There's no model context in child task; task = " + task);
}
// prepare deltaOut to be used
ObjectTreeDeltas deltasOut = wfTask.retrieveResultingDeltas();
if (LOGGER.isTraceEnabled()) { dumpDeltaOut(deltasOut); }
if (deltasOut == null || deltasOut.isEmpty()) {
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("There's no primary delta in focus context; we'll delete model operation context. Task = {}, model context:\n{}", task, modelContext.debugDump());
}
wfTask.deleteModelOperationContext();
} else {
// place deltaOut into model context
modelContext.getFocusContext().setPrimaryDelta(deltasOut.getFocusChange());
Set<Map.Entry<ResourceShadowDiscriminator, ObjectDelta<ShadowType>>> entries = deltasOut.getProjectionChangeMapEntries();
for (Map.Entry<ResourceShadowDiscriminator, ObjectDelta<ShadowType>> entry : entries) {
// TODO what if projection context does not exist?
modelContext.findProjectionContext(entry.getKey()).setPrimaryDelta(entry.getValue());
}
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Resulting model context to be stored into task {}:\n{}", task, modelContext.debugDump(0));
}
wfTask.storeModelContext(modelContext);
}
task.savePendingModifications(result);
} catch (SchemaException | ObjectNotFoundException | ObjectAlreadyExistsException | ConfigurationException | RuntimeException e) {
LoggingUtils.logUnexpectedException(LOGGER, "Couldn't prepare child model context", e);
status = TaskRunResult.TaskRunResultStatus.PERMANENT_ERROR;
} catch (CommunicationException e) {
LoggingUtils.logUnexpectedException(LOGGER, "Couldn't prepare child model context", e);
status = TaskRunResult.TaskRunResultStatus.TEMPORARY_ERROR;
}
TaskRunResult runResult = new TaskRunResult();
runResult.setRunResultStatus(status);
return runResult;
}
// TODO implement correctly
private void dumpDeltaOut(ObjectTreeDeltas<?> deltasOut) {
List<ObjectDelta<?>> deltaOut = deltasOut != null ? deltasOut.getDeltaList() : new ArrayList<ObjectDelta<?>>();
LOGGER.trace("deltaOut has {} modifications:", deltaOut.size());
for (ObjectDelta<?> delta : deltaOut) {
LOGGER.trace("{}", delta.debugDump());
}
}
//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
}