Package com.sos.DataExchange

Source Code of com.sos.DataExchange.SOSDataExchangeEngine

/********************************************************* begin of preamble
**
** Copyright (C) 2003-2010 Software- und Organisations-Service GmbH.
** All rights reserved.
**
** This file may be used under the terms of either the
**
**   GNU General Public License version 2.0 (GPL)
**
**   as published by the Free Software Foundation
**   http://www.gnu.org/licenses/gpl-2.0.txt and appearing in the file
**   LICENSE.GPL included in the packaging of this file.
**
** or the
** 
**   Agreement for Purchase and Licensing
**
**   as offered by Software- und Organisations-Service GmbH
**   in the respective terms of supply that ship with this file.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
** IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
** THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
** BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
** POSSIBILITY OF SUCH DAMAGE.
********************************************************** end of preamble*/
package com.sos.DataExchange;
import java.io.IOException;
import java.util.HashMap;
import java.util.Properties;
import java.util.Vector;

import org.apache.log4j.Logger;

import com.sos.JSHelper.Basics.JSJobUtilities;
import com.sos.JSHelper.Basics.JSVersionInfo;
import com.sos.JSHelper.Exceptions.JobSchedulerException;
import com.sos.VirtualFileSystem.DataElements.SOSFileList;
import com.sos.VirtualFileSystem.DataElements.SOSFileListEntry;
import com.sos.VirtualFileSystem.FTP.SOSFTPOptions;
import com.sos.VirtualFileSystem.Factory.VFSFactory;
import com.sos.VirtualFileSystem.Interfaces.ISOSVFSHandler;
import com.sos.VirtualFileSystem.Interfaces.ISOSVfsFileTransfer;
import com.sos.VirtualFileSystem.Interfaces.ISOSVirtualFile;
import com.sos.i18n.I18NBase;
import com.sos.i18n.annotation.I18NMessage;
import com.sos.i18n.annotation.I18NMessages;
import com.sos.i18n.annotation.I18NResourceBundle;

@I18NResourceBundle(baseName = "SOSDataExchange", defaultLocale = "en")
public class SOSDataExchangeEngine extends I18NBase implements JSJobUtilities {
  private final String    conClassName          = "SOSDataExchangeEngine";
  private Logger        logger              = Logger.getLogger(SOSDataExchangeEngine.class);
  private ISOSVFSHandler    objVFS4Target          = null;
  private ISOSVFSHandler    objVFS4Source          = null;
  public ISOSVfsFileTransfer  objDataTargetClient        = null;
  public ISOSVfsFileTransfer  objDataSourceClient        = null;
  private SOSFTPOptions    objOptions            = null;
  private SOSFileList      objSourceFileList        = null;
  private boolean        jump              = false;                      // TODO tempor�r
  private boolean        makeDirs            = false;
  /** This parameter specifies whether zero byte files should be transferred and processed by subsequent jobs. The following settings are available */
  private boolean        zeroByteFiles          = true;
  private boolean        zeroByteFilesStrict        = false;
  private boolean        zeroByteFilesRelaxed      = false;
  /** notification by e-mail in case of transfer of empty files. */
  private String        fileNotificationTo        = "";
  private String        fileNotificationCC        = "";
  private String        fileNotificationBCC        = "";
  private String        fileNotificationSubject      = "";
  private String        fileNotificationBody      = "";
  private String        fileZeroByteNotificationTo    = "";
  private String        fileZeroByteNotificationCC    = "";
  private String        fileZeroByteNotificationBCC    = "";
  private String        fileZeroByteNotificationSubject  = "";
  private String        fileZeroByteNotificationBody  = "";
  private JSJobUtilities    objJSJobUtilities        = this;
  // private boolean sameConnection = false;
  // private int count = 0;
  private int          zeroByteCount          = 0;                        // tempor�r
  // private boolean isFilePath = false;
  private String        state              = "";
  /**
   * Resource filenames for operation = install
   */
  @SuppressWarnings("unused")
  private boolean        testmode            = false;
  @I18NMessages(value = { @I18NMessage("%1$s: Exception raised, reason is: %2$s"), //
      @I18NMessage(value = "%1$s: Exception raised, reason is: %2$s", locale = "en_UK", //
      explanation = "%1$s: Exception raised, cause: %2$s" //
      ), //
      @I18NMessage(value = "%1$s: Ausnahmefehler aufgetreten, Ursache ist vermutlich: %2$s", locale = "de", //
      explanation = "%1$s: Eine Java-Exception mit dem Grund: %2$s ist aufgetreten." //
      ) //
  }, msgnum = "SOS-E-1001", msgurl = "")
  /*!
   * \var EXCEPTION_RAISED
   * \brief %1$s: Exception raised, cause: %2$s
   */
  final String        EXCEPTION_RAISED        = conClassName + ".EXCEPTION_RAISED";
  @I18NMessages(value = { @I18NMessage("could not complete transaction, cause: {0}"), //
      @I18NMessage(value = "could not complete transaction, cause: {0}", locale = "en_UK", //
      explanation = "could not complete transaction, cause: {0}" //
      ), //
      @I18NMessage(value = "Transaktion wurde fehlerhaft abgebrochen, Ursache: {0}", locale = "de", //
      explanation = "Die Transaktion wurde abgebrochen und alle Aktionen r�ckg�ngig gemacht." //
      ) //
  }, msgnum = "SOSDX-E-0002", msgurl = "")
  /*!
   * \var TRANSACTION_ABORTED
   * \brief could not complete transaction, cause: %1$s
   */
  final String        TRANSACTION_ABORTED        = "SOSDataExchangeEngine.TRANSACTION_ABORTED";

