/*
* Copyright (C) 2006-2016 DLR, Germany
*
* All rights reserved
*
* http://www.rcenvironment.de/
*/
package de.rcenvironment.core.component.workflow.execution.internal;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import de.rcenvironment.core.component.api.ComponentConstants;
import de.rcenvironment.core.component.execution.api.ComponentState;
import de.rcenvironment.core.component.execution.api.ConsoleRow;
import de.rcenvironment.core.component.execution.api.ConsoleRowUtils;
import de.rcenvironment.core.component.workflow.execution.api.WorkflowExecutionContext;
import de.rcenvironment.core.component.workflow.execution.api.WorkflowExecutionController;
import de.rcenvironment.core.component.workflow.execution.api.WorkflowExecutionException;
import de.rcenvironment.core.component.workflow.execution.api.WorkflowExecutionUtils;
import de.rcenvironment.core.component.workflow.execution.api.WorkflowState;
import de.rcenvironment.core.datamodel.api.TimelineIntervalType;
import de.rcenvironment.core.notification.DistributedNotificationService;
import de.rcenvironment.core.toolkitbridge.transitional.ConcurrencyUtils;
import de.rcenvironment.core.utils.common.StringUtils;
import de.rcenvironment.core.utils.incubator.DebugSettings;
import de.rcenvironment.toolkit.modules.concurrency.api.AsyncCallbackExceptionPolicy;
import de.rcenvironment.toolkit.modules.concurrency.api.AsyncOrderedExecutionQueue;
/**
* Implementation of {@link WorkflowExecutionController}.
*
* @author Doreen Seider
* @author Robert Mischke
*/
public class WorkflowExecutionControllerImpl implements WorkflowExecutionController {
private static final Log LOG = LogFactory.getLog(WorkflowExecutionControllerImpl.class);
private static final boolean VERBOSE_LOGGING = DebugSettings.getVerboseLoggingEnabled(WorkflowExecutionControllerImpl.class);
private static DistributedNotificationService notificationService;
private static WorkflowExecutionRelatedInstancesFactory wfExeInstancesFactory;
private WorkflowExecutionContext wfExeCtx;
private WorkflowExecutionStorageBridge wfExeStorageBridge;
private WorkflowStateMachine wfStateMachine;
private ComponentStatesChangedEntirelyVerifier compStatesEntirelyChangedVerifier;
private ComponentsConsoleLogFileWriter compConsoleLogFileWriter;
private ComponentLostWatcher compLostWatcher;
private AsyncOrderedExecutionQueue notifSendingAsyncExecQueue =
ConcurrencyUtils.getFactory().createAsyncOrderedExecutionQueue(AsyncCallbackExceptionPolicy.LOG_AND_PROCEED);
@Deprecated
public WorkflowExecutionControllerImpl() {}
public WorkflowExecutionControllerImpl(WorkflowExecutionContext wfContext) {
this.wfExeCtx = wfContext;
wfExeStorageBridge = wfExeInstancesFactory.createWorkflowExecutionStorageBridge(wfContext);
compConsoleLogFileWriter = wfExeInstancesFactory.createComponentConsoleLogFileWriter(wfExeStorageBridge);
compStatesEntirelyChangedVerifier = wfExeInstancesFactory.createComponentStatesEntirelyChangedVerifier(
wfExeCtx.getWorkflowDescription().getWorkflowNodes().size()
- WorkflowExecutionUtils.getDisabledWorkflowNodes(wfExeCtx.getWorkflowDescription()).size());
compLostWatcher = wfExeInstancesFactory.createComponentLostWatcher(wfExeCtx, compStatesEntirelyChangedVerifier);
wfStateMachine = wfExeInstancesFactory.createWorkflowStateMachine(new WorkflowStateMachineContext(wfExeCtx, wfExeStorageBridge,
compStatesEntirelyChangedVerifier, compConsoleLogFileWriter, compLostWatcher));
compStatesEntirelyChangedVerifier.addListener(wfStateMachine);
}
@Override
public void start() {
wfStateMachine.postEvent(new WorkflowStateMachineEvent(WorkflowStateMachineEventType.START_REQUESTED));
}
@Override
public void pause() {
wfStateMachine.postEvent(new WorkflowStateMachineEvent(WorkflowStateMachineEventType.PAUSE_REQUESTED));
}
@Override
public void resume() {
wfStateMachine.postEvent(new WorkflowStateMachineEvent(WorkflowStateMachineEventType.RESUME_REQUESTED));
}
@Override
public void restart() {
throw new UnsupportedOperationException("Restarting workflows not yet implemented");
}
@Override
public void cancel() {
wfStateMachine.postEvent(new WorkflowStateMachineEvent(WorkflowStateMachineEventType.CANCEL_REQUESTED));
}
@Override
public void dispose() {
wfStateMachine.postEvent(new WorkflowStateMachineEvent(WorkflowStateMachineEventType.DISPOSE_REQUESTED));
}
@Override
public void setComponentExecutionAuthTokens(Map<String, String> exeAuthTokens) {
wfStateMachine.setComponentExecutionAuthTokens(exeAuthTokens);
}
@Override
public WorkflowState getState() {
return wfStateMachine.getState();
}
@Override
public Long getDataManagementId() {
return wfExeStorageBridge.getWorkflowInstanceDataManamagementId();
}
@Override
public void onComponentStateChanged(String compExeId, ComponentState newState,
Integer executionCount, String executionCountOnResets) {
onComponentStateChanged(compExeId, newState, executionCount, executionCountOnResets, null, null);
}
@Override
public void onComponentStateChanged(String compExeId, ComponentState newState, Integer executionCount, String executionCountOnResets,
String errorId) {
onComponentStateChanged(compExeId, newState, executionCount, executionCountOnResets, errorId, null);
}
@Override
public synchronized void onComponentStateChanged(final String compExeId, final ComponentState newState,
Integer executionCount, final String executionCountOnResets, String errorId, String errorMessage) {
notifSendingAsyncExecQueue.enqueue(new Runnable() {
@Override
public void run() {
notificationService.send(ComponentConstants.STATE_NOTIFICATION_ID_PREFIX + compExeId, newState.name());
notificationService.send(ComponentConstants.ITERATION_COUNT_NOTIFICATION_ID_PREFIX + compExeId, executionCountOnResets);
}
});
compStatesEntirelyChangedVerifier.announceComponentState(compExeId, newState);
if (ComponentConstants.FAILED_COMPONENT_STATES.contains(newState)) {
WorkflowStateMachineEventType eventType = WorkflowStateMachineEventType.CANCEL_AFTER_FAILED_REQUESTED;
if (newState == ComponentState.RESULTS_REJECTED) {
eventType = WorkflowStateMachineEventType.CANCEL_AFTER_RESULTS_REJECTED_REQUESTED;
}
wfStateMachine.postEvent(new WorkflowStateMachineEvent(eventType, errorId, errorMessage, compExeId));
}
}
@Override
public void onInputProcessed(String serializedEndpointDatum) {
notificationService.send(StringUtils.format(ComponentConstants.NOTIFICATION_ID_PREFIX_PROCESSED_INPUT + "%s:%s", wfExeCtx
.getNodeId().getLogicalNodeIdString(), wfExeCtx.getExecutionIdentifier()), serializedEndpointDatum);
}
@Override
public void processConsoleRows(ConsoleRow[] consoleRows) {
for (ConsoleRow consoleRow : consoleRows) {
notificationService.send(ConsoleRowUtils.composeConsoleNotificationId(wfExeCtx.getNodeId(), wfExeCtx.getExecutionIdentifier()),
consoleRow);
try {
checkForLifecycleToolRunConsoleRow(consoleRow);
} catch (WorkflowExecutionException e) {
wfStateMachine
.postEvent(new WorkflowStateMachineEvent(WorkflowStateMachineEventType.PROCESS_COMPONENT_TIMELINE_EVENTS_FAILED, e));
}
compConsoleLogFileWriter.addComponentConsoleRow(consoleRow);
checkForLifecycleInfoEndConsoleRow(consoleRow);
}
}
@Override
public void onComponentHeartbeatReceived(String compExecutionId) {
if (VERBOSE_LOGGING) {
LOG.debug(StringUtils.format("Received hearbeat from component (%s) for workflow '%s' (%s)",
compExecutionId, wfExeCtx.getInstanceName(), wfExeCtx.getExecutionIdentifier()));
}
compLostWatcher.announceComponentHeartbeat(compExecutionId);
}
private void checkForLifecycleInfoEndConsoleRow(ConsoleRow row) {
if (row.getType() == ConsoleRow.Type.LIFE_CYCLE_EVENT
&& row.getPayload().startsWith(ConsoleRow.WorkflowLifecyleEventType.COMPONENT_TERMINATED.name())) {
compStatesEntirelyChangedVerifier.announceLastConsoleRow(row.getComponentIdentifier());
}
}
private void checkForLifecycleToolRunConsoleRow(ConsoleRow row) throws WorkflowExecutionException {
if (row.getType() == ConsoleRow.Type.LIFE_CYCLE_EVENT) {
if (row.getPayload().startsWith(ConsoleRow.WorkflowLifecyleEventType.TOOL_STARTING.name())) {
wfExeStorageBridge.addComponentTimelineInterval(TimelineIntervalType.EXTERNAL_TOOL_RUN_IN_COMPONENT_RUN,
row.getTimestamp(), StringUtils.splitAndUnescape(row.getPayload())[1]);
} else if (row.getPayload().startsWith(ConsoleRow.WorkflowLifecyleEventType.TOOL_FINISHED.name())) {
wfExeStorageBridge.setComponentTimelineIntervalFinished(TimelineIntervalType.EXTERNAL_TOOL_RUN_IN_COMPONENT_RUN,
row.getTimestamp(), StringUtils.splitAndUnescape(row.getPayload())[1]);
}
}
}
protected void bindDistributedNotificationService(DistributedNotificationService newService) {
WorkflowExecutionControllerImpl.notificationService = newService;
}
protected void bindWorkflowExecutionRelatedInstancesFactory(WorkflowExecutionRelatedInstancesFactory newService) {
WorkflowExecutionControllerImpl.wfExeInstancesFactory = newService;
}
}