transfer(info,null);
}
/** Execute the Pipe */
public synchronized void transfer(TransferInfo info, Date requestTime) {
LogEntry logEntry = new LogEntry(this, info);
database = info.getDatabaseName();
//Set start time so that duration can be calculated when pipe finishes
long start=System.currentTimeMillis();
Date startTime=new Date();
setExecutionStartInfo(info.getUserName(), startTime);
logEntry.setUserName(info.getUserName());
// TODO: Replace these with proper Status classes
final int PIPE_EXECUTION_OK = 1;
final int PIPE_EXECUTION_FAILED = 0;
//final int PIPE_EXECUTION_ABORTED = -1;
// currentTask information will be used for error/exception logging
String currentTask = "Pipe transfer initialization";
// Initialize Pipe execution status to STATUS_OK
int statusCode = LogEntry.STATUS_OK;
// This status flag indicates whether calling closeComponentSessions is required
// at the end of Pipe execution
boolean componentSessionsOpen = false;
if(requestTime != null) {
logEntry.logMessage("Received Pipe execution request", this, MessageLogger.DEBUG, requestTime);
}
// Get Source component and initialize its parameters
{
SourceIF source = getSource();
if(source == null) {
if(getSourceID() == null) {
logEntry.logMessage(
"Pipe does not have a Source component, aborting",
this,
MessageLogger.ERROR);
} else {
logEntry.logMessage(
"Pipe Source component cannot be loaded, aborting",
this,
MessageLogger.ERROR);
}
setExecutionEndInfo(new Date(), System.currentTimeMillis()-start, LogEntry.STATUS_SOURCE_ERROR);
addLogEntry(logEntry, LogEntry.STATUS_SOURCE_ERROR);
return;
}
source.setData(getSourceData());
}
// Get Converter components and initialize their parameters
{
int converterIndex = 0;
for(Iterator it = converterList.iterator(); it.hasNext();) {
ConverterListItem converterItem = (ConverterListItem) it.next();
converterIndex++;
try {
ConverterIF converter = converterItem.getConverter();
converter.setData(converterItem.getConverterData());
} catch(PipeComponentCreationException e) {
logEntry.logMessage("Pipe Converter component #" + converterIndex
+ " cannot be loaded, aborting", this, MessageLogger.ERROR);
Environment.getInstance().log("Error loading Converter component #" + converterIndex +
" for Pipe \"" + getName() + "\"", e);
setExecutionEndInfo(new Date(), System.currentTimeMillis()-start, LogEntry.STATUS_CONVERSION_ERROR);
addLogEntry(logEntry, LogEntry.STATUS_CONVERSION_ERROR);
return;
}
}
}
// Get Destination component and initialize its parameters
{
DestinationIF destination = getDestination();
if(destination == null) {
if(getDestinationID() == null) {
logEntry.logMessage(
"Pipe does not have a Destination component, aborting",
this,
MessageLogger.ERROR);
} else {
logEntry.logMessage(
"Pipe Destination component cannot be loaded, aborting",
this,
MessageLogger.ERROR);
}
setExecutionEndInfo(new Date(), System.currentTimeMillis()-start, LogEntry.STATUS_DESTINATION_ERROR);
addLogEntry(logEntry, LogEntry.STATUS_DESTINATION_ERROR);
return;
}
destination.setData(getDestinationData());
}
logEntry.logMessage("Starting Pipe execution", this, MessageLogger.DEBUG);
try {
/** Open Source, Converter and Destination components' sessions */
currentTask = "Pipe Component initialization";
statusCode = openComponentSessions(
source,
destination,
getConverterList(),
info,
logEntry);
if(statusCode != LogEntry.STATUS_OK) {
// Initialization failed, LogEntry's statusCode is used at the end of this method
// for addLogEntry() call
throw new FailTransferException();
}
componentSessionsOpen = true;
/** Pipe iteration loop starts here */
int i = 0;
while(true) {
try {
logEntry.logMessage(
"Requesting data block #" + ++i + " from Source component",
this,
MessageLogger.DEBUG);
currentTask = "Source component " + this.source.getName();
statusCode = LogEntry.STATUS_SOURCE_ERROR;
String sourceResults[] = source.give(info, logEntry);
// Test if Source component returned no (more) data
if(sourceResults == null || sourceResults[0] == null) {
logEntry.logMessage(
"Source component returned no data",
this,
MessageLogger.DEBUG);
/*
* Exit iteration loop when Source component returns null instead of data
* String
*/
break;
}
if(sourceResults.length > 1) {
logEntry.logMessage("Source component returned " + sourceResults.length
+ " data blocks", this, MessageLogger.DEBUG);
}
// Iterate over Strings returned by Source component
for(int j = 0; j < sourceResults.length; j++) {
// Proceed with conversions
statusCode = LogEntry.STATUS_CONVERSION_ERROR;
currentTask = "Preparing to call first Converter component";
getConverterList();
Iterator it = this.converterList.iterator();
// Check if we have any Converters on the list
if(it.hasNext() == true) {
/*
* Converters (such as SplitConverter) may return multiple data parts
* based on a single input String
*/
String[] processedData = new String[1];
/*
* For first Converter on the list we call the regular 'convert' method,
* which takes String as input and returns String array
*/
ConverterListItem converterItem = (ConverterListItem) it.next();
ConverterIF converter = converterItem.getConverter();
currentTask = "Converter component " + converter.getName();
processedData = converter.convert(sourceResults[j], info, logEntry);
/*
* Test if any of the first Converter's result Strings is null, if yes ->
* report an error and abort Pipe execution
*/
if(arrayContainsNull(processedData)) {
logEntry.logMessage(
"Error: Converter " + converter.getName()
+ " returned null result, aborting",
this,
MessageLogger.ERROR);
throw new FailTransferException();
}
/*
* Repeat over the rest of the Converters list and call 'convertAll'
* method for processing every String in a String array
*/
while(it.hasNext()) {
converterItem = (ConverterListItem) it.next();
converter = converterItem.getConverter();
currentTask = "Converter component " + converter.getName();
processedData = converter.convertAll(processedData, info, logEntry);
/*
* Test if any of the Converter's result Strings is null, if yes ->
* report an error and abort Pipe execution
*/
if(arrayContainsNull(processedData)) {
logEntry.logMessage(
"Error: Converter " + converter.getName()
+ " returned null result, aborting",
this,
MessageLogger.ERROR);
throw new FailTransferException();
}
}
statusCode = LogEntry.STATUS_DESTINATION_ERROR;
currentTask = "Destination component " + this.destination.getName();
destination.takeAll(processedData, info, logEntry);
} else {
/*
* There were no Converters in this Pipe, so we pass the data from
* Source component directly to Destination component
*/
statusCode = LogEntry.STATUS_DESTINATION_ERROR;
currentTask = "Destination component " + this.destination.getName();
destination.take(sourceResults[j], info, logEntry);
}
statusCode = LogEntry.STATUS_OK;
}
/*
* Notify the Source component that last data block(s) were processed
* successfully
*/
statusCode = LogEntry.STATUS_SOURCE_ERROR;
currentTask = "while notifying Source component " + this.source.getName() + " of "
+ " successful processing of last data block through the Pipe";
source.lastBlockStatus(PIPE_EXECUTION_OK);
currentTask = "End of Pipe iteration loop";
statusCode = LogEntry.STATUS_OK;
} catch(AbortTransferException ate) {
/*
* Pass on AbortTransferException to the outside-loop catcher, since we want to
* abort the entire transfer.
*/
throw ate;
} catch(Throwable t) {
if(t instanceof Exception || t instanceof VirtualMachineError) {
logPipeExecutionError(t, currentTask, logEntry);
/**
* Notify the Source component of last data block failing to process, unless
* an unknown exception has occured in the Source component itself
*/
if(statusCode != LogEntry.STATUS_SOURCE_ERROR) {
currentTask = "Notifying Source component " + this.source.getName()
+ " of last data block failing to process through the Pipe";
// TODO: test support for FailTransferException and AbortTransferException during lastBlockStatus!
source.lastBlockStatus(PIPE_EXECUTION_FAILED);
}
logEntry.logMessage(
"Data block processing failed, aborting Pipe execution",
this,
MessageLogger.ERROR);
if(t instanceof Exception) {
// Pass Exception for the outer Exception handler
throw (Exception) t;
} else {
// Convert VirtualMachineErrors to FailTransferExceptions as we have
// already written the detailed error message to Transfer log
throw new FailTransferException();
}
}
}
} // Iteration loop ends here
logEntry.logMessage("Data block processing complete", this, MessageLogger.DEBUG);
statusCode = LogEntry.STATUS_OK;
} catch(AbortTransferException ate) {
statusCode = LogEntry.STATUS_ABORTED;
} catch(Exception e) {
// -----------------------------------------------------------
// If some component did not deliberately fail the transfer by
// throwing AbortTransferException, log the exception
// -----------------------------------------------------------
if(!(e instanceof FailTransferException)) {
Environment.getInstance().log(Utils.getThrowableName(e) + " during transfer, " + currentTask, e);
logEntry.logMessage(
Utils.getThrowableName(e) + " during transfer, " + currentTask + ": " + e.getMessage()
+ ". See OpenSyncro log file for details.",
this,
MessageLogger.ERROR);
}
} finally {
// Close iteration session (if open).
// Discard return code since an error has already happened.
// Preserve the earlier statusCode for addLogEntry() at the end of this method.
if(componentSessionsOpen) {
currentTask = "Closing Pipe component sessions";
// Preserve the Pipe's original statusCode unless
// something goes wrong during closing the component iteration sessions.
int closeSessionStatusCode = closeComponentSessions(info, logEntry);
if(closeSessionStatusCode != LogEntry.STATUS_OK) {
statusCode = closeSessionStatusCode;
}
componentSessionsOpen = false;
}
switch(statusCode) {
case LogEntry.STATUS_OK:
break;
case LogEntry.STATUS_ABORTED:
logEntry.logMessage("TRANSFER ABORTED", this, MessageLogger.WARNING);
break;
// The rest of the statusCodes are errors
default:
logEntry.logMessage("TRANSFER FAILED!", this, MessageLogger.ERROR);
break;
}
logEntry.logMessage("Pipe execution finished", this, MessageLogger.DEBUG);
setExecutionEndInfo( new Date(), System.currentTimeMillis()-start, statusCode);
addLogEntry(logEntry, statusCode);
// Add "--" log message entry when there are no other entries.
// Needed to display log entries that don't have log message entries.
Persister persister = new Persister(database);
if (persister.getLogMessageEntries(logEntry.getId(), MessageLogger.LOG_DYNAMIC).size() == 0){
logEntry.setIndex(1);
logEntry.logMessage("--", MessageLogger.ERROR);
}
}
}