  public SOSDataExchangeEngine() throws Exception {
    super("SOSDataExchange");
    init();
  }

  private void init() {
   
    @SuppressWarnings("unused")
    final String  conMethodName  = conClassName + "::init";
   
    logger.info(conClassName + " --- " + JSVersionInfo.getVersionString());
   
  } // private void init
  /**
   * @param settingsFile
   * @param settingsSection
   * @param logger
   * @param arguments_
   */
  public SOSDataExchangeEngine(Properties pobjProperties) throws Exception {
    super();
    this.Options();
    // TODO Properties in die OptionsClasse weiterreichen
//    objOptions.setAllOptions(pobjProperties);
  }

  public SOSDataExchangeEngine(SOSFTPOptions pobjOptions) throws Exception {
    super();
    this.objOptions = pobjOptions;
  }

  public SOSDataExchangeEngine(HashMap<String, String> pobjJSSettings) throws Exception {
    super();
    this.Options();
    objOptions.setAllOptions(pobjJSSettings);
  }

  @SuppressWarnings("unused")
  private ISOSVFSHandler getVFS() throws Exception {
    if (objVFS4Target == null) {
      objVFS4Target = VFSFactory.getHandler(objOptions.getDataTargetType());
    }
    return objVFS4Target;
  }

  public SOSFTPOptions Options() {
    if (objOptions == null) {
      objOptions = new SOSFTPOptions();
    }
    return objOptions;
  }

  public boolean Run() throws Exception {
    @SuppressWarnings("unused")
    final String conMethodName = conClassName + "::Run";
    return this.transfer();
  }

  public boolean Execute() throws Exception {
    @SuppressWarnings("unused")
    final String conMethodName = conClassName + "::execute";
    return this.transfer();
  }

  public ISOSVfsFileTransfer DataSourceClient() {

    @SuppressWarnings("unused")
    final String conMethodName = conClassName + "::DataSourceClient";

    if (objDataSourceClient == null) {
      try {
        objVFS4Source = VFSFactory.getHandler(objOptions.getDataSourceType());
        objVFS4Source.Connect(objOptions.getConnectionOptions().Source());
        objVFS4Source.Authenticate(objOptions.getConnectionOptions().Source());
        objVFS4Source.setSource();
        objVFS4Source.Options(objOptions);
      }
      catch (Exception e) {
        throw new JobSchedulerException("Problems creating/connecting DataSourceClient", e);
      }
    }

    return objDataSourceClient;
  } // private ISOSVfsFileTransfer DataSourceClient

  /**
   *
   * \brief DataTargetClient
   * Returns an instance of the TargetClient
   *
   * \details
   *
   * \return ISOSVfsFileTransfer
   *
   * @return
   * @throws Exception
   */
  public ISOSVfsFileTransfer DataTargetClient() throws Exception {
    @SuppressWarnings("unused")
    final String conMethodName = conClassName + "::DataTarget";
    if (objDataTargetClient == null) {
      objOptions.CheckMandatory();
      objVFS4Target = VFSFactory.getHandler(objOptions.getDataTargetType());
      objVFS4Target.Connect(objOptions.getConnectionOptions().Target());
      objVFS4Target.Authenticate(objOptions.getConnectionOptions().Target());
      objDataTargetClient = (ISOSVfsFileTransfer) objVFS4Target;
      objVFS4Target.setTarget();
      objVFS4Target.Options(objOptions);
    }
    return objDataTargetClient;
  } // private ISOSVfsFileTransfer DataTarget

