/*
* Copyright (C) 2006-2016 DLR, Germany
*
* All rights reserved
*
* http://www.rcenvironment.de/
*/
package de.rcenvironment.core.component.execution.internal;
import java.util.HashMap;
import de.rcenvironment.core.communication.common.CommunicationException;
import de.rcenvironment.core.component.execution.api.ComponentExecutionContext;
import de.rcenvironment.core.component.execution.api.ComponentExecutionException;
import de.rcenvironment.core.datamanagement.DataManagementIdMapping;
import de.rcenvironment.core.datamanagement.MetaDataService;
import de.rcenvironment.core.datamodel.api.FinalComponentRunState;
import de.rcenvironment.core.datamodel.api.FinalComponentState;
import de.rcenvironment.core.utils.common.StringUtils;
/**
* Bridge class to the data management, holding relevant data management ids.
*
* @author Doreen Seider
* @author Robert Mischke (8.0.0 id adaptations)
* @author Brigitte Boden
*/
public class ComponentExecutionStorageBridge {
private static MetaDataService metaDataService;
private final ComponentExecutionRelatedInstances compExeRelatedInstances;
private final String errorMessageSuffix;
private final int timestampOffset;
private Long compExeDmId;
private EndpointCountMap inputCount = new EndpointCountMap();
private EndpointCountMap outputCount = new EndpointCountMap();
@Deprecated
public ComponentExecutionStorageBridge() {
compExeRelatedInstances = null;
this.timestampOffset = 0;
errorMessageSuffix = null;
}
public ComponentExecutionStorageBridge(ComponentExecutionRelatedInstances compExeRelatedInstances) {
this.compExeRelatedInstances = compExeRelatedInstances;
this.timestampOffset = compExeRelatedInstances.timestampOffsetToWorkfowNode;
errorMessageSuffix = StringUtils.format(" of '%s' (%s) (workflow '%s' (%s)) at %s",
compExeRelatedInstances.compExeCtx.getInstanceName(), compExeRelatedInstances.compExeCtx.getExecutionIdentifier(),
compExeRelatedInstances.compExeCtx.getWorkflowInstanceName(),
compExeRelatedInstances.compExeCtx.getWorkflowExecutionIdentifier(),
compExeRelatedInstances.compExeCtx.getWorkflowNodeId());
}
protected synchronized void addComponentExecution(final ComponentExecutionContext compExeCtx, final Integer executionCount)
throws ComponentExecutionException {
try {
compExeDmId = metaDataService.addComponentRun(compExeRelatedInstances.compExeCtx.getInstanceDataManagementId(),
DataManagementIdMapping.mapLogicalNodeIdToDbString(compExeCtx.getNodeId()),
executionCount, System.currentTimeMillis() + timestampOffset,
compExeRelatedInstances.compExeCtx.getDefaultStorageNodeId());
// catch RuntimeException until https://mantis.sc.dlr.de/view.php?id=13865 is solved
} catch (CommunicationException | RuntimeException e) {
throw new ComponentExecutionException("Failed to store component execution" + errorMessageSuffix, e);
}
}
protected synchronized Long addOutput(final String outputName, final String datum) throws ComponentExecutionException {
assertCompExeDmIdNotNull("Adding value for output: " + outputName);
try {
return metaDataService.addOutputDatum(compExeDmId,
compExeRelatedInstances.compExeCtx.getOutputDataManagementIds().get(outputName), datum,
outputCount.getAndIncrement(outputName), compExeRelatedInstances.compExeCtx.getDefaultStorageNodeId());
// catch RuntimeException until https://mantis.sc.dlr.de/view.php?id=13865 is solved
} catch (CommunicationException | RuntimeException e) {
throw new ComponentExecutionException(StringUtils.format("Failed to store output '%s'", outputName) + errorMessageSuffix, e);
}
}
protected synchronized void addInput(final String inputName, final Long typedDatumId) throws ComponentExecutionException {
assertCompExeDmIdNotNull("Adding value for input: " + inputName);
if (typedDatumId == null) {
throw new ComponentExecutionException(StringUtils.format("Failed to store input '%s'", inputName) + errorMessageSuffix + ", "
+ "because given datamanagement id of related output was null. Likely, because saving output failed earlier.");
} else {
try {
metaDataService.addInputDatum(compExeDmId, typedDatumId,
compExeRelatedInstances.compExeCtx.getInputDataManagementIds().get(inputName),
inputCount.getAndIncrement(inputName), compExeRelatedInstances.compExeCtx.getDefaultStorageNodeId());
// catch RuntimeException until https://mantis.sc.dlr.de/view.php?id=13865 is solved
} catch (CommunicationException | RuntimeException e) {
throw new ComponentExecutionException(StringUtils.format("Failed to store input '%s'", inputName) + errorMessageSuffix, e);
}
}
}
protected synchronized void setComponentExecutionFinished(final FinalComponentRunState finalState) throws ComponentExecutionException {
assertCompExeDmIdNotNull("Setting component execution to finish");
try {
metaDataService.setComponentRunFinished(compExeDmId, System.currentTimeMillis() + timestampOffset,
finalState, compExeRelatedInstances.compExeCtx.getDefaultStorageNodeId());
// catch RuntimeException until https://mantis.sc.dlr.de/view.php?id=13865 is solved
} catch (CommunicationException | RuntimeException e) {
throw new ComponentExecutionException("Failed to store component execution" + errorMessageSuffix, e);
}
compExeDmId = null;
}
protected synchronized void setFinalComponentState(final FinalComponentState finalState) throws ComponentExecutionException {
try {
metaDataService.setComponentInstanceFinalState(compExeRelatedInstances.compExeCtx.getInstanceDataManagementId(), finalState,
compExeRelatedInstances.compExeCtx.getDefaultStorageNodeId());
// catch RuntimeException until https://mantis.sc.dlr.de/view.php?id=13865 is solved
} catch (CommunicationException | RuntimeException e) {
throw new ComponentExecutionException("Failed to store final state" + errorMessageSuffix, e);
}
}
protected synchronized void setOrUpdateHistoryDataItem(final String historyDataItem) throws ComponentExecutionException {
assertCompExeDmIdNotNull("Adding or updating history data");
try {
metaDataService.setOrUpdateHistoryDataItem(compExeDmId, historyDataItem,
compExeRelatedInstances.compExeCtx.getDefaultStorageNodeId());
// catch RuntimeException until https://mantis.sc.dlr.de/view.php?id=13865 is solved
} catch (CommunicationException | RuntimeException e) {
throw new ComponentExecutionException("Failed to add or update history data" + errorMessageSuffix, e);
}
}
protected synchronized boolean hasUnfinishedComponentExecution() {
return compExeDmId != null;
}
protected synchronized Long getComponentExecutionDataManagementId() {
return compExeDmId;
}
private void assertCompExeDmIdNotNull(String info) throws ComponentExecutionException {
if (compExeDmId == null) {
throw new ComponentExecutionException(StringUtils.format("No component run for component '%s' stored in the database; "
+ "request failed: '%s'; note: writing outputs and history data items is only allowed within 'start()' if "
+ "'treatStartAsComponentRun()' returns true and within 'processInputs()' and not allowed at all if component "
+ "was cancelled", compExeRelatedInstances.compExeCtx.getExecutionIdentifier(), info));
}
}
/**
* {@link HashMap} that has default values and adds support for incrementing its values when returning them.
*
* @author Doreen Seider
*/
private class EndpointCountMap extends HashMap<String, Integer> {
private static final long serialVersionUID = 6170727124152514043L;
@Override
public Integer get(Object key) {
if (!containsKey(key)) {
put((String) key, new Integer(0));
}
return super.get(key);
}
public Integer getAndIncrement(String endpointName) {
Integer count = get(endpointName);
put(endpointName, count + 1);
return count;
}
}
protected void bindMetaDataService(MetaDataService newService) {
ComponentExecutionStorageBridge.metaDataService = newService;
}
}