/*
* Copyright (C) 2006-2016 DLR, Germany
*
* All rights reserved
*
* http://www.rcenvironment.de/
*/
package de.rcenvironment.components.cpacs.writer.execution;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.io.FileUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import de.rcenvironment.components.cpacs.writer.common.CpacsWriterComponentConstants;
import de.rcenvironment.core.component.api.ComponentConstants;
import de.rcenvironment.core.component.api.ComponentException;
import de.rcenvironment.core.component.datamanagement.api.ComponentDataManagementService;
import de.rcenvironment.core.component.execution.api.ComponentContext;
import de.rcenvironment.core.component.execution.api.ComponentLog;
import de.rcenvironment.core.component.model.api.LazyDisposal;
import de.rcenvironment.core.component.model.spi.DefaultComponent;
import de.rcenvironment.core.component.xml.XmlComponentHistoryDataItem;
import de.rcenvironment.core.component.xml.api.EndpointXMLService;
import de.rcenvironment.core.datamodel.api.DataTypeException;
import de.rcenvironment.core.datamodel.api.TypedDatum;
import de.rcenvironment.core.datamodel.types.api.FileReferenceTD;
import de.rcenvironment.core.notification.DistributedNotificationService;
import de.rcenvironment.core.utils.common.LogUtils;
import de.rcenvironment.core.utils.common.StringUtils;
import de.rcenvironment.core.utils.common.TempFileServiceAccess;
/**
* Implementing class for Destination functionality with file support.
*
* @author Markus Kunde
* @author Markus Litz
* @author Arne Bachmann
*/
@LazyDisposal
public class CpacsWriterComponent extends DefaultComponent {
private Log log = LogFactory.getLog(getClass());
private ComponentContext componentContext;
private ComponentLog componentLog;
private DistributedNotificationService notificationService;
private ComponentDataManagementService dataManagementService;
private boolean overwriteEachRun = true;
private XmlComponentHistoryDataItem historyDataItem = null;
private EndpointXMLService endpointXmlService;
private File localFolder;
private File tempFile;
@Override
public void setComponentContext(ComponentContext componentContext) {
this.componentContext = componentContext;
componentLog = componentContext.getLog();
}
@Override
public void start() throws ComponentException {
dataManagementService = componentContext.getService(ComponentDataManagementService.class);
endpointXmlService = componentContext.getService(EndpointXMLService.class);
notificationService = componentContext.getService(DistributedNotificationService.class);
notificationService.setBufferSize(componentContext.getExecutionIdentifier() + CpacsWriterComponentConstants.RUNTIME_CPACS_UUIDS, 1);
overwriteEachRun = Boolean.parseBoolean(componentContext.getConfigurationValue(CpacsWriterComponentConstants.SAVE_MODE));
// determine local storage, if specified, or null, if not
final String localStore = componentContext.getConfigurationValue(CpacsWriterComponentConstants.LOCAL_STORE_FOLDER);
if ((localStore != null) && (!localStore.trim().isEmpty())) {
File folder = new File(localStore);
if (folder.isAbsolute()) {
localFolder = folder;
} else {
localFolder = null;
throw new ComponentException("Failed to write CPACS file as the given path is invalid,"
+ " it must be an absolute one: " + folder.getPath());
}
} else {
localFolder = null;
componentLog.componentInfo("Incoming CPACS file(s) not stored to local file system as no path is configured");
}
}
@Override
public void processInputs() throws ComponentException {
initializeNewHistoryDataItem();
FileReferenceTD cpacsFileRef = (FileReferenceTD) componentContext.readInput(CpacsWriterComponentConstants.INPUT_NAME_CPACS);
Map<String, TypedDatum> varInputs = new HashMap<>();
for (String inputName : componentContext.getInputsWithDatum()) {
if (componentContext.isDynamicInput(inputName)) {
varInputs.put(inputName, componentContext.readInput(inputName));
}
}
if (!varInputs.isEmpty() || hasDynamicOutputs()) {
try {
tempFile =
TempFileServiceAccess.getInstance().createTempFileWithFixedFilename(CpacsWriterComponentConstants.CPACS_FILENAME);
dataManagementService.copyReferenceToLocalFile(cpacsFileRef.getFileReference(), tempFile,
componentContext.getDefaultStorageNodeId());
} catch (IOException e) {
logError("Failed to write CPACS file into a temporary file (that is required for CPACS Writer) - skip run", e);
return;
}
boolean updated = false;
try {
endpointXmlService.updateXMLWithInputs(tempFile, varInputs, componentContext);
updated = true;
} catch (DataTypeException e) {
logError("Failed to add dynamic input values to the CPACS file", e);
}
String fileName;
if (updated) {
fileName = getFileName("cpacs_with_variables");
try {
cpacsFileRef = dataManagementService.createFileReferenceTDFromLocalFile(componentContext, tempFile, fileName);
} catch (IOException e) {
logError("Failed to store the CPACS file with variables into the data management - "
+ "if it is not stored in the data management, it can not be sent as output value", e);
}
if (!varInputs.isEmpty() && historyDataItem != null) {
historyDataItem.setXmlWithVariablesFileReference(cpacsFileRef.getFileReference());
storeHistoryDataItem();
}
} else {
fileName = getFileName("cpacs");
}
// copy CPACS file to local folder if configured to do so
if (localFolder != null) {
try {
File file = new File(localFolder, fileName);
FileUtils.copyFile(tempFile, file);
componentLog.componentInfo("Stored CPACS file to: " + file.getAbsolutePath());
} catch (IOException e) {
logError("Failed to store CPACS file to the local file system", e);
}
}
if (hasDynamicOutputs()) {
try {
endpointXmlService.updateOutputsFromXML(tempFile, componentContext);
} catch (DataTypeException e) {
logError("Failed to read dynamic output values from the CPACS file", e);
}
}
} else {
String fileName = getFileName("cpacs");
// write CPACS file to local folder if configured to do so
if (localFolder != null) {
try {
File file = new File(localFolder, fileName);
dataManagementService.copyReferenceToLocalFile(cpacsFileRef.getFileReference(), file,
componentContext.getDefaultStorageNodeId());
componentLog.componentInfo("Stored CPACS file to: " + file.getAbsolutePath());
} catch (IOException e) {
logError("Failed to store CPACS file to the local file system", e);
}
}
}
sendCPACSFile(cpacsFileRef);
deleteTempFile();
}
private void logError(String message, Exception e) {
String errorId = LogUtils.logExceptionWithStacktraceAndAssignUniqueMarker(log, message, e);
componentLog.componentError(message, e, errorId);
}
private void sendCPACSFile(FileReferenceTD cpacsFileRef) {
componentContext.writeOutput(CpacsWriterComponentConstants.OUTPUT_NAME_CPACS, cpacsFileRef);
notificationService.send(componentContext.getExecutionIdentifier()
+ CpacsWriterComponentConstants.RUNTIME_CPACS_UUIDS, cpacsFileRef.getFileReference());
}
@Override
public void completeStartOrProcessInputsAfterFailure() throws ComponentException {
storeHistoryDataItem();
deleteTempFile();
}
private void initializeNewHistoryDataItem() {
if (Boolean.valueOf(componentContext.getConfigurationValue(ComponentConstants.CONFIG_KEY_STORE_DATA_ITEM))) {
historyDataItem = new XmlComponentHistoryDataItem(CpacsWriterComponentConstants.COMPONENT_ID);
}
}
private void storeHistoryDataItem() {
if (Boolean.valueOf(componentContext.getConfigurationValue(ComponentConstants.CONFIG_KEY_STORE_DATA_ITEM))) {
componentContext.writeFinalHistoryDataItem(historyDataItem);
}
}
private String getFileName(String name) {
String fileName;
if (!overwriteEachRun) {
fileName = StringUtils.format("%s_%d.xml", name, componentContext.getExecutionCount());
} else {
fileName = StringUtils.format("%s.xml", name);
}
return fileName;
}
private boolean hasDynamicOutputs() {
for (String outputName : componentContext.getOutputs()) {
if (componentContext.isDynamicOutput(outputName)) {
return true;
}
}
return false;
}
@Override
public void dispose() {
if (componentContext != null) {
notificationService.removePublisher(componentContext.getExecutionIdentifier()
+ CpacsWriterComponentConstants.RUNTIME_CPACS_UUIDS);
}
}
private void deleteTempFile() {
if (tempFile != null) {
try {
TempFileServiceAccess.getInstance().disposeManagedTempDirOrFile(tempFile);
} catch (IOException e) {
LogFactory.getLog(getClass()).error("Failed to delete temp file: " + tempFile.getAbsolutePath(), e);
}
}
}
}