  /**
   * Send files by FTP/SFTP to a target 
   *
   * @return boolean
   * @throws Exception
   */
  public boolean transfer() throws Exception {
    boolean rc = false;
    try { // to connect, authenticate and execute commands
      Options().CheckMandatory();
      // logger.debug(Options().toString());
      objSourceFileList = new SOSFileList(objVFS4Target);
      objSourceFileList.Options(objOptions);
      objSourceFileList.StartTransaction();
      DataSourceClient();
      DataTargetClient();
      try {
        // objDataTargetClient = (ISOSVfsFileTransfer) objVFS4Target;
        objDataSourceClient = (ISOSVfsFileTransfer) objVFS4Source;
        objSourceFileList.objDataSourceClient = objDataSourceClient;
        objSourceFileList.objDataTargetClient = objDataTargetClient;
        if (objOptions.passive_mode.value()) {
          objDataTargetClient.passive();
          objDataSourceClient.passive();
        }
        objDataTargetClient.TransferMode(objOptions.transfer_mode);
        objDataSourceClient.TransferMode(objOptions.transfer_mode);

        objDataTargetClient.ControlEncoding(objOptions.ControlEncoding.Value());
        objDataSourceClient.ControlEncoding(objOptions.ControlEncoding.Value());

        if (objOptions.PreFtpCommands.IsNotEmpty()) {
          String[] strA = objOptions.PreFtpCommands.Value().split(";");
          for (String strCmd : strA) {
            objDataTargetClient.getHandler().ExecuteCommand(strCmd);
          }
        }

        makeDirs();
        String strSourceDir = objOptions.SourceDir.Value();
        String strRemoteDir = objOptions.TargetDir.Value();
        boolean flgRecurseFolders = objOptions.recursive.value();
        if (objOptions.OneOrMoreSingleFilesSpecified()) {
          objSourceFileList.add(getSingleFileNames(), strSourceDir);
        }
        else {
          String fileSpec = objOptions.file_spec.Value();
          objDataSourceClient.changeWorkingDirectory(strSourceDir);
          ISOSVirtualFile objLocFile = objDataSourceClient.getFileHandle(strSourceDir);
          String strM = "source directory/file: " + strSourceDir + ", target directory: " + strRemoteDir + ", file regexp: " + fileSpec;
          logger.debug(strM);
          if (objLocFile.isDirectory() == true) {
            String[] strFileList = objDataSourceClient.getFilelist(strSourceDir, fileSpec, 0, flgRecurseFolders);
            objSourceFileList.add(strFileList, strSourceDir);
          }
          else {
            objSourceFileList.add(strSourceDir);
          }
        }
        // TODO implement polling for files

        // TODO in Options setzen anhand der Values in der Liste.
        if (zeroByteFiles == false) {
          // TODO in die SOSFileList einbauen (SkipZeroByteFiles)
          for (SOSFileListEntry objEntry : objSourceFileList.List()) {
            String strSourceFileName = objEntry.SourceFileName();
            ISOSVirtualFile objVF = objDataSourceClient.getFileHandle(strSourceFileName);
            if (objVF.FileExists()) {
              if (objVF.isEmptyFile()) {
                objEntry.setTransferSkipped();
                if (objOptions.remove_files.value()) {
                  objVF.delete();
                  objEntry.zeroByteCount++;
                }
              }
            }
            else {
              // TODO Datei (nicht mehr) da? Fehler ausl�sen, weil in Liste enthalten.
            }
          }
        } // (zeroByteFiles == false)
        try {
          sendFiles(objSourceFileList);

          objDataSourceClient.close();
          objDataTargetClient.close();

          objSourceFileList.renameAtomicTransferFiles();
          objSourceFileList.DeleteSourceFiles();
        }
        catch (JobSchedulerException e) {
          e.printStackTrace(System.err);
          String strM = getMsg(TRANSACTION_ABORTED, e.toString());
          if (objOptions.transactional.value()) {
            logger.error(strM, e);
          }
          else {
            logger.error(strM, e);
          }
          objSourceFileList.Rollback();
          throw new JobSchedulerException(strM, e);
        }
        finally {
          objSourceFileList.EndTransaction();
        }
        objSourceFileList.sendMails();
        // TODO in die Klasse SOSFileList oder SOSFtpCommand
        rc = printState(rc);
        // }
        // TODO das mu� beim JobScheduler-Job in die Parameter zur�ck, aber nur da
        // siehe hierzu das Interface ...
        // arguments.put("successful_transfers", String.valueOf(count));
        // return the number of transferred files
        // arguments.put("status", "success");
        return rc;
      }
      catch (Exception e) {
        // arguments.put("status", "error");
        // failed_transfer++;
        // arguments.put("failed_transfers", String.valueOf(failed_transfer));
        rc = false;
        e.printStackTrace(System.err);
        throw (new JobSchedulerException("could not process file transfer: " + e.getMessage()));
      }
      finally {
        if (jump) { // jump host ist angegeben, hier m�ssen z.B. tempor�r generierte Verzeichnisse auf Remote host gel�scht werden
          rc = doPostCommands(rc, objSourceFileList);
        }
      }
    }
    catch (Exception e) {
      e.printStackTrace(System.err);
      logger.error("data transfer failed: ", e);
      // if (sosString.parseToString(logger.getWarning()).length() > 0 || sosString.parseToString(logger.getError()).length() > 0) {
      // //TODO in die Order/Job-Parameter
      // getArguments().put("last_error", logger.getWarning() + " " + logger.getError());
      // }
      // TODO das mu� in die SOSFileList geschoben werden bzw in die SOSFTPCommand
      // writeHistory(localFile != null ? localFile.getAbsolutePath() : "", "");
      throw new JobSchedulerException("processing aborted.", e);
    }
  }

  public void Logout() {
    try {
      if (objDataTargetClient != null) {
        objDataTargetClient.logout();
        objDataTargetClient.disconnect();
        objDataTargetClient = null;
      }
      if (objDataSourceClient != null) {
        objDataSourceClient.logout();
        objDataSourceClient.disconnect();
        objDataSourceClient = null;
      }
    }
    catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }

