/*
* Copyright (C) 2006-2016 DLR, Germany
*
* All rights reserved
*
* http://www.rcenvironment.de/
*/
package de.rcenvironment.components.outputwriter.execution;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import org.apache.commons.io.FileUtils;
import org.apache.commons.logging.LogFactory;
import de.rcenvironment.components.outputwriter.common.OutputWriterComponentConstants;
import de.rcenvironment.components.outputwriter.common.OutputWriterComponentConstants.HandleExistingFile;
import de.rcenvironment.core.component.api.ComponentException;
import de.rcenvironment.core.component.execution.api.ComponentLog;
import de.rcenvironment.core.datamodel.api.TypedDatum;
import de.rcenvironment.core.utils.common.StringUtils;
/**
* A class for collecting simple input Data for an outputWriter and writing them into a formatted file.
*
* @author Brigitte Boden
*/
public class OutputLocationWriter {
private static final String ITERATION = " - iteration ";
private static final String BACKSLASHES = "\\";
private static final String DOT = ".";
private static final String DATE_FORMAT = "yyyy-MM-dd_HH-mm-ss-S";
private static final String LINE_SEP = System.getProperty("line.separator");
private File outputFile;
private String basicName;
private FileOutputStream outputStream;
private List<String> inputNames;
private final String header;
private final String formatString;
private final HandleExistingFile handleExistingFile;
private final ComponentLog componentLog;
// Iteration counter; used for AUTORENAME option
private long iterations;
protected OutputLocationWriter(List<String> inputNames, String header, String formatString,
HandleExistingFile handle, ComponentLog componentLog) {
this.header = header;
this.formatString = formatString;
this.handleExistingFile = handle;
this.iterations = 0;
this.inputNames = inputNames;
this.componentLog = componentLog;
}
/**
*
* In case of the APPEND or OVERRIDE option, the file is opened here and kept open.
*
* @throws ComponentException if creating/initializing the file failed
*
*/
protected void initializeFile(File fileToWrite) throws ComponentException {
this.basicName = fileToWrite.getName();
// Check for invalid filename
List<String> forbiddenFilenames = Arrays.asList(OutputWriterComponentConstants.PROBLEMATICFILENAMES_WIN);
if (forbiddenFilenames.contains(basicName) || basicName.contains("/") || basicName.contains("\\")) {
throw new ComponentException(StringUtils.format("Failed to write file beacuse '%s' "
+ "is a forbidden filename", basicName));
}
this.outputFile = fileToWrite;
if (handleExistingFile == HandleExistingFile.APPEND || handleExistingFile == HandleExistingFile.OVERRIDE) {
if (fileToWrite.exists()) {
fileToWrite = autoRename(fileToWrite);
this.outputFile = fileToWrite;
}
try {
outputStream = FileUtils.openOutputStream(fileToWrite, true);
// In case of the APPEND option, write the file header
if (handleExistingFile == HandleExistingFile.APPEND && !header.isEmpty()) {
Date dt = new Date();
SimpleDateFormat df = new SimpleDateFormat(DATE_FORMAT);
String timeStamp = df.format(dt);
FileUtils.writeStringToFile(outputFile, formatHeader(timeStamp, 0) + LINE_SEP, true);
}
} catch (IOException e) {
throw new ComponentException("Failed to create/initialized file used as target for simple data types: "
+ outputFile.getAbsolutePath(), e);
}
}
componentLog.componentInfo("Created and initialized file used as target for simple data types: " + outputFile.getAbsolutePath());
}
protected void writeOutput(Map<String, TypedDatum> inputMap, String timestamp, int executionCount) throws ComponentException {
String outputString = formatOutput(inputMap, timestamp, executionCount);
iterations++;
try {
if (handleExistingFile == HandleExistingFile.APPEND) {
// For option APPEND, the file is already open. Append the outputString.
FileUtils.writeStringToFile(outputFile, outputString, true);
} else if (handleExistingFile == HandleExistingFile.OVERRIDE) {
if (!header.isEmpty()) {
// For option OVERRIDE, write to the existing file without appending.
Date dt = new Date();
SimpleDateFormat df = new SimpleDateFormat(DATE_FORMAT);
String timeStamp = df.format(dt);
FileUtils.writeStringToFile(outputFile, formatHeader(timeStamp, executionCount) + LINE_SEP + outputString, false);
} else {
FileUtils.writeStringToFile(outputFile, outputString, false);
}
} else if (handleExistingFile == HandleExistingFile.AUTORENAME) {
if (!header.isEmpty()) {
// For option AUTORENAME, create a file with new name and write to it.
Date dt = new Date();
SimpleDateFormat df = new SimpleDateFormat(DATE_FORMAT);
String timeStamp = df.format(dt);
outputFile = getNamePerIteration(outputFile);
FileUtils.writeStringToFile(outputFile, formatHeader(timeStamp, executionCount) + LINE_SEP + outputString, false);
} else {
outputFile = getNamePerIteration(outputFile);
FileUtils.writeStringToFile(outputFile, outputString, false);
}
}
} catch (IOException e) {
throw new ComponentException("Failed to write file used as target for simple data types: " + outputFile.getAbsolutePath(), e);
}
componentLog.componentInfo(StringUtils.format("Wrote '%s' to: %s", inputMap, outputFile.getAbsolutePath()));
}
protected String formatOutput(Map<String, TypedDatum> inputMap, String timestamp, int executionCount) {
String outputString = formatString;
outputString = outputString.replaceAll(escapePlaceholder(OutputWriterComponentConstants.PH_TIMESTAMP), timestamp);
outputString = outputString.replaceAll(escapePlaceholder(OutputWriterComponentConstants.PH_LINEBREAK), LINE_SEP);
outputString =
outputString.replaceAll(escapePlaceholder(OutputWriterComponentConstants.PH_EXECUTION_COUNT), Integer.toString(executionCount));
for (Map.Entry<String, TypedDatum> entry : inputMap.entrySet()) {
outputString = outputString.replaceAll(escapePlaceholder(OutputWriterComponentConstants.PH_PREFIX) + entry.getKey()
+ escapePlaceholder(OutputWriterComponentConstants.PH_SUFFIX),
entry.getValue().toString());
outputString =
outputString.replaceAll(escapePlaceholder(OutputWriterComponentConstants.PH_PREFIX)
+ OutputWriterComponentConstants.INPUTNAME + OutputWriterComponentConstants.PH_DELIM + entry.getKey()
+ escapePlaceholder(OutputWriterComponentConstants.PH_SUFFIX),
entry.getKey());
}
return outputString;
}
protected String formatHeader(String timestamp, int executionCount) {
String outputString = this.header;
outputString = outputString.replaceAll(escapePlaceholder(OutputWriterComponentConstants.PH_TIMESTAMP), timestamp);
outputString = outputString.replaceAll(escapePlaceholder(OutputWriterComponentConstants.PH_LINEBREAK), LINE_SEP);
outputString =
outputString.replaceAll(escapePlaceholder(OutputWriterComponentConstants.PH_EXECUTION_COUNT), Integer.toString(executionCount));
for (String inputName : inputNames) {
outputString =
outputString.replaceAll(escapePlaceholder(OutputWriterComponentConstants.PH_PREFIX)
+ OutputWriterComponentConstants.INPUTNAME + OutputWriterComponentConstants.PH_DELIM + inputName
+ escapePlaceholder(OutputWriterComponentConstants.PH_SUFFIX),
inputName);
}
return outputString;
}
private String escapePlaceholder(String placeholder) {
placeholder = placeholder.replace(OutputWriterComponentConstants.PH_PREFIX, BACKSLASHES + OutputWriterComponentConstants.PH_PREFIX);
return placeholder.replace(OutputWriterComponentConstants.PH_SUFFIX, BACKSLASHES + OutputWriterComponentConstants.PH_SUFFIX);
}
protected File getNamePerIteration(File fileToWrite) {
String folderpath = fileToWrite.getParent();
String fileName = basicName;
String extension = "";
if (fileName.contains(DOT)) {
extension = fileName.substring(fileName.lastIndexOf(DOT));
fileName = fileName.substring(0, fileName.lastIndexOf(DOT));
}
File possibleFile = new File(folderpath, fileName + ITERATION + iterations + extension);
if (possibleFile.exists()) {
possibleFile = autoRename(possibleFile);
}
return possibleFile;
}
protected void close() {
try {
if (outputStream != null) {
outputStream.close();
}
} catch (IOException e) {
LogFactory.getLog(getClass()).error("Failed to close output stream: ", e);
}
}
protected File autoRename(File fileToWrite) {
String folderpath = fileToWrite.getParent();
String fileName = fileToWrite.getName();
String extension = "";
if (fileName.contains(DOT)) {
extension = fileName.substring(fileName.lastIndexOf(DOT));
fileName = fileName.substring(0, fileName.lastIndexOf(DOT));
}
int i = 1;
File possibleFile = new File(folderpath, fileName + " (" + i + ")" + extension);
while (possibleFile.exists()) {
possibleFile = new File(folderpath, fileName + " (" + ++i + ")" + extension);
}
componentLog.componentInfo(StringUtils.format("File '%s' already exists, "
+ "renamed to: %s", fileToWrite.getAbsolutePath(), possibleFile.getAbsolutePath()));
return possibleFile;
}
}