Package smilehouse.opensyncro.pipes

Source Code of smilehouse.opensyncro.pipes.Pipe

/* OpenSyncro - A web-based enterprise application integration tool
* Copyright (C) 2008 Smilehouse Oy, support@opensyncro.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

package smilehouse.opensyncro.pipes;

import java.io.Serializable;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import java.util.Set;

import javax.mail.Address;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;

import smilehouse.opensyncro.pipes.component.AbortTransferException;
import smilehouse.opensyncro.pipes.component.ConverterIF;
import smilehouse.opensyncro.pipes.component.DestinationIF;
import smilehouse.opensyncro.pipes.component.FailTransferException;
import smilehouse.opensyncro.pipes.component.PipeComponentData;
import smilehouse.opensyncro.pipes.component.PipeComponentIF;
import smilehouse.opensyncro.pipes.component.SourceIF;
import smilehouse.opensyncro.pipes.log.LogEntry;
import smilehouse.opensyncro.pipes.log.LogMessageEntry;
import smilehouse.opensyncro.pipes.log.MessageLogger;
import smilehouse.opensyncro.pipes.metadata.TransferInfo;
import smilehouse.opensyncro.servlets.PipeComponentCreationException;
import smilehouse.opensyncro.system.Environment;
import smilehouse.opensyncro.system.Persister;
import smilehouse.util.Utils;

public class Pipe implements Serializable,Cloneable {

  private static final String MAIL_MESSAGE_NO_ENTRIES = "There are no log entries that match the notification level setting for this pipe";

    private static final String MAIL_SENDER = "OpenSyncro";

    private static final String[] MAIL_ADDRESS_DELIMITERS = {",", ";"};

    private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm";
   
    private static DateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);

    /** identifier field */
    private Long id;

    /** nullable persistent field */
    private String name;

    private String startPassword;
    // RPC Start is not currently supported
    //private boolean rpcStartEnabled;

    private boolean httpStartEnabled;

    private boolean abortMailEnabled;
   
    /** persistent field */
    private String sourceID;

    /** non-persistent properties */
    private SourceIF source;
    private PipeComponentData sourceData;

    /** persistent field */
    private String destinationID;

    /** non-persistent properties */
    private DestinationIF destination;
    private PipeComponentData destinationData;

    private List converterList;


    /** persistent field */
    private Set log;

    private int loggingVerbosityLevel;
    private int transferLogNotificationLevel;
    private String mailHost;
    private String recipientAddress;
   
    private Date startTime;
    private Date endTime;
    private String lastStatus;
    private Long duration;
    private String user;
   
    private String database;
   
    /** default constructor */
    public Pipe() {
        this.name = "Unnamed Pipe";
        this.startPassword = "";
        //this.rpcStartEnabled = false;
        this.httpStartEnabled = false;
        this.abortMailEnabled = true;
        loggingVerbosityLevel = MessageLogger.LOG_DYNAMIC;
        transferLogNotificationLevel = 1;
        mailHost = "";
        recipientAddress = "";
        this.converterList = new LinkedList();
        this.source = null;
        this.sourceData = null;
        this.destination = null;
        this.destinationData = null;
        this.startTime=null;
        this.endTime=null;
        this.duration=new Long("0");
        this.user="";
        this.lastStatus="";
       
    }

    public PipeComponentData getSourceData() {
        return this.sourceData;
    }

    public Long getId() {
        return this.id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSourceID() {
        return this.sourceID;
    }

    public void setSourceID(String sourceID) {
        this.sourceID = sourceID;
        this.source = null;
    }

    public String getDestinationID() {
        return this.destinationID;
    }


    public void setDestinationID(String destinationID) {
        this.destinationID = destinationID;
        this.destination = null;
    }

    public String getStartPassword() {
        return this.startPassword;
    }

    public void setStartPassword(String startPassword) {
        this.startPassword = startPassword;
    }

    /*
     * public boolean isRpcStartEnabled() { return this.rpcStartEnabled; }
     *
     * public void setRpcStartEnabled(boolean rpcStartEnabled) { this.rpcStartEnabled =
     * rpcStartEnabled; }
     */

    public boolean isHttpStartEnabled() {
        return this.httpStartEnabled;
    }

    public void setHttpStartEnabled(boolean httpStartEnabled) {
        this.httpStartEnabled = httpStartEnabled;
    }
   
    public boolean isAbortMailEnabled() {
        return this.abortMailEnabled;
    }

    public void setAbortMailEnabled(boolean emptyMailEnabled) {
        this.abortMailEnabled = emptyMailEnabled;
    }
   
    public SourceIF getSource() {
        try {
            if((this.source == null) && (this.sourceID != null)) {
                this.source = (SourceIF) Persister.getInstance(getSourceID());
            }
        } catch(PipeComponentCreationException e) {
            Environment.getInstance().log("Error loading Source component for Pipe \"" +
                getName() + "\"", e);
            this.source = null;
        }
        return this.source;
    }

    public SourceIF getCurrentSource() {
        return this.source;
    }


    public void setSourceData(PipeComponentData sourceData) {
        this.sourceData = sourceData;
    }

    public void setSource(SourceIF source) {
        this.source = source;
    }

    public DestinationIF getDestination() {
        try {
            if((this.destination == null) && (this.destinationID != null)) {
                this.destination = (DestinationIF) Persister.getInstance(getDestinationID());
            }
        } catch(PipeComponentCreationException e) {
            Environment.getInstance().log("Error loading Destination component for Pipe \""
                + getName() + "\"", e);
            this.destination = null;
        }
        return this.destination;
    }

    public DestinationIF getCurrentDestination() {
        return this.destination;
    }

    public void setDestinationData(PipeComponentData destinationData) {
        this.destinationData = destinationData;
    }

    public void setDestination(DestinationIF destination) {
        this.destination = destination;
    }

    public List getConverterList() {
        return this.converterList;
    }

    public void setConverterList(List converters) {
        Iterator iter = converters.iterator();
        while(iter.hasNext()) {
            ConverterListItem convListItem = (ConverterListItem) iter.next();
            convListItem.setParent(this);
        }
        this.converterList = converters;
    }

    public ConverterListItem addConverter(String converterID, PipeComponentData pcdata) {
        ConverterListItem convListItem = new ConverterListItem(converterID, pcdata);
        convListItem.setParent(this);
        this.converterList.add(convListItem);
        return convListItem;
    }

    public ConverterListItem addConverter(ConverterIF converter, PipeComponentData pcdata) {
        ConverterListItem convListItem = new ConverterListItem(converter, pcdata);
        convListItem.setParent(this);
        this.converterList.add(convListItem);
        return convListItem;
    }

    public PipeComponentData getDestinationData() {
        return this.destinationData;
    }

    public Set getLog() {
        return this.log;
    }

    public void setLog(Set log) {
        this.log = log;
    }

    public void setLoggingVerbosityLevel(int level) {
        this.loggingVerbosityLevel = level;
    }

    public int getLoggingVerbosityLevel() {
        return this.loggingVerbosityLevel;
    }

    public void setTransferLogNotificationLevel(int level) {
        this.transferLogNotificationLevel = level;
    }

    public int getTransferLogNotificationLevel() {
        return this.transferLogNotificationLevel;
    }

    public String getMailHost() {
        return this.mailHost;
    }

    public void setMailHost(String host) {
        this.mailHost = host;
    }

    public String getRecipientAddress() {
        return this.recipientAddress;
    }

    public void setRecipientAddress(String address) {
        this.recipientAddress = address;
    }

    public String toString() {
        return new ToStringBuilder(this).append("id", getId()).toString();
    }

    public boolean equals(Object other) {
        if(!(other instanceof Pipe))
            return false;
        Pipe castOther = (Pipe) other;
        return new EqualsBuilder().append(this.getId(), castOther.getId()).isEquals();
    }

    public int hashCode() {
        return new HashCodeBuilder().append(getId()).toHashCode();
    }

    public synchronized void transfer(TransferInfo info){
      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);
            }

        }

    }


  private int openComponentSessions(SourceIF source,
                                      DestinationIF destination,
                                      List converterList,
                                      TransferInfo info,
                                      LogEntry logEntry) {
        int statusCode = LogEntry.STATUS_OK;

        /** Open iteration session at Source component */
        if(openComponentSession(getSource(), info, logEntry) == PipeComponentIF.ITERATION_OPEN_STATUS_ERROR) {
            statusCode = LogEntry.STATUS_SOURCE_ERROR;
            return statusCode;
        }

        /** Open iteration session at Converter components */
            // Initialize converters
        int converterIndex = 0;
        for(Iterator it = converterList.iterator(); it.hasNext();) {
            ConverterListItem converterItem = (ConverterListItem) it.next();
            ConverterIF converter = converterItem.getConverter();
            converterIndex++;

            // Set PipeComponentData to Converter components before opening iteration session
            converter.setData(converterItem.getConverterData());

            // Open Converter's iteration session
            if(openComponentSession(converter, converterIndex, info, logEntry) == PipeComponentIF.ITERATION_OPEN_STATUS_ERROR) {
                // Close preceding Converter and Source component sessions

                // Warning: make sure (converterIndex - 1) here is at least 0, because
                // -1 means that all Converter sessions are to be closed
                closeConverterComponentSessions(converterIndex - 1, info, logEntry);
                closeComponentSession(source, info, logEntry);

                statusCode = LogEntry.STATUS_CONVERSION_ERROR;
                return statusCode;
            }
        }

        /** Open iteration session at Destination component */
        if(openComponentSession(getDestination(), info, logEntry) == PipeComponentIF.ITERATION_OPEN_STATUS_ERROR) {

            // Close Converter and Source component sessions
            closeConverterComponentSessions(info, logEntry);
            closeComponentSession(source, info, logEntry);

            statusCode = LogEntry.STATUS_DESTINATION_ERROR;
            return statusCode;
        }

        return statusCode;
    }

    private int openComponentSession(DestinationIF destination, TransferInfo info, LogEntry logEntry) {
        // Open Destination component session
        try {
            int retCode;
            // Initialize Destination component for iteration mode
            logEntry.logMessage(
                "Opening iteration session at Destination component",
                this,
                MessageLogger.DEBUG);
            retCode = destination.open(info, logEntry);
            if(retCode != PipeComponentIF.ITERATION_OPEN_STATUS_OK) {
                logEntry.logMessage("Error opening session at Destination component "
                        + this.destination.getName(), this, MessageLogger.ERROR);
                return PipeComponentIF.ITERATION_OPEN_STATUS_ERROR;
            }

        } catch(Exception e) {
       
            logSessionOpenError(e, "destination", destination, logEntry);
            return PipeComponentIF.ITERATION_OPEN_STATUS_ERROR;

        } catch(VirtualMachineError e) {

            logSessionOpenError(e, "destination", destination, logEntry);
            return PipeComponentIF.ITERATION_OPEN_STATUS_ERROR;
       
        }

        return PipeComponentIF.ITERATION_OPEN_STATUS_OK;
    }

    private int openComponentSession(ConverterIF converter,
                                     int converterIndex,
                                     TransferInfo info,
                                     LogEntry logEntry) {
        // Open Converter component session
        try {
            int retCode;
            logEntry.logMessage("Opening iteration session at Converter component #"
                    + converterIndex + " (" + converter.getName() + ")", this, MessageLogger.DEBUG);

            retCode = converter.open(info, logEntry);
            if(retCode != PipeComponentIF.ITERATION_OPEN_STATUS_OK) {

                logEntry.logMessage(
                    "Error opening iteration session at Converter component #" + converterIndex
                            + " (" + converter.getName() + ")",
                    this,
                    MessageLogger.ERROR);
                return PipeComponentIF.ITERATION_OPEN_STATUS_ERROR;

            }
        } catch(Exception e) {

            logSessionOpenError(e, "converter", converter, logEntry);
            return PipeComponentIF.ITERATION_OPEN_STATUS_ERROR;
           
        } catch(VirtualMachineError e) {

            logSessionOpenError(e, "converter", converter, logEntry);
            return PipeComponentIF.ITERATION_OPEN_STATUS_ERROR;
           
        }

        return PipeComponentIF.ITERATION_OPEN_STATUS_OK;
    }

    private int openComponentSession(SourceIF source, TransferInfo info, LogEntry logEntry) {
        // Open Source component session
        try {
            int retCode;

            // Initialize Source component for iteration mode
            logEntry.logMessage(
                "Opening iteration session at Source component",
                this,
                MessageLogger.DEBUG);
            retCode = source.open(info, logEntry);
            if(retCode != PipeComponentIF.ITERATION_OPEN_STATUS_OK) {
                logEntry.logMessage(
                    "Error opening session at Source component " + source.getName(),
                    this,
                    MessageLogger.ERROR);
                return PipeComponentIF.ITERATION_OPEN_STATUS_ERROR;
            }

        } catch(Exception e) {
           
            logSessionOpenError(e, "source", source, logEntry);
            return PipeComponentIF.ITERATION_OPEN_STATUS_ERROR;
           
        } catch(VirtualMachineError e) {

            logSessionOpenError(e, "source", source, logEntry);
            return PipeComponentIF.ITERATION_OPEN_STATUS_ERROR;
           
        }
       
        return PipeComponentIF.ITERATION_OPEN_STATUS_OK;
    }

    public int closeComponentSessions(TransferInfo info, LogEntry logEntry) {

        int statusCode = LogEntry.STATUS_OK;

        /** Close iteration session at Source component */
        if(closeComponentSession(getSource(), info, logEntry) == PipeComponentIF.ITERATION_CLOSE_STATUS_ERROR) {
            statusCode = LogEntry.STATUS_SOURCE_ERROR;
        }

        /** Close iteration session at Converter component(s) */
        if(closeConverterComponentSessions(info, logEntry) == PipeComponentIF.ITERATION_CLOSE_STATUS_ERROR) {
            statusCode = LogEntry.STATUS_CONVERSION_ERROR;
        }

        /** Close iteration session at Destination component */
        if(closeComponentSession(getDestination(), info, logEntry) == PipeComponentIF.ITERATION_CLOSE_STATUS_ERROR) {
            statusCode = LogEntry.STATUS_DESTINATION_ERROR;
        }

        return statusCode;
    }

    private int closeConverterComponentSessions(TransferInfo info, LogEntry logEntry) {
        return closeConverterComponentSessions(-1, info, logEntry);
    }

    /**
     * @param stopIndex Number of Converters to process. -1 closes all Converters' sessions.
     * @return
     * @see smilehouse.opensyncro.pipes.log.LogEntry#STATUS_*
     */
    private int closeConverterComponentSessions(int stopIndex, TransferInfo info, LogEntry logEntry) {
        int converterIndex = 0;
        for(Iterator it = getConverterList().iterator(); it.hasNext();) {

            // If stopIndex is specified, break out of the loop when stopIndex
            // is reached
            if((stopIndex != -1) && (converterIndex >= stopIndex))
                break;

            ConverterListItem converterItem = (ConverterListItem) it.next();
            converterIndex++;

            if(closeComponentSession(converterItem.getConverter(), converterIndex, info, logEntry) == PipeComponentIF.ITERATION_CLOSE_STATUS_ERROR) {
                return PipeComponentIF.ITERATION_CLOSE_STATUS_ERROR;
            }
        }
        return PipeComponentIF.ITERATION_CLOSE_STATUS_OK;
    }

    private int closeComponentSession(DestinationIF destination,
                                      TransferInfo info,
                                      LogEntry logEntry) {
        int retCode;
        try {
            logEntry.logMessage(
                "Closing iteration session at Destination component",
                this,
                MessageLogger.DEBUG);

            retCode = destination.close(info, logEntry);
            if(retCode != PipeComponentIF.ITERATION_CLOSE_STATUS_OK) {

                logEntry.logMessage(
                    "Error closing iteration session at Destination component",
                    this,
                    MessageLogger.ERROR);
                return PipeComponentIF.ITERATION_CLOSE_STATUS_ERROR;
            }
        } catch(Exception e) {

            logSessionCloseError(e, "destination", destination, logEntry);
            return PipeComponentIF.ITERATION_CLOSE_STATUS_ERROR;

        } catch(VirtualMachineError e) {

            logSessionCloseError(e, "destination", destination, logEntry);
            return PipeComponentIF.ITERATION_CLOSE_STATUS_ERROR;

        }
       
        return PipeComponentIF.ITERATION_CLOSE_STATUS_OK;
    }

    private int closeComponentSession(ConverterIF converter,
                                      int converterIndex,
                                      TransferInfo info,
                                      LogEntry logEntry) {

        try {
            int retCode;
            logEntry.logMessage("Closing iteration session at Converter component #"
                    + converterIndex + " (" + converter.getName() + ")", this, MessageLogger.DEBUG);

            retCode = converter.close(info, logEntry);

            if(retCode != PipeComponentIF.ITERATION_CLOSE_STATUS_OK) {

                logEntry.logMessage(
                    "Error closing iteration session at Converter component #" + converterIndex
                            + " (" + converter.getName() + ")",
                    this,
                    MessageLogger.ERROR);
                return PipeComponentIF.ITERATION_CLOSE_STATUS_ERROR;

            }

        } catch(Exception e) {

            logSessionCloseError(e, "converter", converter, logEntry);
            return PipeComponentIF.ITERATION_CLOSE_STATUS_ERROR;

        } catch(VirtualMachineError e) {

            logSessionCloseError(e, "converter", converter, logEntry);
            return PipeComponentIF.ITERATION_CLOSE_STATUS_ERROR;

        }

        return PipeComponentIF.ITERATION_CLOSE_STATUS_OK;
    }

    private int closeComponentSession(SourceIF source, TransferInfo info, LogEntry logEntry) {

        try {
            int retCode;
            logEntry.logMessage(
                "Closing iteration session at Source component",
                this,
                MessageLogger.DEBUG);

            retCode = source.close(info, logEntry);
            if(retCode != PipeComponentIF.ITERATION_CLOSE_STATUS_OK) {

                logEntry.logMessage(
                    "Error closing iteration session at Source component",
                    this,
                    MessageLogger.ERROR);
                return PipeComponentIF.ITERATION_CLOSE_STATUS_ERROR;
            }

        } catch(Exception e) {

            logSessionCloseError(e, "source", source, logEntry);
            return PipeComponentIF.ITERATION_CLOSE_STATUS_ERROR;

        } catch(VirtualMachineError e) {

            logSessionCloseError(e, "source", source, logEntry);
            return PipeComponentIF.ITERATION_CLOSE_STATUS_ERROR;

        }
           
        return PipeComponentIF.ITERATION_CLOSE_STATUS_OK;
    }

    private void logSessionError(Throwable t,
                                 String componentType,
                                 PipeComponentIF component,
                                 String taskDescription,
                                 LogEntry logEntry) {
        if(t instanceof FailTransferException || t instanceof AbortTransferException) {
            logEntry.logMessage(
                "Error while " + taskDescription + " at " + componentType + " component " + component.getName(),
                this,
                MessageLogger.ERROR);
        } else {
            // Log unknown Throwable
            Environment.getInstance().log(
                Utils.getThrowableName(t) + " while " + taskDescription + " at " + componentType + " component "
                + component.getName(), t);
            logEntry.logMessage(
                Utils.getThrowableName(t) + " while " + taskDescription + " at " + componentType + " component "
                + component.getName() + ", see OpenSyncro application log file for details",
                this,
                MessageLogger.ERROR);
        }
       
    }
   
    private void logSessionOpenError(Throwable t,
                                     String componentType,
                                     PipeComponentIF component,
                                     LogEntry logEntry) {
        logSessionError(t, componentType, component, "opening session", logEntry);
    }

    private void logSessionCloseError(Throwable t,
                                      String componentType,
                                      PipeComponentIF component,
                                      LogEntry logEntry) {
        logSessionError(t, componentType, component, "closing session", logEntry);
    }

    private void logPipeExecutionError(Throwable t, String currentTask, LogEntry logEntry) {
        if(!(t instanceof FailTransferException)) {
            Environment.getInstance().log("Exception while executing Pipe, " + currentTask, t);
            logEntry.logMessage(
                Utils.getThrowableName(t) + " while executing Pipe, " + currentTask + ": " + t.getMessage()
                        + ", see OpenSyncro log file for details",
                this,
                MessageLogger.ERROR);
        } else {
            // FailTransferException
            logEntry.logMessage(
                "Error while executing Pipe, " + currentTask + ".",
                this,
                MessageLogger.ERROR);
        }
    }

    private void addLogEntry(LogEntry logEntry, int statusCode) {
        if(this.log == null)
            this.log = new HashSet();
       
        logEntry.setStatusCode(statusCode);
        logEntry.setTime(new Date());
       
               
        // The LogEntry is not explicitly added to the Pipe's log Set, since it causes
        // Hibernate to query all LogEntries from the database and thus consume
        // ever-increasing amount of server resources.

        //this.log.add(logEntry);
        String status = getStatusString(statusCode);
       
        Persister persister = new Persister(database);

        try {
            persister.update(logEntry);

            List messages;
           
            boolean mailAddressNotSet =((getMailHost() == null || getRecipientAddress() == null) ||
                    (getMailHost().length() == 0 || getRecipientAddress().length() == 0));
           
            // Notification via email only if host and email address are present
            if(!mailAddressNotSet&&!(getTransferLogNotificationLevel()==MessageLogger.MAIL_NONE)) {
               

                String date = dateFormat.format(new Date());
                String subject = this.getName() + " " + status + " " + date + " (" + database + ")";
                String message = "";

                // Get number of log messages at or below transferLogNotificationLevel. 
               
                int entries=persister.getLogMessageEntries(logEntry.getId(), getTransferLogNotificationLevel()).size();
               
                //Generate mail message
                if(entries > 0) {
                  
                  messages = persister.getLogMessageEntries(
                             logEntry.getId(),
                             getLoggingVerbosityLevel());
                    for(Iterator m = messages.iterator(); m.hasNext();) {
                        LogMessageEntry messageEntry = (LogMessageEntry) m.next();
                        message += (messageEntry.getMessage()) + "\n";
                    }
                } else {
                    message += MAIL_MESSAGE_NO_ENTRIES;
                }
               
                // Send notification email except when the message is
        // MAIL_MESSAGE_NO_ENTRIES or the pipe has aborted and
                // isAbortMailEnabled()==true
        if (!message.equals(MAIL_MESSAGE_NO_ENTRIES)
            || (statusCode==LogEntry.STATUS_ABORTED && isAbortMailEnabled())) {
          try {

            Properties props = new Properties();
            props.put("mail.host", getMailHost());

            Session mailConnection = Session.getInstance(props,
                null);
            Message msg = new MimeMessage(mailConnection);
            Address sender = new InternetAddress(MAIL_SENDER + "@"
                + getMailHost(), MAIL_SENDER);
            Address[] receivers = receiverAddresses(getRecipientAddress());

            // Set mail content and subject
            msg.setContent(message, "text/plain");
            msg.setFrom(sender);
            msg.setRecipients(Message.RecipientType.TO, receivers);
            msg.setSubject(subject);

            // Send the mail
            Transport.send(msg);

          } catch (MessagingException e) {
            String error = "An error occurred when sending mail report from "
                + MAIL_SENDER
                + "@"
                + getMailHost()
                + " to "
                + getRecipientAddress()
                + ":\n"
                + e.getMessage();
            Environment.getInstance().log(error);
            logEntry.logMessage(error, this, MessageLogger.ERROR);
            persister.update(logEntry);
          } catch (RuntimeException ex) {
            Environment.getInstance().log(
                "A RuntimeException has occurred: "
                    + ex.getMessage()
                    + ex.getStackTrace().toString());
          }
        }
      }
            // Remove unnecessary (debug level) messages from the LogEntry if Transfer log
            // verbosity level is set to DYNAMIC and the current LogEntry's status is either
            // OK or ABORTED
            if(getLoggingVerbosityLevel() == MessageLogger.LOG_DYNAMIC
                    && (statusCode == LogEntry.STATUS_OK || statusCode == LogEntry.STATUS_ABORTED) ) {
                messages = persister.getLogMessageEntries(logEntry.getId(), MessageLogger.DEBUG);
                if(messages.size() > 0) {
                    for(Iterator m = messages.iterator(); m.hasNext();) {
                        LogMessageEntry messageEntry = (LogMessageEntry) m.next();
                        if(messageEntry.getMessageType() == MessageLogger.DEBUG) {
                            persister.delete(messageEntry);
                           
                        }
                    }
                }
            }
        } catch(Exception e) {
            Environment.getInstance().log(e.getMessage());
        } finally {
            persister.close();
        }
    }

    // Utility method for splitting a String of email addresses to an array of JavaMail Addresses
    private Address[] receiverAddresses(String recipientAddress) throws AddressException {
        Address[] addresses = null;

        for(int i = 0; i < MAIL_ADDRESS_DELIMITERS.length; i++) {
            if(recipientAddress.indexOf(MAIL_ADDRESS_DELIMITERS[i]) != -1) {
                String[] separatedAddresses = Utils.split(
                    recipientAddress,
                    MAIL_ADDRESS_DELIMITERS[i]);
                addresses = new Address[separatedAddresses.length];
                for(int j = 0; j < separatedAddresses.length; j++) {

                    addresses[j] = new InternetAddress(separatedAddresses[j]);
                }
                return (addresses);
            }

        }
        addresses = new Address[1];
        addresses[0] = new InternetAddress(recipientAddress);

        return addresses;
    }

    // Returns true if a String array contains a null entry
    private boolean arrayContainsNull(String[] array) {
        for(int k = 0; k < array.length; k++) {
            if(array[k] == null) {
                return true;
            }
        }
        return false;
    }
   
 

  /**Get end time of last pipe execution
   * @return End time of last pipe execution
   */
  public Date getEndTime() {
    return endTime;
  }

  /**Set end time of pipe execution
   * @param endTime
   */
  public void setEndTime(Date endTime) {
    this.endTime = endTime;
  }

  /**Get last pipe execution status
   * @return last pipe execution status
   */
  public String getLastStatus() {
    return lastStatus;
  }

  /**Set last execution status
   * @param lastStatus
   */
  public void setLastStatus(String lastStatus) {
    this.lastStatus = lastStatus;
  }

  /**Get start time of last execution
   * @return Start time of last execution
   */
  public Date getStartTime() {
    return startTime;
  }

  /**Set the start time of execution
   * @param startTime
   */
  public void setStartTime(Date startTime) {
    this.startTime = startTime;
  }
 
  /**Get the duration of last pipe execution
   * @return Duration of last pipe execution
   */
  public Long getDuration() {
    return duration;
  }

  /**Set duration of pipe execution
   * @param duration
   */
  public void setDuration(Long duration) {
    this.duration = duration;
  }

  /**Get the user the pipe was started by
   * @return user Name of the user who started the pipe last
   */
  public String getUser() {
    return user;
  }

  /**Set the user name who started the pipe
   * @param user Name of the user
   */
  public void setUser(String user) {
    this.user = user;
  }
 
  /**
   * Sets some parameters of the pipe to same values as of the given pipe.
   * All parameters, except those relating to last execution info are copied
   *
   * @param pipe The pipe to get the settings from
   */
  public Pipe clone() throws ClassCastException{
    Pipe pipe=new Pipe();
    pipe.setAbortMailEnabled(this.isAbortMailEnabled());
   
    Iterator it=this.getConverterList().iterator();
    List newClist=new LinkedList();
    while(it.hasNext()){
      ConverterListItem cvi=(ConverterListItem)it.next();
      ConverterListItem ci=new ConverterListItem();
      ci.setConverter(cvi.getConverter());
      HashMap cmap=new HashMap(cvi.getConverterData().getAttributes());
      ci.setConverterData(new PipeComponentData(cmap));
      ci.setConverterID(cvi.getConverterID());
      ci.setParent(this);
      newClist.add(ci);
    }
    pipe.setConverterList(newClist);
   
    HashMap dmap=new HashMap();
    if(this.getDestinationData()!=null){
      dmap.putAll(this.getDestinationData().getAttributes());
    }
    pipe.setDestinationData(new PipeComponentData(dmap));
    pipe.setDestinationID(this.getDestinationID());
   
    pipe.setHttpStartEnabled(this.isHttpStartEnabled());
    pipe.setMailHost(this.getMailHost());
    pipe.setName("Copy of "+this.getName());
    pipe.setRecipientAddress(this.getRecipientAddress());
   
    HashMap smap=new HashMap();
    if(this.getSourceData()!=null){
      smap.putAll(this.getSourceData().getAttributes());
    }
    pipe.setSourceData(new PipeComponentData(smap));
    pipe.setSourceID(this.getSourceID());
   
    pipe.setStartPassword(this.getStartPassword());
    pipe.setTransferLogNotificationLevel(this.getTransferLogNotificationLevel());
    pipe.setLoggingVerbosityLevel(this.getLoggingVerbosityLevel());
    return pipe;
   
  }
 
  private void setExecutionEndInfo(Date finish, long duration, int statusCode){
    this.setDuration(duration);
    this.setEndTime(finish);
    this.setLastStatus(getStatusString(statusCode));
  }
 
    private void setExecutionStartInfo(String userName, Date startTime) {
       this.setUser(userName);
      this.setStartTime(startTime);
    }

  private String getStatusString(int statusCode) {
    String status = "";
        switch(statusCode) {
        case LogEntry.STATUS_OK:
            status = LogEntry.STAT_OK;
            break;
        case LogEntry.STATUS_SOURCE_ERROR:
            status = LogEntry.STAT_SOURCE_ERROR;
            break;
        case LogEntry.STATUS_CONVERSION_ERROR:
            status = LogEntry.STAT_CONVERSION_ERROR;
            break;
        case LogEntry.STATUS_DESTINATION_ERROR:
            status = LogEntry.STAT_DESTINATION_ERROR;
            break;
        case LogEntry.STATUS_ABORTED:
            status = LogEntry.STAT_ABORTED;
            break;
        default:
            status = LogEntry.STAT_UNKNOWN;
        }
        return status;
  }
 

}
TOP

Related Classes of smilehouse.opensyncro.pipes.Pipe

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.