  // TODO Keep_connection ist nicht dokumentiert. deshalb nicht in der Options-Klasse
  /**
   * Parameter auslesen
   * @throws Exception
   */
  // if (sosString.parseToString(arguments.get("keep_connection")).length() > 0) {
  // String keep = sosString.parseToString(arguments.get("keep_connection"));
  // if (keep.equalsIgnoreCase("true") || keep.equalsIgnoreCase("1")) {
  // keepConnection = true;
  // }
  // else {
  // keepConnection = false;
  // }
  // }
  // else {
  // keepConnection = false;
  // }
  //
  // if (keepConnection) {
  // sameConnection = ftpClient != null && ftpClient.isConnected() && lastHost.equalsIgnoreCase(host) && lastPort == port
  // && lastUser.equalsIgnoreCase(user) && lastAccount.equalsIgnoreCase(account);
  // }
  // if (ftpClient != null && ftpClient.isConnected() && !sameConnection) {
  // try {
  // if (isLoggedIn)
  // ftpClient.logout();
  // ftpClient.disconnect();
  // }
  // catch (Exception e) {
  // }
  // }
  // if (sosString.parseToString(arguments.get("file_zero_byte_transfer")).length() > 0) {
  // if (sosString.parseToString(arguments.get("file_zero_byte_transfer")).equals("1")
  // || sosString.parseToString(arguments.get("file_zero_byte_transfer")).equalsIgnoreCase("true")
  // || sosString.parseToString(arguments.get("file_zero_byte_transfer")).equalsIgnoreCase("yes")) {
  // zeroByteFiles = true;
  // zeroByteFilesStrict = false;
  // }
  // else
  // if (sosString.parseToString(arguments.get("file_zero_byte_transfer")).equalsIgnoreCase("strict")) {
  // zeroByteFiles = false;
  // zeroByteFilesStrict = true;
  // }
  // else
  // if (sosString.parseToString(arguments.get("file_zero_byte_transfer")).equalsIgnoreCase("relaxed")) {
  // zeroByteFiles = false;
  // zeroByteFilesStrict = false;
  // zeroByteFilesRelaxed = true;
  // }
  // else {
  // zeroByteFiles = false;
  // zeroByteFilesStrict = false;
  // }
  // }
  // TODO die notifications sind wohl all enicht dokumentiert mu� nachgeholt werden
  // if (sosString.parseToString(arguments.get("file_notification_to")).length() > 0) {
  // fileNotificationTo = sosString.parseToString(arguments.get("file_notification_to"));
  // }
  //
  // if (sosString.parseToString(arguments.get("file_notification_cc")).length() > 0) {
  // fileNotificationCC = sosString.parseToString(arguments.get("file_notification_cc"));
  // }
  //
  // if (sosString.parseToString(arguments.get("file_notification_bcc")).length() > 0) {
  // fileNotificationBCC = sosString.parseToString(arguments.get("file_notification_bcc"));
  // }
  //
  // if (sosString.parseToString(arguments.get("file_notification_subject")).length() > 0) {
  // fileNotificationSubject = sosString.parseToString(arguments.get("file_notification_subject"));
  // }
  //
  // if (sosString.parseToString(arguments.get("file_notification_body")).length() > 0) {
  // fileNotificationBody = sosString.parseToString(arguments.get("file_notification_body"));
  // }
  //
  // if (sosString.parseToString(arguments.get("file_zero_byte_notification_to")).length() > 0) {
  // fileZeroByteNotificationTo = sosString.parseToString(arguments.get("file_zero_byte_notification_to"));
  // }
  //
  // if (sosString.parseToString(arguments.get("file_zero_byte_notification_cc")).length() > 0) {
  // fileZeroByteNotificationCC = sosString.parseToString(arguments.get("file_zero_byte_notification_cc"));
  // }
  //
  // if (sosString.parseToString(arguments.get("file_zero_byte_notification_bcc")).length() > 0) {
  // fileZeroByteNotificationBCC = sosString.parseToString(arguments.get("file_zero_byte_notification_bcc"));
  // }
  //
  // if (sosString.parseToString(arguments.get("file_zero_byte_notification_subject")).length() > 0) {
  // fileZeroByteNotificationSubject = sosString.parseToString(arguments.get("file_zero_byte_notification_subject"));
  // }
  //
  // if (sosString.parseToString(arguments.get("file_zero_byte_notification_body")).length() > 0) {
  // fileZeroByteNotificationBody = sosString.parseToString(arguments.get("file_zero_byte_notification_body"));
  // }
  // TODO testmode nicht dokumentiert, deshalb nicht in OptionsKlasse
  // testmode = sosString.parseToBoolean(arguments.get("testmode"));
  // TODO die Mail-Options sind nicht dokumentiert.
  // if (sosString.parseToString(arguments.get("mail_smtp")).length() > 0)
  // mailSMTP = (sosString.parseToString(arguments.get("mail_smtp")));
  //
  // if (sosString.parseToString(arguments.get("mail_from")).length() > 0)
  // mailFrom = (sosString.parseToString(arguments.get("mail_from")));
  //
  // if (sosString.parseToString(arguments.get("mail_queue_dir")).length() > 0)
  // mailQueueDir = (sosString.parseToString(arguments.get("mail_queue_dir")));
  // TODO als Default zu den einzelnen Optionen einstellen ....
  // private void getFileNotificationParameter() throws Exception {
  // try {
  // if (fileNotificationTo != null && fileNotificationTo.length() > 0) {
  // if (fileNotificationSubject == null || fileNotificationSubject.length() == 0) {
  // fileNotificationSubject = "[debug1] SOSFTPCommand";
  // }
  //
  // if (fileNotificationBody == null || fileNotificationBody.length() == 0) {
  // fileNotificationBody = "The following files have been sent:\n\n";
  // }
  // }
  //
  // if (fileZeroByteNotificationTo != null && fileZeroByteNotificationTo.length() > 0) {
  // if (fileZeroByteNotificationSubject == null || fileZeroByteNotificationSubject.length() == 0) {
  // fileZeroByteNotificationSubject = "[warning] SOSFTPCommand";
  // }
  //
  // if (fileZeroByteNotificationBody == null || fileZeroByteNotificationBody.length() == 0) {
  // fileZeroByteNotificationBody = "The following files have not been sent and were removed due to zero byte constraints:\n\n";
  // }
  // }
  // }
  // catch (Exception e) {
  // throw new JobSchedulerException("error in  " + sos.util.SOSClassUtil.getMethodName() + " , cause: " + e);
  // }
  // }
  /**
   * Verzeichnis generieren
   * @throws Exception
   */
  private void makeDirs() {
    try {
      boolean cd = true;
      // TODO make_dirs ist nicht dokumentiert.
      // boolean flgMakeDirs = objOptions.make_dirs.Value();
      boolean flgMakeDirs = makeDirs;
      String strTargetDir = objOptions.TargetDir.Value();
      if (flgMakeDirs) {
        if (objDataTargetClient.changeWorkingDirectory(strTargetDir)) {
          cd = true;
        }
        else {
          objDataTargetClient.mkdir(strTargetDir);
          cd = objDataTargetClient.changeWorkingDirectory(strTargetDir);
        }
      }
      else
        if (strTargetDir != null && strTargetDir.length() > 0) {
          cd = objDataTargetClient.changeWorkingDirectory(strTargetDir);
        }
      // TODO alternative_remote_dir, wozu und wie gehen wir damit um?
      if (cd == false && objOptions.alternative_remote_dir.IsNotEmpty()) {// alternative Parameter
        String alternativeRemoteDir = objOptions.alternative_remote_dir.Value();
        logger.debug("..try with alternative parameter [remoteDir=" + alternativeRemoteDir + "]");
        cd = objDataTargetClient.changeWorkingDirectory(alternativeRemoteDir);
        objOptions.TargetDir.Value(alternativeRemoteDir);
      }
    }
    catch (Exception e) {
      throw new JobSchedulerException("..error in makeDirs, cause: " + e);
    }
  } // private void makeDirs()

