/** * Copyright 2009, Frederic Bregier, and individual contributors by the @author tags. See the * COPYRIGHT.txt in the distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 3.0 of the * License, or (at your option) any later version. * * This software 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this * software; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.waarp.gateway.kernel.exec; import java.io.File; import java.sql.Timestamp; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import org.waarp.common.command.exception.CommandAbstractException; import org.waarp.common.command.exception.Reply421Exception; import org.waarp.common.database.DbSession; import org.waarp.common.database.data.AbstractDbData; import org.waarp.common.database.exception.WaarpDatabaseException; import org.waarp.common.future.WaarpFuture; import org.waarp.common.logging.WaarpLogger; import org.waarp.common.logging.WaarpLoggerFactory; import org.waarp.openr66.database.DbConstant; import org.waarp.openr66.database.data.DbRule; import org.waarp.openr66.database.data.DbTaskRunner; import org.waarp.openr66.protocol.configuration.Configuration; import org.waarp.openr66.protocol.configuration.PartnerConfiguration; import org.waarp.openr66.protocol.localhandler.packet.RequestPacket; /** * R66PreparedTransferExecutor class. If the command starts with "REFUSED", the command will be * refused for execution. If "REFUSED" is set, the command "RETR" or "STOR" like operations will be * stopped at starting of command. * * * * Format is like r66send command in any order except "-info" which should be the last item:<br> * "-to Host -file FILE -rule RULE [-md5] [-nolog] [-start yyyyMMddHHmmss or -delay (delay or +delay)] [-info INFO]" <br> * <br> * INFO is the only one field that can contains blank character.<br> * <br> * The following replacement are done dynamically before the command is executed:<br> * - #BASEPATH# is replaced by the full path for the root of FTP Directory<br> * - #FILE# is replaced by the current file path relative to FTP Directory (so #BASEPATH##FILE# is * the full path of the file)<br> * - #USER# is replaced by the username<br> * - #ACCOUNT# is replaced by the account<br> * - #COMMAND# is replaced by the command issued for the file<br> * - #SPECIALID# is replaced by the FTP id of the transfer (whatever in or out)<br> * - #UUID# is replaced by a special UUID globally unique for the transfer, in general to be placed in -info part (for instance ##UUID## giving #uuid#)<br> * <br> * So for instance * "-to Host -file #BASEPATH##FILE# -rule RULE [-md5] [-nolog] [-delay +delay] [-info ##UUID## #USER# #ACCOUNT# #COMMAND# INFO]" <br> * will be a standard use of this function. * * @author Frederic Bregier * */ public class R66PreparedTransferExecutor extends AbstractExecutor { /** * Internal Logger */ private static final WaarpLogger logger = WaarpLoggerFactory .getLogger(R66PreparedTransferExecutor.class); protected final WaarpFuture future; protected String filename = null; protected String rulename = null; protected String fileinfo = null; protected boolean isMD5 = false; protected boolean nolog = false; protected Timestamp timestart = null; protected String remoteHost = null; protected int blocksize = Configuration.configuration.getBLOCKSIZE();; protected DbSession dbsession; /** * * @param command * @param delay * @param futureCompletion */ public R66PreparedTransferExecutor(String command, long delay, WaarpFuture futureCompletion) { String args[] = command.split(" "); for (int i = 0; i < args.length; i++) { if (args[i].equalsIgnoreCase("-to")) { i++; remoteHost = args[i]; if (Configuration.configuration.getAliases().containsKey(remoteHost)) { remoteHost = Configuration.configuration.getAliases().get(remoteHost); } } else if (args[i].equalsIgnoreCase("-file")) { i++; filename = args[i]; } else if (args[i].equalsIgnoreCase("-rule")) { i++; rulename = args[i]; } else if (args[i].equalsIgnoreCase("-info")) { i++; fileinfo = args[i]; i++; while (i < args.length) { fileinfo += " " + args[i]; i++; } } else if (args[i].equalsIgnoreCase("-md5")) { isMD5 = true; } else if (args[i].equalsIgnoreCase("-block")) { i++; blocksize = Integer.parseInt(args[i]); if (blocksize < 100) { logger.warn("Block size is too small: " + blocksize); blocksize = Configuration.configuration.getBLOCKSIZE(); } } else if (args[i].equalsIgnoreCase("-nolog")) { nolog = true; i++; } else if (args[i].equalsIgnoreCase("-start")) { i++; SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss"); Date date; try { date = dateFormat.parse(args[i]); timestart = new Timestamp(date.getTime()); } catch (ParseException e) { } } else if (args[i].equalsIgnoreCase("-delay")) { i++; if (args[i].charAt(0) == '+') { timestart = new Timestamp(System.currentTimeMillis() + Long.parseLong(args[i].substring(1))); } else { timestart = new Timestamp(Long.parseLong(args[i])); } } } if (fileinfo == null) { fileinfo = "noinfo"; } this.future = futureCompletion; } /** * @param dbsession * the dbsession to set */ public void setDbsession(DbSession dbsession) { this.dbsession = dbsession; } public void run() throws CommandAbstractException { String message = "R66Prepared with -to " + remoteHost + " -rule " + rulename + " -file " + filename + " -nolog: " + nolog + " -isMD5: " + isMD5 + " -info " + fileinfo; if (remoteHost == null || rulename == null || filename == null) { logger.error("Mandatory argument is missing: -to " + remoteHost + " -rule " + rulename + " -file " + filename); throw new Reply421Exception("Mandatory argument is missing\n " + message); } logger.debug(message); DbRule rule; try { rule = new DbRule(dbsession, rulename); } catch (WaarpDatabaseException e) { logger.error("Cannot get Rule: " + rulename + " since {}\n " + message, e.getMessage()); throw new Reply421Exception("Cannot get Rule: " + rulename + "\n " + message); } int mode = rule.getMode(); if (isMD5) { mode = RequestPacket.getModeMD5(mode); } String sep = PartnerConfiguration.getSeparator(remoteHost); long originalSize = -1; if (RequestPacket.isSendMode(mode) && !RequestPacket.isThroughMode(mode)) { File file = new File(filename); if (file.canRead()) { originalSize = file.length(); } } RequestPacket request = new RequestPacket(rulename, mode, filename, blocksize, 0, DbConstant.ILLEGALVALUE, fileinfo, originalSize, sep); // Not isRecv since it is the requester, so send => isRetrieve is true boolean isRetrieve = !RequestPacket.isRecvMode(request.getMode()); logger.debug("Will prepare: {}", request); DbTaskRunner taskRunner; try { taskRunner = new DbTaskRunner(dbsession, rule, isRetrieve, request, remoteHost, timestart); } catch (WaarpDatabaseException e) { logger.error("Cannot get new task since {}\n " + message, e .getMessage()); throw new Reply421Exception("Cannot get new task\n " + message); } taskRunner.changeUpdatedInfo(AbstractDbData.UpdatedInfo.TOSUBMIT); if (!taskRunner.forceSaveStatus()) { try { if (!taskRunner.specialSubmit()) { logger.error("Cannot prepare task: " + message); throw new Reply421Exception("Cannot get new task\n " + message); } } catch (WaarpDatabaseException e) { logger.error("Cannot prepare task since {}\n " + message, e .getMessage()); throw new Reply421Exception("Cannot get new task\n " + message); } } logger.debug("R66PreparedTransfer prepared: {}", request); future.setSuccess(); } }