/********************************************************* 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.VirtualFileSystem.DataElements;
import java.io.File;
import java.lang.management.ManagementFactory;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.Properties;
import org.apache.log4j.Logger;
import com.sos.JSHelper.Basics.JSToolBox;
import com.sos.JSHelper.Exceptions.JobSchedulerException;
import com.sos.VirtualFileSystem.FTP.SOSFTPOptions;
import com.sos.VirtualFileSystem.Factory.VFSFactory;
import com.sos.VirtualFileSystem.Interfaces.ISOSFtpOptions;
import com.sos.VirtualFileSystem.Interfaces.ISOSVFSHandler;
import com.sos.VirtualFileSystem.Interfaces.ISOSVfsFileTransfer;
import com.sos.VirtualFileSystem.Interfaces.ISOSVirtualFile;
import com.sos.VirtualFileSystem.Options.SOSConnection2OptionsAlternate;
import com.sos.VirtualFileSystem.zip.SOSVfsZip;
import com.sos.i18n.annotation.I18NResourceBundle;
import com.sos.scheduler.model.SchedulerObjectFactory;
import com.sos.scheduler.model.commands.JSCmdAddOrder;
import com.sos.scheduler.model.objects.Params;
import com.sos.scheduler.model.objects.Spooler;
/**
* <p style="text-align:center">
* <br />---------------------------------------------------------------------------
APL/Software GmbH - Berlin
##### generated by ClaviusXPress (http://www.sos-berlin.com) #########
Montag, 15. Oktober 2007, Klaus.Buettner@sos-berlin.com (KB)
* <br />---------------------------------------------------------------------------
* </p>
* SOSFileListEntry - Datenstruktur f�r Dateiverarbeitung
* <p>
* Diese Klasse rep�sentiert eine Datenstruktur f�r die Dateiverarbeitung
* von lokalen und remote Dateien.
* </p>
* <p>
* Verwendung findet diese Struktur beim download von Dateien, deren Name
* �ber einen (regul�ren) Ausdruck definiert ist und dabei dann mehr als
* eine Datei relevant ist.
* </p>
* @author Klaus.Buettner@sos-berlin.com
* @version 0.9
* @see reference
* @exception classname description
*
*/
@I18NResourceBundle(baseName = "SOSVirtualFileSystem", defaultLocale = "en")
public class SOSFileListEntry extends JSToolBox implements Runnable /* , ISOSVirtualFile */{
private static String conClassName = "SOSFileListEntry";
private Logger logger = Logger.getLogger(SOSFileListEntry.class);
private boolean flgNoDataSent = false;
private ISOSVirtualFile fleSourceTransferFile = null;
private ISOSVirtualFile fleSourceFile = null;
private ISOSVirtualFile fleTargetFile = null;
private String strSourceFileName = null;
private String strSourceTransferName = null;
private String strTargetTransferName = null;
private String strTargetFileName = null;
private long lngNoOfBytesTransferred = 0;
private long lngFileSize = -1L;
private String strZipFileName = "";
private long lngTransferProgress = 0;
private boolean flgTransactionalRemoteFile = false;
private boolean flgTransactionalLocalFile = false;
public long zeroByteCount = 0;
private long lngOriginalFileSize = 0;
@SuppressWarnings("unused")
private boolean flgTransferSkipped = false;
// private JSFile objFile = null;
private SOSFTPOptions objOptions = null;
private String strAtomicFileName = EMPTY_STRING;
private enuTransferStatus eTransferStatus = enuTransferStatus.transferUndefined;
public enum enuTransferStatus {
transferUndefined, waiting4transfer, transferring, transferInProgress, transferred, transfer_skipped, transfer_has_errors, transfer_aborted, compressed, notOverwritten, deleted, renamed, IgnoredDueToZerobyteConstraint, setBack, polling
}
private ISOSVfsFileTransfer objDataSourceClient = null;
private ISOSVfsFileTransfer objDataTargetClient = null;
private ISOSVirtualFile objTargetTransferFile = null;
private ISOSVirtualFile objSourceTransferFile = null;
private SOSFileList objParent = null;
private boolean flgFileExists = false;
private String strMD5Hash = "n.a.";
@SuppressWarnings("unused")
private Date dteStartTransfer = null;
@SuppressWarnings("unused")
private Date dteEndTransfer = null;
@SuppressWarnings("unused")
private ISOSVfsFileTransfer objVfsHandler = null;
private long guid = System.currentTimeMillis(); // unique id for each file
/**
* \brief getobjDataSourceClient
*
* \details
* getter
*
* @return the objDataSourceClient
*/
public ISOSVfsFileTransfer getDataSourceClient() {
return objDataSourceClient;
}
/**
* \brief setobjDataSourceClient -
*
* \details
* setter
*
* @param objDataSourceClient the value for objDataSourceClient to set
*/
public void setDataSourceClient(ISOSVfsFileTransfer pobjDataSourceClient) {
this.objDataSourceClient = pobjDataSourceClient;
}
/**
* \brief getobjDataTargetClient
*
* \details
* getter
*
* @return the objDataTargetClient
*/
public ISOSVfsFileTransfer getDataTargetClient() {
return objDataTargetClient;
}
/**
* \brief setobjDataTargetClient -
*
* \details
* setter
*
* @param objDataTargetClient the value for objDataTargetClient to set
*/
public void setDataTargetClient(ISOSVfsFileTransfer objDataTargetClient) {
this.objDataTargetClient = objDataTargetClient;
}
public void VfsHandler(final ISOSVfsFileTransfer pobjVfs) {
this.objVfsHandler = pobjVfs;
}
public SOSFileListEntry() {
}
public void setParent(SOSFileList objFileList) {
this.objParent = objFileList;
this.objDataSourceClient = objParent.objDataSourceClient;
this.objDataTargetClient = objParent.objDataTargetClient;
if (objDataSourceClient != null) {
lngOriginalFileSize = objDataSourceClient.getFileHandle(strSourceFileName).getFileSize();
lngFileSize = lngOriginalFileSize;
}
}
public String SourceTransferName() {
return strSourceTransferName;
}
public String TargetTransferName() {
return strTargetTransferName;
}
// public ISOSVirtualFile getFile() {
//
// @SuppressWarnings("unused")
// final String conMethodName = conClassName + "::getFile";
//
// checkFilehandle();
// return objFile;
// } // private File getFile
public String getZipFileName() {
@SuppressWarnings("unused")
final String conMethodName = conClassName + "::getZipFileName";
return strZipFileName;
} // private String getZipFileName
// private ISOSVirtualFile checkFilehandle() {
//
// @SuppressWarnings("unused")
// final String conMethodName = conClassName + "::checkFilehandle";
//
// if (objFile == null) {
// objFile = new JSFile(strSourceFileName);
// lngFileSize = objFile.length();
// }
//
// return objFile;
// } // private JSFile checkFilehandle
// public boolean notExists() {
//
// @SuppressWarnings("unused")
// final String conMethodName = conClassName + "::notExists";
//
// return checkFilehandle().exists() == false;
// } // private boolean notExists
// public long length() {
//
// @SuppressWarnings("unused")
// final String conMethodName = conClassName + "::exists";
//
// return checkFilehandle().length();
// } // private boolean exists
// public String getAbsolutePath() {
//
// @SuppressWarnings("unused")
// final String conMethodName = conClassName + "::getAbsolutePath";
//
// return checkFilehandle().getAbsolutePath();
// } // private String getAbsolutePath
//
// public String getName() {
//
// @SuppressWarnings("unused")
// final String conMethodName = conClassName + "::getName";
//
// return checkFilehandle().getName();
// } // private String getAbsolutePath
// public boolean delete() {
//
// @SuppressWarnings("unused")
// final String conMethodName = conClassName + "::delete";
//
// if (checkFilehandle().delete() == false) {
// // TODO Fehlerstatus setzen und im Protokoll drauf hinweisen. �bertragung abbrechen ? Hierbei wohl nicht, oder?
// throw new RuntimeException("..error occurred, could not remove local file: " + this.getAbsolutePath());
// }
// else {
// logger.debug("file deleted: " + this.getAbsolutePath());
// }
//
// return true;
// } // private String delete
public enuTransferStatus getTransferStatus() {
@SuppressWarnings("unused")
final String conMethodName = conClassName + "::getTransferStatus";
return eTransferStatus;
} // private enuTransferStatus getTransferStatus
public void TransferStatus(final enuTransferStatus peTransferStatus) {
@SuppressWarnings("unused")
final String conMethodName = conClassName + "::TransferStatus";
this.setStatus(peTransferStatus);
} // private void TransferStatus
public void setTransferSkipped() {
@SuppressWarnings("unused")
final String conMethodName = conClassName + "::setTransferSkipped";
this.eTransferStatus = enuTransferStatus.transfer_skipped;
logger.debug(String.format("transfer skipped for file %1$s ", this.strSourceFileName));
} // private void TransferStatus
public void setNotOverwritten() {
@SuppressWarnings("unused")
final String conMethodName = conClassName + "::setNotOverwritten";
this.eTransferStatus = enuTransferStatus.notOverwritten;
logger.debug(String.format("transfer skipped for file %1$s due to overwrite constraint", this.strSourceFileName));
} // private void TransferStatus
public String TargetFileName() {
@SuppressWarnings("unused")
final String conMethodName = conClassName + "::TargetFileName";
return strTargetFileName;
} // private String TargetFileName
public void NoOfBytesTransferred(final long plngNoOfBytesTransferred) {
@SuppressWarnings("unused")
final String conMethodName = conClassName + "::NoOfBytesTransferred";
this.lngNoOfBytesTransferred = plngNoOfBytesTransferred;
logger.info("number of bytes transferred : " + plngNoOfBytesTransferred);
} // private void NoOfBytesTransferred
public void setTransactionalRemoteFile() {
@SuppressWarnings("unused")
final String conMethodName = conClassName + "::setTransactionalRemoteFile";
this.flgTransactionalRemoteFile = true;
} // private void setTransactionalRemoteFile
public boolean getTransactionalLocalFile() {
return flgTransactionalLocalFile;
}
public void setTransactionalLocalFile() {
@SuppressWarnings("unused")
final String conMethodName = conClassName + "::setTransactionalRemoteFile";
this.flgTransactionalLocalFile = true;
} // private void setTransactionalRemoteFile
public ISOSVirtualFile getTargetFile(final ISOSFtpOptions objO) {
fleSourceTransferFile = null;
fleSourceFile = objDataSourceClient.getFileHandle(strSourceFileName);
fleTargetFile = null;
// first assumption: localfilename and localTransferfileName are identical
strSourceTransferName = fleSourceFile.getName();
// second assumption: localfilename and TargetFileName are equal (until it changed)
strTargetFileName = fleSourceFile.getName();
if (objO.getcompress_files().value() == true) { // compress file before sending
strSourceTransferName = fleSourceFile.MakeZIPFile(objO.getcompressed_file_extension().Value());
strTargetFileName = strTargetFileName + objO.getcompressed_file_extension().Value();
}
strTargetFileName = getFileNameWithoutPath(strTargetFileName);
strTargetTransferName = strTargetFileName;
if (objO.getreplacing().IsNotEmpty()) {
try {
strTargetFileName = objO.getreplacing().doReplace(strTargetFileName, objO.getreplacement().Value());
}
catch (Exception e) {
e.printStackTrace(System.err);
logger.error(e.getLocalizedMessage(), new JobSchedulerException("getreplacing().doReplace aborted with an exception", e));
}
// String currPath = "";
// String strParent = fleSourceTransferFile.getParent();
// if (isNotEmpty(strParent)) {
// currPath = normalized(strParent);
// }
// strSourceTransferName = new File(currPath + currTransferFilename).getName();
// ? logger.debug("source filename [" + this.SourceFileName() + "] will transferred to: " + strTargetFileName);
}
if (objO.getatomic_prefix().IsNotEmpty() || objO.getatomic_suffix().IsNotEmpty()) {
setTransactionalRemoteFile();
strTargetTransferName = MakeAtomicFileName(objO);
}
return null;
}
private String MakeFileNameReplacing(final String pstrFileName) {
String strR = pstrFileName.replaceAll("\\\\", "/"); // avoid trouble with regexp-groups
String strReplaceWith = objOptions.getreplacement().Value();
try {
strR = objOptions.getreplacing().doReplace(strR, strReplaceWith);
}
catch (Exception e) {
e.printStackTrace(System.err);
logger.error(e.getLocalizedMessage(), new JobSchedulerException("getreplacing().doReplace aborted with an exception", e));
}
return strR;
}
private String getFileNameWithoutPath(final String pstrTargetFileName) {
String strT = pstrTargetFileName;
if (strT.contains("\\")) {
strT = strT.replaceAll("\\\\", "/");
}
String[] strA = strT.split("/");
strT = strA[strA.length - 1];
return strT;
}
protected String normalized(String str) {
str = str.replaceAll("\\\\", "/");
return (str.endsWith("/") || str.endsWith("\\") ? str : str + "/");
}
/**
*
* \brief MakeAtomicFileName
*
* \details
* This Method creates a intermediate File-Name, which is used on the target as the first filename
* After successfull completion of the whole transfer, this name will be renamed to the
* final targetFileName.
*
* An intermediate filename is mostly used to avoid that a file-trigger on the target-host
* will react to early on the transfer.
*
* \return the intermediate filename (without foldername) on the target-host
*
* @param ISOSFtpOptions.objO
* @return intermediate TargetTransferFileName
*/
public String MakeAtomicFileName(final ISOSFtpOptions objO) {
@SuppressWarnings("unused")
final String conMethodName = conClassName + "::MakeAtomicFileName";
String strAtomicSuffix = objO.getatomic_suffix().Value();
String strAtomicPrefix = objO.getatomic_prefix().Value();
// if (this.flgTransactionalRemoteFile) {
strTargetTransferName = strTargetFileName + strAtomicSuffix.trim();
strTargetTransferName = strAtomicPrefix + strTargetTransferName;
strAtomicFileName = strTargetTransferName;
// }
return strTargetTransferName.trim();
} // private String MakeAtomicFileName
public void DeleteSourceFile() {
objDataSourceClient.getFileHandle(strSourceFileName).delete();
logger.info(String.format("Source-File %1$s deleted", strSourceFileName));
}
public void setStatus(final enuTransferStatus peTransferStatus) {
@SuppressWarnings("unused")
final String conMethodName = conClassName + "::setStatus";
String strM = "";
this.eTransferStatus = peTransferStatus;
switch (peTransferStatus) {
case transferInProgress:
strM = "processing in progress";
break;
case waiting4transfer:
strM = "waiting for processing";
// TODO Message senden
break;
case transfer_skipped:
dteEndTransfer = Now();
strM = "processing skipped";
// TODO Message senden
break;
case transferring:
strM = "processing started";
dteStartTransfer = Now();
// TODO Message senden
break;
case transferred:
strM = "processing normal end";
dteEndTransfer = Now();
// TODO Message senden
break;
case transfer_aborted:
strM = "processing abnormal end";
dteEndTransfer = Now();
// TODO Message senden
break;
default:
break;
}
if (isNotEmpty(strM)) {
// TODO send not only transferred - messages. make it customizable
if (objOptions.SendTransferHistory.value() == true) {
if (objOptions.transactional.value() == false && peTransferStatus == enuTransferStatus.transferred) {
sendTransferHistory();
}
}
switch (peTransferStatus) {
case transferInProgress:
logger.debug(String.format("%1$s for file %2$s, actual %3$,d bytes", strM, strSourceFileName, lngTransferProgress));
break;
default:
logger.debug(String.format("%1$s for file %2$s", strM, strSourceFileName));
break;
}
}
} // private void TransferStatus
public void Log4Debug() {
logger.debug("SourceFileName = " + this.SourceFileName());
logger.debug("SourceTransferFileName = " + this.SourceTransferName());
logger.debug("TargetTransferFileName = " + this.TargetTransferName());
logger.debug("TargetFileName = " + this.TargetFileName());
}
public SOSFileListEntry(String pstrLocalFileName) {
this("", pstrLocalFileName, 0);
}
public SOSFileListEntry(String pstrRemoteFileName, String pstrLocalFileName, long plngNoOfBytesTransferred) {
strTargetFileName = pstrRemoteFileName;
strSourceFileName = pstrLocalFileName;
lngNoOfBytesTransferred = plngNoOfBytesTransferred;
// this.setStatus(enuTransfesrStatus.waiting4transfer);
}
public String toString() {
String strT = String.format("Operation = %4$s, TargetFile = %1$s, SourceFile = %2$s, BytesTransferred = %3$s", this.RemoteFileName(),
this.SourceFileName(), this.NoOfBytesTransferred(), objOptions.operation.Value());
return strT;
}
public String toCsv() {
String strT = String.format("TargetFile = %1$s, SourceFile = %2$s, BytesTransferred = %3$s", this.RemoteFileName(), this.SourceFileName(),
this.NoOfBytesTransferred());
return strT;
}
public String RemoteFileName() {
return strTargetFileName;
}
public void setRemoteFileName(String pstrRemoteFileName) {
this.strTargetFileName = pstrRemoteFileName;
}
public String SourceFileName() {
return strSourceFileName;
}
public void setSourceFileName(String pstrLocalFileName) {
this.strSourceFileName = pstrLocalFileName;
}
public long NoOfBytesTransferred() {
return lngNoOfBytesTransferred;
}
/**
*
* \brief setNoOfBytesTransferred
*
* \details
* This Method must be called only at the end of the transfer.
* Otherwise a call would result in a "FileSize"-Exception.
*
* \return void
*
* @param plngNoOfBytesTransferred
*/
public void setNoOfBytesTransferred(long plngNoOfBytesTransferred) {
this.lngNoOfBytesTransferred = plngNoOfBytesTransferred;
if (lngFileSize <= 0) { // if the file is compressed, then the original filesize may be to big
lngFileSize = objDataSourceClient.getFileHandle(strSourceFileName).getFileSize();
}
if (lngFileSize != plngNoOfBytesTransferred) {
logger.error(String.format("File-Size failure for file '%3$s'. No of bytes transferred '%1$d', size of file is '%2$d'", plngNoOfBytesTransferred,
lngFileSize, strSourceFileName), new JobSchedulerException("FileSize"));
this.setStatus(enuTransferStatus.transfer_aborted);
throw new JobSchedulerException("FileSize");
}
if (lngOriginalFileSize != plngNoOfBytesTransferred) {
logger.error(String.format("File-Size failure. No of bytes transferred '%1$d', original size of file '%2$d'", plngNoOfBytesTransferred,
lngOriginalFileSize), new JobSchedulerException("FileSize"));
this.setStatus(enuTransferStatus.transfer_aborted);
throw new JobSchedulerException("FileSize");
}
this.setStatus(enuTransferStatus.transferred);
// TODO Message "transferCompleted absetzen"
}
/**
* \brief setlngTransferProgress -
*
* \details
* setter
*
* @param lngTransferProgress the value for lngTransferProgress to set
*/
public void setTransferProgress(long plngTransferProgress) {
this.lngTransferProgress = plngTransferProgress;
this.setStatus(enuTransferStatus.transferInProgress);
String lstrTargetFileName = strTargetFileName;
if (objDataTargetClient.getHandler() instanceof SOSVfsZip) {
lstrTargetFileName = String.format("%1$s(%2$s)", objOptions.remote_dir.Value(), strTargetFileName);
}
logger.info(String.format("%1$,d bytes for file '%2$s' transferred to '%3$s'", lngTransferProgress, strSourceFileName, lstrTargetFileName));
}
/**
* \brief getlngTransferProgress
*
* \details
* getter
*
* @return the lngTransferProgress
*/
public long getTransferProgress() {
return lngTransferProgress;
}
public void StartTransfer() {
this.setStatus(enuTransferStatus.transferring);
}
public void EndTransfer(final long plngNoOfBytesTransferred) {
this.setNoOfBytesTransferred(plngNoOfBytesTransferred);
this.EndTransfer();
}
public void EndTransfer() {
this.setStatus(enuTransferStatus.transferred);
}
public void Options(final SOSFTPOptions pobjOptions) {
@SuppressWarnings("unused")
final String conMethodName = conClassName + "::Options";
this.objOptions = pobjOptions;
} // private void Options
// TODO polling �ber die File-Gr��e
/**
* Diese Routine pr�ft *nur* auf dem lokalen fileSystem und ist aus der "Send"-Klasse kopiert.
* hier hat sie nichts zu suchen, da das polling f�r dateien in der Engine erfolgen muss,
* unabh�ngig davon, wo die Dateien liegen. Es mu� *immer* die Datasource gepollt werden.
*
* Auf alle F�lle mu� hier �ber das Vfs auf die Datei(en) zugegriffen werden.
*/
public boolean CheckFileSizeIsChanging() throws Exception {
@SuppressWarnings("unused")
final String conMethodName = conClassName + "::polling";
String lastmd5file = "";
String message = "";
try {
// TODO TransferStatus "polling" einbauen
String fileName = strSourceFileName;
if (objOptions.poll_timeout.value() > 0 && isNotEmpty(fileName)) {
setStatus(enuTransferStatus.polling);
double delay = objOptions.poll_interval.value();
double nrOfTries = (objOptions.poll_timeout.value() * 60) / delay;
int tries = 0;
boolean found = true;
logger.info("polling for file: " + fileName);
// TODO in die Implementation des ISOSVirtualFile verschieben
File fleFile = new File(fileName);
// TODO �ber Option auf FileSize ausweichen, da MD5 bei gro�en dateien eine ziemliche Last erzeugt
lastmd5file = sos.util.SOSCrypt.MD5encrypt(fleFile);
Thread.sleep((long) delay * 1000);
for (int i = 0; i < nrOfTries; i++) {
tries++;
String newMD5File = sos.util.SOSCrypt.MD5encrypt(fleFile);
logger.debug(i + " polling and checking md5 hash: " + newMD5File);
if (!lastmd5file.equals(newMD5File)) {
lastmd5file = newMD5File;
logger.info("polling for file ..." + fileName);
Thread.sleep((long) delay * 1000);
if (i + 1 == nrOfTries) {
found = false;
message = message + " " + fileName;
}
}
else {
break;
}
}
if (!found) {
message = "During triggering for " + objOptions.poll_timeout.value() + " minutes the file " + message + " has been changed repeatedly";
if (objOptions.force_files.value() == true) {
logger.error(message);
throw new JobSchedulerException(message);
}
else {
logger.info(message);
return false;
}
}
}
return true;
}
catch (Exception e) {
throw new JobSchedulerException("error in " + conMethodName + " error while polling, cause: " + e);
}
}
// Runnable
@Override
public void run() {
@SuppressWarnings("unused")
final String conMethodName = conClassName + "::run";
boolean flgNewConnectionUsed = false;
try {
logger.debug("thread is starting...");
ISOSVFSHandler objVFS4Source = null;
ISOSVFSHandler objVFS4Target = null;
if (objDataSourceClient == null) {
flgNewConnectionUsed = true;
objVFS4Source = VFSFactory.getHandler(objOptions.getDataSourceType());
objVFS4Source.setSource();
objVFS4Source.Connect(objOptions.getConnectionOptions().Source());
objVFS4Source.Authenticate(objOptions);
objDataSourceClient = (ISOSVfsFileTransfer) objVFS4Source;
objVFS4Source.setSource();
objVFS4Source.Options(objOptions);
}
if (objDataTargetClient == null) {
flgNewConnectionUsed = true;
objVFS4Target = VFSFactory.getHandler(objOptions.getDataTargetType());
objVFS4Target.setTarget();
objVFS4Target.Connect(objOptions.getConnectionOptions().Target());
objVFS4Target.Authenticate(objOptions);
objDataTargetClient = (ISOSVfsFileTransfer) objVFS4Target;
objVFS4Target.setTarget();
objVFS4Target.Options(objOptions);
}
ISOSVirtualFile objSourceFile = objDataSourceClient.getFileHandle(strSourceFileName);
if (objSourceFile.notExists() == true) {
throw new JobSchedulerException(".. file '" + strSourceFileName + "' does not exist ");
}
/**
* hier nicht verwenden, weil es zu sp�t kommt.
*/
// if (CheckFileSizeIsChanging() == false) {
// // TODO Exception ausl�sen
// return;
// }
if (objOptions.TransferZeroByteFiles() == false && objSourceFile.isEmptyFile()) {
this.TransferStatus(enuTransferStatus.transfer_skipped);
return;
}
File subParent = null;
String subPath = "";
String strTargetFolderName = objOptions.TargetDir.Value();
String localDir = objOptions.SourceDir.Value();
boolean recursive = objOptions.recursive.value();
if (recursive) {
// TODO Das Erstellen des Verzeichnis mu� eine separate Methode werden
// �berpr�fen, ob das Verzeichnis auf den Target (-Server) existiert, wenn nicht dann soll das gleiche Verzeichnis generiert
// werden
if (objSourceFile.getParentVfs() != null && objSourceFile.getParentVfsFile().isDirectory()) {
subPath = strSourceFileName.substring((localDir.length() + 1)); // Unterverzeichnisse sind alle Verzeichnisse unterhalb
// der localDir
subParent = new File(subPath).getParentFile();
if (subParent != null) {
subPath = subPath.replaceAll("\\\\", File.separator);
subPath = subPath.substring(0, subPath.length() - new File(strSourceFileName.toString()).getName().length() - 1);
logger.debug(".. creating sub-directory on data-target: " + subPath);
String[] ftpFiles = objDataTargetClient.listNames(strTargetFolderName + "/" + subPath);
if (ftpFiles == null || ftpFiles.length == 0) {
objDataTargetClient.mkdir(strTargetFolderName + File.separator + subPath);
}
}
}
}
this.getTargetFile(objOptions); // TODO Namen �ndern
// if (subParent != null && recursive) {
// // fleTransferFile = new File((subParent != null ? subParent.getName() + "/" : "") + fleTransferFile.getName());
// // strTransferFilename = (subParent != null ? subPath + "/" : "") + fleTransferFile.getName();
// }
if (objOptions.transactional.value() == true) {
this.setTransactionalLocalFile();
}
String strOp = objOptions.operation.Value();
if (strOp.equalsIgnoreCase("delete")) {
objSourceFile.delete();
logger.debug(String.format("filename '%1$s' deleted", strSourceFileName));
this.setStatus(enuTransferStatus.deleted);
return;
}
if (strOp.equalsIgnoreCase("rename")) {
String strNewFileName = MakeFileNameReplacing(strSourceFileName);
logger.debug(String.format("filename %1$s, renamed to %2$s", strSourceFileName, strNewFileName));
objSourceFile.rename(strNewFileName);
this.setStatus(enuTransferStatus.renamed);
return;
}
ISOSVirtualFile objTargetFile = objDataTargetClient.getFileHandle(MakeFullPathName(objOptions.TargetDir.Value(), strTargetFileName));
if (strTargetFileName.equalsIgnoreCase(strTargetTransferName) == false) {
objTargetTransferFile = objDataTargetClient.getFileHandle(MakeFullPathName(objOptions.TargetDir.Value(), strTargetTransferName));
}
else {
objTargetTransferFile = objTargetFile;
}
if (objOptions.compress_files.value() == true) {
objSourceTransferFile = objDataSourceClient.getFileHandle(strSourceTransferName);
this.lngFileSize = objSourceTransferFile.getFileSize();
lngOriginalFileSize = this.lngFileSize;
}
else {
strSourceTransferName = getFileNameWithoutPath(strSourceTransferName);
objSourceTransferFile = objDataSourceClient.getFileHandle(MakeFullPathName(objOptions.SourceDir.Value(), strSourceTransferName));
}
this.flgFileExists = objTargetFile.FileExists();
if (objOptions.DoNotOverwrite() && flgFileExists == true) {
logger.debug("data-target(-server) reply [filename exists] [" + strTargetFileName + "]: " + objDataTargetClient.getReplyString());
this.setNotOverwritten();
return;
}
/*
* Hier kann �ber die Streams auch, ohne Zwischendatei, von einem Server
* zum anderen, der Transfer stattfinden. Input = Server1, Output = Server2.
* Es ist damit auch ein Server2Server f�r FTP (SFTP und FTPs??) m�glich.
*
* Es gibt f�r FTP auch die andere M�glichkeit �ber Server2Server, siehe apache-Klassen.
*/
// InputStream objInputStream = objSourceTransferFile.getFileInputStream();
// OutputStream objOutputStream = null;
// if (objOptions.append_files.value() == true) {
// objOutputStream = objTargetTransferFile.getFileAppendStream();
// }
// else {
// objOutputStream = objTargetTransferFile.getFileOutputStream();
// }
// this.doTransfer(objInputStream, objOutputStream);
this.doTransfer(objSourceTransferFile, objTargetTransferFile);
if (objOptions.isAtomicTransfer()) {
if (objOptions.transactional.value() == false) {
if (objOptions.overwrite_files.value() == true & flgFileExists == true) {
// hier werden Dateien gel�scht, vor dem umbenennen.
// Besser: auch erstmal umbenennen und dann erst l�schen
objTargetFile.delete();
}
objTargetTransferFile.rename(MakeFullPathName(objOptions.TargetDir.Value(), this.TargetFileName()));
}
}
if (flgNewConnectionUsed == true) {
objDataSourceClient.logout();
objDataSourceClient.disconnect();
objDataTargetClient.logout();
objDataTargetClient.disconnect();
}
}
catch (Exception e) {
String strT = "error. unable to transfer data, reason: " + e;
e.printStackTrace(System.err);
// TODO rollback?
logger.error(strT);
throw new JobSchedulerException(strT, e);
}
}
private void RaiseException(final String pstrM) {
this.TransferStatus(enuTransferStatus.transfer_aborted);
logger.error(pstrM);
throw new JobSchedulerException(pstrM);
}
@SuppressWarnings("null")
// private long doTransfer(final InputStream objInput, final OutputStream objOutput) {
private long doTransfer(final ISOSVirtualFile objInput, final ISOSVirtualFile objOutput) {
@SuppressWarnings("unused")
final String conMethodName = conClassName + "::doTransfer";
boolean flgClosingDone = false;
if (objOutput == null) {
RaiseException("virtual Target File has null value.");
}
if (objInput == null) {
RaiseException("virtual source file has null value.");
}
boolean flgCreateSecurityHash = objOptions.CreateSecurityHash.value();
MessageDigest md = null;
if (flgCreateSecurityHash) {
try {
// TODO implement in value-method of securityhashtype
md = MessageDigest.getInstance(objOptions.SecurityHashType.Value());
}
catch (NoSuchAlgorithmException e1) {
e1.printStackTrace();
flgCreateSecurityHash = false;
}
}
long lngTotalBytesTransferred = 0;
this.setStatus(enuTransferStatus.transferring);
try {
int lngBufferSize = objOptions.BufferSize.value();
byte[] buffer = new byte[lngBufferSize];
int intBytesTransferred;
synchronized (this) {
while ((intBytesTransferred = objInput.read(buffer)) != -1) {
try {
objOutput.write(buffer, 0, intBytesTransferred);
}
catch (JobSchedulerException e) {
break;
}
// TODO in case of wrong outputbuffer tha handling of the error must be improved
lngTotalBytesTransferred += intBytesTransferred;
setTransferProgress(lngTotalBytesTransferred);
if (flgCreateSecurityHash) {
md.update(buffer, 0, intBytesTransferred);
}
}
}
objInput.closeInput();
objOutput.closeOutput();
flgClosingDone = true;
if (flgCreateSecurityHash) {
strMD5Hash = toHexString(md.digest());
logger.info(String.format("Security hash (%3$s) for file %2$s is %1$s", strMD5Hash, strSourceTransferName, objOptions.SecurityHashType.Value()));
}
// objDataTargetClient.CompletePendingCommand();
if (objDataTargetClient.isNegativeCommandCompletion()) {
RaiseException("..error occurred during transfer on the data-target for file [" + objTargetTransferFile.getName() + "]: "
+ objDataTargetClient.getReplyString());
}
// objDataSourceClient.CompletePendingCommand();
if (objDataSourceClient.isNegativeCommandCompletion()) {
RaiseException("..error occurred during transfer on the data-source for file [" + objSourceTransferFile.getName() + "]: "
+ objDataSourceClient.getReplyString());
}
this.setNoOfBytesTransferred(lngTotalBytesTransferred);
// this.TransferStatus(enuTransferStatus.transferred);
return lngTotalBytesTransferred;
}
catch (Exception e) {
RaiseException(e, "transfer aborted with an exception");
}
finally {
if (flgClosingDone == false) {
objInput.closeInput();
objOutput.closeOutput();
flgClosingDone = true;
}
}
return lngTotalBytesTransferred;
} // putFile
private void RaiseException(final Exception e, final String pstrM) {
logger.error(pstrM);
e.printStackTrace(System.err);
throw new JobSchedulerException(pstrM, e);
}
/*
private void closeObject(OutputStream objO) {
try {
if (objO != null) {
objO.flush();
objO.close();
objO = null;
}
}
catch (Exception e) {
}
}
private void closeInput(InputStream objO) {
try {
if (objO != null) {
objO.close();
objO = null;
}
}
catch (IOException e) {
}
}
*/
public String getAtomicFileName() {
return strAtomicFileName;
}
public void setAtomicFileName(String pstrValue) {
strAtomicFileName = pstrValue;
}
public boolean FileExists() {
return flgFileExists;
}
// public void run() {
// @SuppressWarnings("unused")
// final String conMethodName = conClassName + "::run";
//
// try {
// logger.debug("thread is starting...");
//
// ISOSVFSHandler objVFS = VFSFactory.getHandler(objOptions.protocol.Value());
//
// objVFS.Connect(objOptions);
// objVFS.Authenticate(objOptions);
//
// ftpClient = (ISOSVfsFileTransfer) objVFS;
//
// File localFile = this.getFile();
// if (this.getFile() == null) {
// return;
// }
//
// String strSourceFileName = this.getAbsolutePath();
// if (this.notExists()) {
// throw new JobSchedulerException(".. file [" + strSourceFileName + "] does not exist ");
// }
//
// if (polling() == false) {
// return;
// }
//
// if (objOptions.TransferZeroByteFiles() == false && this.isEmptyFile()) {
// this.TransferStatus(enuTransferStatus.transfer_skipped);
// return;
// }
//
// File subParent = null;
// String subPath = "";
// String strTargetFolderName = objOptions.remote_dir.Value();
// String localDir = objOptions.local_dir.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.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 = ftpClient.listNames(strTargetFolderName + "/" + subPath);
// if (ftpFiles == null || ftpFiles.length == 0) {
// ftpClient.mkdir(strTargetFolderName + "/" + subPath);
// }
// }
// }
// }
//
// this.getTargetFile(objOptions);
//
// if (subParent != null && recursive) {
// // fleTransferFile = new File((subParent != null ? subParent.getName() + "/" : "") + fleTransferFile.getName());
// // strTransferFilename = (subParent != null ? subPath + "/" : "") + fleTransferFile.getName();
// }
//
// long bytesSend = 0;
// Vector<String> vecTargetFileNamesList = ftpClient.nList(strTargetFileName);
// logger.debug("target-server reply [filename exists] [" + strTargetFileName + "]: " + ftpClient.getReplyString());
//
// if (objOptions.transactional.value() == true) {
// this.setTransactionalLocalFile();
// }
//
// if (objOptions.DoNotOverwrite()) {
// if (vecTargetFileNamesList.isEmpty() == false) {
// this.setNotOverwritten();
// return;
// }
// }
//
// if (objOptions.isAtomicTransfer()) {
// this.setStatus(enuTransferStatus.transferring);
// bytesSend = ftpClient.putFile(this.SourceTransferName(), this.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)) {
// ftpClient.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) {
// ftpClient.rename(this.TargetTransferName(), this.TargetFileName());
// }
// }
// else {
// this.setStatus(enuTransferStatus.transferring);
// if (objOptions.append_files.value() == true) {
// bytesSend = ftpClient.appendFile(this.SourceTransferName(), this.TargetTransferName());
// }
// else {
// bytesSend = ftpClient.putFile(this.SourceTransferName(), this.TargetTransferName());
// }
// }
// this.setNoOfBytesTransferred(bytesSend);
// this.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 && this.length() > 0 && this.length() != this.NoOfBytesTransferred()) {
// // throw new JobSchedulerException("..error occurred sending file, target file size [" + this.length()
// // + "] does not match number of bytes transferred [" + this.NoOfBytesTransferred() + "]");
// // }
//
// if (objOptions.remove_files.value() == true) {
// this.getFile().delete();
// }
//
// }
// catch (Exception e) {
// String strT = "error. unable to send files, cause: " + e;
// e.printStackTrace(System.err);
// // TODO rollback?
// logger.error(strT);
// throw new JobSchedulerException(strT, e);
// }
//
// }
private String toHexString(byte[] b) {
char[] hexChar = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
int length = b.length * 2;
StringBuffer sb = new StringBuffer(length);
for (int i = 0; i < b.length; i++) {
// oberer Byteanteil
sb.append(hexChar[(b[i] & 0xf0) >>> 4]);
// unterer Byteanteil
sb.append(hexChar[b[i] & 0x0f]);
}
return sb.toString();
}
/**
*
* \brief sendTransferHistory
*
* \details
* This methods send for every file the needed informations about the transfer history
* to the background service (JobScheduler).
*
* \return void
*
*/
public void sendTransferHistory() {
@SuppressWarnings("unused")
final String conMethodName = conClassName + "::sendTransferHistory";
if (objOptions.SendTransferHistory.value() == false) {
if (flgNoDataSent == false) {
flgNoDataSent = true;
logger.debug(String.format("No data sent to the background service due to '%1$s'", objOptions.SendTransferHistory.getKey()));
}
return;
}
String strBackgroundServiceHostName = objOptions.scheduler_host.Value();
if (isEmpty(strBackgroundServiceHostName)) {
if (flgNoDataSent == false) {
flgNoDataSent = true;
logger.debug("No data sent to the background service due to missing host name");
}
return;
}
// long guid = System.currentTimeMillis(); // 4- GUID
String mandator = objOptions.mandator.Value(); // 0-
String transfer_timestamp = EMPTY_STRING;
try {
transfer_timestamp = sos.util.SOSDate.getCurrentTimeAsString();
}
catch (Exception e) {
} // 1- timestamp: Zeitstempel im ISO-Format
/**
* this hack is tested for SUN-JVM only. No guarantee is made for other JVMs
*/
String pid = ManagementFactory.getRuntimeMXBean().getName();
String strA[] = pid.split("@");
pid = strA[0];
String ppid = System.getProperty("ppid", "0");
String operation = objOptions.operation.Value(); // 4- operation: send|receive
SOSConnection2OptionsAlternate objS = objOptions.getConnectionOptions().Source();
String localhost = objS.host.Value(); // 5- local host
String localhost_ip = objS.host.getHostAdress(); // 5-1- local host IP adresse
String local_user = System.getProperty("user.name"); // 6- local user
SOSConnection2OptionsAlternate objT = objOptions.getConnectionOptions().Target();
String remote_host = objT.host.Value(); // 7- remote host
String remote_host_ip = objT.host.getHostAdress(); // 7- remote host IP
String remote_user = objT.user.Value(); // 8- remote host user
String protocol = objT.protocol.Value(); // 9- protocol
String port = objT.port.Value(); // 10- port
String local_dir = objOptions.local_dir.Value();
String remote_dir = new File(this.strTargetFileName).getAbsolutePath();
String local_filename = this.strSourceFileName; // 13- file name
String remote_filename = this.strTargetFileName; // 14- name
if (isEmpty(remote_filename)) {
remote_filename = "n.a.";
}
String fileSize = String.valueOf(this.lngFileSize);
String md5 = this.strMD5Hash;
String status = this.eTransferStatus.name();
String last_error_message = "";
// last_error_message = clearCRLF(((getLogger().getError() != null && getLogger().getError().length() > 0) ? getLogger().getError()
// : getLogger().getWarning())); // 15- last_error=|warn message
// last_error_message = normalizedPassword(sosString.parseToString(last_error_message));
String log_filename = objOptions.log_filename.Value();
String jump_host = objOptions.jump_host.Value();
String jump_host_ip = objOptions.jump_host.getHostAdress();
String jump_port = objOptions.jump_port.Value();
String jump_protocol = objOptions.jump_protocol.Value();
String jump_user = objOptions.jump_user.Value();
Properties objSchedulerOrderParameterSet = new Properties();
objSchedulerOrderParameterSet.put("guid", String.valueOf(guid)); // 1- GUID
objSchedulerOrderParameterSet.put("mandator", mandator); // 2- mandator: default SOS
objSchedulerOrderParameterSet.put("transfer_timestamp", transfer_timestamp); // 3- timestamp: Zeitstempel im ISO-Format
objSchedulerOrderParameterSet.put("pid", pid); // 4- pid= Environment PID | 0 f�r Windows
objSchedulerOrderParameterSet.put("ppid", ppid); // 5- ppid= Environment PPID | 0 f�r Windows
objSchedulerOrderParameterSet.put("operation", operation); // 6- operation: send|receive
objSchedulerOrderParameterSet.put("localhost", localhost); // 7- local host
objSchedulerOrderParameterSet.put("localhost_ip", localhost_ip); // 8- local host IP adresse
objSchedulerOrderParameterSet.put("local_user", local_user); // 9- local user
objSchedulerOrderParameterSet.put("remote_host", remote_host); // 10- remote host
objSchedulerOrderParameterSet.put("remote_host_ip", remote_host_ip); // 11- remote host IP
objSchedulerOrderParameterSet.put("remote_user", remote_user); // 12- remote host user
objSchedulerOrderParameterSet.put("protocol", protocol); // 13- protocol
objSchedulerOrderParameterSet.put("port", port); // 14- port
objSchedulerOrderParameterSet.put("local_dir", local_dir); // 15- local dir
objSchedulerOrderParameterSet.put("remote_dir", remote_dir); // 16- remote dir
objSchedulerOrderParameterSet.put("local_filename", local_filename); // 17- file name
objSchedulerOrderParameterSet.put("remote_filename", remote_filename); // 18- file name
objSchedulerOrderParameterSet.put("file_size", fileSize); // 19 - file name
objSchedulerOrderParameterSet.put("md5", md5); // 20
if (status.equalsIgnoreCase("transferred")) {
status = "success"; // for old friends ;-)
}
objSchedulerOrderParameterSet.put("status", status); // 21- status=success|error
objSchedulerOrderParameterSet.put("last_error_message", last_error_message); // 22
objSchedulerOrderParameterSet.put("log_filename", log_filename); // 23
objSchedulerOrderParameterSet.put("jump_host", jump_host); // 24
objSchedulerOrderParameterSet.put("jump_host_ip", jump_host_ip); // 25
objSchedulerOrderParameterSet.put("jump_port", jump_port); // 26
objSchedulerOrderParameterSet.put("jump_protocol", jump_protocol); // 27
objSchedulerOrderParameterSet.put("jump_user", jump_user); // 28
// TODO custom-fields einbauen
/**
* bei SOSFTP ist es m�glich "custom" Felder zu definieren, die bei UDP als Auftragsparameter mitgeschickt werden.
* Damit man diese Felder identifizieren kann, werden hier Parameter defininiert, die beim Auftrag dabei sind, aber keine
* "custom" Felder sind
*
* ? alternativ Metadaten der Tabelle lesen (Spalten) und mit den Auftragsparameter vergleichen
*/
SchedulerObjectFactory objFactory = objParent.objFactory;
if (objFactory == null) {
objFactory = new SchedulerObjectFactory(objOptions.scheduler_host.Value(), objOptions.scheduler_port.value());
objFactory.initMarshaller(Spooler.class);
objParent.objFactory = objFactory;
objFactory.Options().TransferMethod.Value(objOptions.Scheduler_Transfer_Method.Value());
// objFactory.Options().TransferMethod.Value(enuJSTransferModes.tcp.description);
objFactory.Options().PortNumber.Value(objOptions.scheduler_port.Value());
objFactory.Options().ServerName.Value(objOptions.scheduler_host.Value());
}
JSCmdAddOrder objOrder = objFactory.createAddOrder();
objOrder.setJobChain(objOptions.scheduler_job_chain.Value() /* "scheduler_sosftp_history" */);
objOrder.setTitle("Test for UDP communication method");
Params objParams = objFactory.setParams(objSchedulerOrderParameterSet);
objOrder.setParams(objParams);
logger.debug(objOrder.toXMLString());
objOrder.run();
} // private void sendTransferHistory
}