  // TODO pr�fen, ob eine Verlagerung in SOSFileList die bessere L�sung ist. Stichwort: Multithreading
  private void sendFiles(final SOSFileList pobjFileList) {
    @SuppressWarnings("unused")
    final String conMethodName = conClassName + "::sendFiles";
    int intMaxParallelTransfers = 0;
    if (objOptions.ConcurrentTransfer.value() == true) {
      intMaxParallelTransfers = objOptions.MaxConcurrentTransfers.value();
    }
    Vector<Thread> objThreads = new Vector<Thread>();
    try {
      /**
       * if "sendTransferHistory" is activated due to not thread-safe xml-parser
       * the parallel transfer is omitted.
       */
      if (intMaxParallelTransfers <= 0 || objOptions.SendTransferHistory.value() == true) {
        for (SOSFileListEntry objSourceFile : pobjFileList.List()) {
          objSourceFile.Options(objOptions);
          objSourceFile.run();
        }
      }
      else {
        int intThreadsRunning = 0;
        for (SOSFileListEntry objListItem : pobjFileList.List()) {
          objListItem.Options(objOptions);
          objListItem.setDataSourceClient(null); // force a new connection
          objListItem.setDataTargetClient(null);
          Thread objT = new Thread(objListItem);
          objT.start();
          synchronized (objThreads) {
            objThreads.add(objT);
          }
          boolean flgThreadsActive = true;
          intThreadsRunning = 0;
          while (flgThreadsActive) {
            flgThreadsActive = false;
            synchronized (objThreads) {
              for (Thread thread : objThreads) {
                if (thread.isAlive()) {
                  flgThreadsActive = true;
                  intThreadsRunning++;
                }
              }
            }
            try {
              if (flgThreadsActive == true && intThreadsRunning >= intMaxParallelTransfers) {
                Thread.sleep(500); // TODO this should be an option
              }
              if (intThreadsRunning < intMaxParallelTransfers) {
                break;
              }
            }
            catch (InterruptedException e) {
              e.printStackTrace();
              throw new JobSchedulerException("thread processing interrupted", e);
            }
            catch (Exception e) {
              e.printStackTrace();
              throw new JobSchedulerException("thread processing interrupted", e);
            }
          }
        }
      }
    }
    catch (JobSchedulerException e) {
      throw e;
    }
  }

  // @SuppressWarnings("unused")
  // private void sendFiles2(final SOSFileList pobjFileList) {
  // try {
  // for (SOSFileListEntry objSourceFile : pobjFileList.List()) {
  // File localFile = objSourceFile.getFile();
  // if (localFile == null)
  // continue;
  //
  // String strSourceFileName = objSourceFile.getAbsolutePath();
  // if (objSourceFile.notExists()) {
  // throw new JobSchedulerException(".. file [" + strSourceFileName + "] does not exist ");
  // }
  //
  // if (objSourceFile.polling() == false)
  // continue;
  //
  // File subParent = null;
  // String subPath = "";
  // String strTargetFolderName = objOptions.TargetDir.Value();
  // String localDir = objOptions.SourceDir.Value();
  // boolean recursive = objOptions.recursive.value();
  // if (recursive && objOptions.isFilePath() == false) {
  // // TODO Das Erstellen des Verzeichnis mu� eine separate Methode werden
  // // �berpr�fen, ob das Verzeichnis auf den FTP Server existiert, wenn nicht dann soll das gleiche Verzeichnis generiert
  // // werden
  // if (localFile.getParent() != null && localFile.getParentFile().isDirectory()) { // es existieren Vaterknoten
  // subPath = strSourceFileName.toString().substring((localDir.length() + 1)); // Unterverzeichnisse sind alle
  // // Verzeichnisse unterhalb der localDir
  // subParent = new File(subPath).getParentFile();
  //
  // if (subParent != null) {
  // subPath = subPath.replaceAll("\\\\", "/");
  // subPath = subPath.substring(0, subPath.length() - new File(strSourceFileName.toString()).getName().length() - 1);
  // logger.debug(".. creating sub-directory on remote host: " + subPath);
  // String[] ftpFiles = objDataTargetClient.listNames(strTargetFolderName + "/" + subPath);
  // if (ftpFiles == null || ftpFiles.length == 0) {
  // objDataTargetClient.mkdir(strTargetFolderName + "/" + subPath);
  // }
  // }
  // }
  // }
  //
  // if (zeroByteFiles == false && objSourceFile.isEmptyFile())
  // continue;
  //
  // objSourceFile.getTargetFile(objOptions);
  //
  // if (subParent != null && recursive) {
  // // fleTransferFile = new File((subParent != null ? subParent.getName() + "/" : "") + fleTransferFile.getName());
  // // strTransferFilename = (subParent != null ? subPath + "/" : "") + fleTransferFile.getName();
  // }
  //
  // long bytesSend = 0;
  // String strTargetFileName = objSourceFile.TargetFileName();
  // Vector<String> vecTargetFileNamesList = objDataTargetClient.nList(strTargetFileName);
  // logger.debug("target-server reply [filename exists] [" + strTargetFileName + "]: " + objDataTargetClient.getReplyString());
  //
  // if (objOptions.transactional.value() == true) {
  // objSourceFile.setTransactionalLocalFile();
  // }
  //
  // if (objOptions.DoNotOverwrite()) {
  // if (vecTargetFileNamesList.isEmpty() == false) {
  // objSourceFile.setNotOverwritten();
  // continue;
  // }
  // }
  //
  // if (objOptions.isAtomicTransfer()) {
  // objSourceFile.setStatus(enuTransferStatus.transferring);
  // bytesSend = objDataTargetClient.putFile(objSourceFile.SourceTransferName(), objSourceFile.TargetTransferName());
  //
  // if (objOptions.overwrite_files.value() == true) {
  // // hier werden Dateien gel�scht, vor dem umbenennen.
  // // Besser: auch erstmal umbenennen und dann erst l�schen
  // if (vecTargetFileNamesList.isEmpty() == false && vecTargetFileNamesList.contains(strTargetFileName)) {
  // objDataTargetClient.delete(strTargetFileName);
  // }
  // }
  //
  // // TODO Warum schon hier umbenennen, und nicht erst dann, wenn alle Dateien �bertragen sind? In FileListentry ist das zu
  // // finden
  // if (objOptions.transactional.value() == false) {
  // objDataTargetClient.rename(objSourceFile.TargetTransferName(), objSourceFile.TargetFileName());
  // }
  // }
  // else {
  // objSourceFile.setStatus(enuTransferStatus.transferring);
  // if (objOptions.append_files.value() == true) {
  // bytesSend = objDataTargetClient.appendFile(objSourceFile.SourceTransferName(), objSourceFile.TargetTransferName());
  // }
  // else {
  // bytesSend = objDataTargetClient.putFile(objSourceFile.SourceTransferName(), objSourceFile.TargetTransferName());
  // }
  // }
  // objSourceFile.setNoOfBytesTransferred(bytesSend);
  // objSourceFile.TransferStatus(enuTransferStatus.transferred);
  // // TODO das mu� in die FileEntry-Klasse
  // // writeHistory(fleSourceFile.getAbsolutePath(), fleTransferFile.getAbsolutePath());
  //
  // // TODO das ist eine merkw�rdige Art zu pr�fen
  // // if (objOptions.check_size.value() == true && objSourceFile.length() > 0 && objSourceFile.length() !=
  // // objSourceFile.NoOfBytesTransferred()) {
  // // throw new JobSchedulerException("..error occurred sending file, target file size [" + objSourceFile.length()
  // // + "] does not match number of bytes transferred [" + objSourceFile.NoOfBytesTransferred() + "]");
  // // }
  //
  // if (objOptions.remove_files.value() == true) {
  // objSourceFile.getFile().delete();
  // }
  // }
  //
  // }
  // catch (Exception e) {
  // String strT = "error. unable to send files, cause: " + e;
  // // TODO rollback?
  // logger.error(strT);
  // throw new JobSchedulerException(strT, e);
  // }
  // }
  /**
   * Es wurde ein Jump Host angegeben.
   *
   *  Alle tempor�ren Verzeichnisse auf dem Remote Host sollen gel�scht werden.
   * 
   * @param rc
   * @param filelist
   * @return
   * @throws Exception
   */
  private boolean doPostCommands(boolean rc, SOSFileList filelist) throws Exception {
    final String conMethodName = conClassName + "::doPostCommands";
    try {
      // logger.debug("enter " + sos.util.SOSClassUtil.getMethodName());
      // arguments.put("xx_make_temp_directory_xx", "ok"); //hilfsvariable, wenn dieser key existiert, dann gilt im execute diese
      // Parameter
      // if (!logger.hasWarnings()) {//fehler beim transferieren, also vom jump_host nicht weitersenden
      // if (sosString.parseToString(postCommands).length() > 0) {
      // this.setCommands(postCommands.split(getCommandDelimiter()));
      // if (!execute())
      // throw new JobSchedulerException("error occurred processing command:" + normalizedPassword(postCommands));
      // }
      // }
      // //Auf jeden fall soll das Tempor�re Verzeichnis gel�scht werden
      // //jump_command nicht ausgelesen //
      // String com = sosString.parseToString(arguments.get("jump_command")) + " -operation=remove_temp_directory -input=\"" +
      // tempJumpRemoteDir + "\"";
      // this.setCommands(com.split(getCommandDelimiter()));
      // if (!execute()) {
      // arguments.remove("xx_make_temp_directory_xx");
      // logger.warn("error occurred processing command:" + tempJumpRemoteDir);
      // }
      // arguments.remove("xx_make_temp_directory_xx");
      //
      // if (rc) {
      // //jump_host hat erfolgreich alle Dateien an target_host weitergegeben. Jetzt
      // //k�nnen die lokalen Dateien gel�scht werden, wenn der Parameter remove_files=yes angegeben ist
      // if (!objOptions.transactional.value() && sosString.parseToBoolean(arguments.get("remove_after_jump_transfer"))) {
      // for (int i = 0; i < filelist.List().size(); i++) {
      // File f = new File(sosString.parseToString(filelist.List().get(i)));
      // if (!f.delete()) {
      // throw new JobSchedulerException("..error occurred, could not remove local file: " + f.getAbsolutePath());
      // }
      // else {
      // logger.ebug("removing localfile: " + f.getAbsolutePath());
      // }
      // }
      // arguments.remove("remove_after_jump_transfer");
      // }
      // else {
      // rc = false;
      // }
      // }
      return rc;
    }
    catch (Exception e) {
      throw new JobSchedulerException(String.format(getMsg(EXCEPTION_RAISED), conMethodName, e));
    }
  }

  /**
   * senden von Mails
   * @throws Exception
   */
  /**
   * Statt ein Verzeichnis k�nnen ein oder mehrere - mit semikolen getrennt - dateien zum transferieren angegeben wrden
   * @return
   */
  private String[] getSingleFileNames() {
    final String conMethodName = conClassName + "::getSingleFileNames";
    String filePath = objOptions.file_path.Value();
//    String strPS = System.getProperty("file.separator");
    String strPS = "/";   // standard on FTP/SFTP
    logger.debug("single file(s) specified : " + filePath);
    Vector<String> filelist = new Vector<String>();
    try {
      String localDir = objOptions.SourceDir.Value().trim();
      // TODO separator-char variable as Option
      String[] split = filePath.split(";");
      for (String strT : split) {
        strT = strT.trim();
        if (strT.length() > 0) {
          if (localDir.trim().length() > 0) {
            if (strT.contains("\\") == false && strT.contains("/") == false) {
              /**
               * Problem with folders, when pgs run on Windows, but has to
               * create a path for unix-systems.
               */
              // strT = new File(localDir, strT).getAbsolutePath();
              strT = AddFileSeparator(localDir) + strT;
            }
          }
          filelist.add(strT);
        }
      }
    }
    catch (Exception e) {
      String strM = String.format("error in  %1$s", conMethodName);
      logger.error(strM + e);
      throw new JobSchedulerException(strM, e);
    }
    String[] strA = { "" };
    if (filelist.size() > 0) {
      strA = (String[]) filelist.toArray(new String[filelist.size()]);
    }
    return strA;
  }

  private String AddFileSeparator(final String pstrPathName) {
    String strT = pstrPathName;
    int intL = strT.length();
    if (intL > 0) {
      String strL = strT.substring(intL - 1, intL);
      if (strL.equals("\\") || strL.equals("/")) {
      }
      else {
//        strT += File.separator;
        strT += "/";
      }
    }
    return strT;
  }

  /**
   * Zustand ausgeben. Erst ab log_level 1
   * @param rc
   * @return
   * @throws Exception
   */
  private boolean printState(boolean rc) throws Exception {
    final String conMethodName = conClassName + "::printState";
    try {
      state = "processing successful ended";
      int count = (int) objSourceFileList.SuccessfulTransfers();
      switch (count) {
        case 0:
          if (zeroByteCount > 0 && zeroByteFilesRelaxed) {
            state = "no matching files found, " + zeroByteCount + " zero byte files skipped";
          }
          else
            if (zeroByteCount > 0 && zeroByteFilesStrict) {
              throw new JobSchedulerException("zero byte file(s) found");
            }
            else
              if (objOptions.force_files.value() == true) {
                if (objSourceFileList.List().size() <= 0) {
                  throw new JobSchedulerException("no (matching) files found");
                }
              }
              else {
                state = "no matching files found";
              }
          rc = (objOptions.force_files.value() == false ? true : !zeroByteFilesRelaxed);
          break;
        case 1:
          String strM = "";
          if (zeroByteCount > 0) {
            strM = String.format("%1$d files skipped due to zero byte constraint", zeroByteCount);
          }
          state = "1 file transferred. " + strM;
          rc = true;
          break;
        default:
          state = count + " files transferred" + ((zeroByteCount > 0) ? ", " + zeroByteCount + " files skipped due to zero byte constraint" : "");
          rc = true;
          break;
      }
      logger.info(state);
      return rc;
    }
    catch (Exception e) {
      throw new JobSchedulerException(String.format(EXCEPTION_RAISED, conMethodName, e));
    }
  }

  // TODO install in eine separate Klasse verpacken weil es mit FTP nicht so viel zu tun hat. Vielleicht kann sie ja auch in einem anderen
  // Zusammenhang eingesetzt werden.
  /**
   * @return the state
   */
  public String getState() {
    return state;
  }

  public SOSFileList getFileList() {
    return objSourceFileList;
  }

  /**
   *
   * \brief setJSJobUtilites
   *
   * \details
   * The JobUtilities are a set of methods used by the SSH-Job or can be used be other, similar, job-
   * implementations.
   *
   * \return void
   *
   * @param pobjJSJobUtilities
   */
  public void setJSJobUtilites(JSJobUtilities pobjJSJobUtilities) {
    if (pobjJSJobUtilities == null) {
      objJSJobUtilities = this;
    }
    else {
      objJSJobUtilities = pobjJSJobUtilities;
      // objVFS.setJSJobUtilites(pobjJSJobUtilities);
    }
    logger.debug("objJSJobUtilities = " + objJSJobUtilities.getClass().getName());
  }

  /**
   *
   * \brief replaceSchedulerVars
   *
   * \details
   * Dummy-Method to make sure, that there is always a valid Instance for the JSJobUtilities.
   * \return
   *
   * @param isWindows
   * @param pstrString2Modify
   * @return
   */
  @Override
  public String replaceSchedulerVars(boolean isWindows, String pstrString2Modify) {
    final String conMethodName = conClassName + "::replaceSchedulerVars";
    logger.debug(conMethodName + " as Dummy-call executed. No Instance of JobUtilites specified.");
    return pstrString2Modify;
  }

  /**
   *
   * \brief setJSParam
   *
   * \details
   * Dummy-Method to make shure, that there is always a valid Instance for the JSJobUtilities.
   * \return
   *
   * @param pstrKey
   * @param pstrValue
   */
  @Override
  public void setJSParam(String pstrKey, String pstrValue) {
    final String conMethodName = conClassName + "::setJSParam";
    logger.debug(conMethodName + " as Dummy-call executed. No Instance of JobUtilites specified.");
  }

  @Override
  public void setJSParam(String pstrKey, StringBuffer pstrValue) {
    final String conMethodName = conClassName + "::setJSParam";
    logger.debug(conMethodName + " as Dummy-call executed. No Instance of JobUtilites specified.");
  }

  @Override
  public String myReplaceAll(String pstrSourceString, String pstrReplaceWhat, String pstrReplaceWith) {
    String newReplacement = pstrReplaceWith.replaceAll("\\$", "\\\\\\$");
    return pstrSourceString.replaceAll("(?m)" + pstrReplaceWhat, newReplacement);
  }

  @Override
  public String getCurrentNodeName() {
    return "";
  }
}
TOP

Related Classes of com.sos.DataExchange.SOSDataExchangeEngine

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.