View Javadoc
1   /*
2    * This file is part of Waarp Project (named also Waarp or GG).
3    *
4    *  Copyright (c) 2019, Waarp SAS, and individual contributors by the @author
5    *  tags. See the COPYRIGHT.txt in the distribution for a full listing of
6    * individual contributors.
7    *
8    *  All Waarp Project is free software: you can redistribute it and/or
9    * modify it under the terms of the GNU General Public License as published by
10   * the Free Software Foundation, either version 3 of the License, or (at your
11   * option) any later version.
12   *
13   * Waarp is distributed in the hope that it will be useful, but WITHOUT ANY
14   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15   * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16   *
17   *  You should have received a copy of the GNU General Public License along with
18   * Waarp . If not, see <http://www.gnu.org/licenses/>.
19   */
20  
21  
22  package org.waarp.gateway.ftp.exec;
23  
24  import org.waarp.common.command.exception.CommandAbstractException;
25  import org.waarp.common.command.exception.Reply421Exception;
26  import org.waarp.common.database.data.AbstractDbData.UpdatedInfo;
27  import org.waarp.common.database.exception.WaarpDatabaseException;
28  import org.waarp.common.future.WaarpFuture;
29  import org.waarp.common.logging.WaarpLogger;
30  import org.waarp.common.logging.WaarpLoggerFactory;
31  import org.waarp.openr66.client.TransferArgs;
32  import org.waarp.openr66.database.data.DbRule;
33  import org.waarp.openr66.database.data.DbTaskRunner;
34  import org.waarp.openr66.protocol.configuration.PartnerConfiguration;
35  import org.waarp.openr66.protocol.localhandler.packet.RequestPacket;
36  
37  import java.io.File;
38  
39  import static org.waarp.common.database.DbConstant.*;
40  import static org.waarp.common.file.filesystembased.FilesystemBasedFileImpl.*;
41  
42  /**
43   * R66PreparedTransferExecutor class. If the command starts with "REFUSED", the
44   * command will be refused for
45   * execution. If "REFUSED" is set, the command "RETR" or "STOR" like operations
46   * will be stopped at starting of
47   * command.
48   * <p>
49   * <p>
50   * <p>
51   * Format is like r66send command in any order except "-info" which should be
52   * the last item:<br>
53   * "-to Host -file FILE -rule RULE [-md5] [-nolog] [-start yyyyMMddHHmmss or
54   * -delay (delay or +delay)] [-info INFO]" <br>
55   * <br>
56   * INFO is the only one field that can contains blank character and MUST be
57   * the last argument.<br>
58   * <br>
59   * The following replacement are done dynamically before the command is
60   * executed:<br>
61   * - #BASEPATH# is replaced by the full path for the root of FTP Directory<br>
62   * - #FILE# is replaced by the current file path relative to FTP Directory (so
63   * #BASEPATH##FILE# is the full
64   * path of the file)<br>
65   * - #USER# is replaced by the username<br>
66   * - #ACCOUNT# is replaced by the account<br>
67   * - #COMMAND# is replaced by the command issued for the file<br>
68   * - #SPECIALID# is replaced by the FTP id of the transfer (whatever in or
69   * out)<br>
70   * - #UUID# is replaced by a special UUID globally unique for the transfer, in
71   * general to be placed in -info
72   * part (for instance ##UUID## giving #uuid#)<br>
73   * <br>
74   * So for instance "-to Host -file #BASEPATH##FILE# -rule RULE [-md5] [-nolog]
75   * [-delay +delay] [-info ##UUID##
76   * #USER# #ACCOUNT# #COMMAND# INFO]" <br>
77   * will be a standard use of this function.
78   */
79  public class R66PreparedTransferExecutor extends AbstractExecutor {
80    private static final String CANNOT_GET_NEW_TASK = "Cannot get new task\n    ";
81  
82    /**
83     * Internal Logger
84     */
85    private static final WaarpLogger logger =
86        WaarpLoggerFactory.getLogger(R66PreparedTransferExecutor.class);
87  
88    protected final WaarpFuture future;
89    protected final TransferArgs transferArgs;
90  
91    protected boolean nolog;
92  
93    /**
94     * Transfer arguments:<br>
95     * <br>
96     * -to <arg>        Specify the requested Host<br>
97     * (-id <arg>|      Specify the id of transfer<br>
98     * (-file <arg>     Specify the file path to operate on<br>
99     * -rule <arg>))    Specify the Rule<br>
100    * [-block <arg>]   Specify the block size<br>
101    * [-nofollow]      Specify the transfer should not integrate a FOLLOW id<br>
102    * [-md5]           Specify the option to have a hash computed for the
103    * transfer<br>
104    * [-delay <arg>]   Specify the delay time as an epoch time or '+' a delay in ms<br>
105    * [-start <arg>]   Specify the start time as yyyyMMddHHmmss<br>
106    * [-info <arg>)    Specify the transfer information (generally in last position)<br>
107    * [-nolog]         Specify to not log anything included database once the
108    * transfer is done<br>
109    * [-notlogWarn |   Specify to log final result as Info if OK<br>
110    * -logWarn]        Specify to log final result as Warn if OK<br>
111    *
112    * @param command transfer arguments
113    * @param delay delay
114    * @param futureCompletion future for completion
115    */
116   public R66PreparedTransferExecutor(final String command, final long delay,
117                                      final WaarpFuture futureCompletion) {
118     final String[] args = BLANK.split(command);
119     transferArgs = TransferArgs.getParamsInternal(0, args, false);
120     if (transferArgs != null) {
121       TransferArgs.getAllInfo(transferArgs, 0, args, null);
122       nolog = transferArgs.isNolog();
123     }
124     future = futureCompletion;
125   }
126 
127   @Override
128   public final void run() throws CommandAbstractException {
129     if (transferArgs == null) {
130       logger.error(
131           "Mandatory argument is missing: -to  -rule  -file or -to -id");
132       throw new Reply421Exception(
133           "Mandatory argument is missing: -to  -rule  -file or -to -id");
134     }
135     if (transferArgs.getRemoteHost() == null ||
136         transferArgs.getRulename() == null ||
137         transferArgs.getFilename() == null) {
138       logger.error(
139           "Mandatory argument is missing: -to " + transferArgs.getRemoteHost() +
140           " -rule " + transferArgs.getRulename() + " -file " +
141           transferArgs.getFilename());
142       throw new Reply421Exception("Mandatory argument is missing");
143     }
144     final String message =
145         "R66Prepared with -to " + transferArgs.getRemoteHost() + " -rule " +
146         transferArgs.getRulename() + " -file " + transferArgs.getFilename() +
147         " -nolog: " + nolog + " -isMD5: " + transferArgs.isMD5() + " -info " +
148         transferArgs.getTransferInfo();
149     logger.debug(message);
150     final DbRule rule;
151     try {
152       rule = new DbRule(transferArgs.getRulename());
153     } catch (final WaarpDatabaseException e) {
154       logger.error("Cannot get Rule: {} since {}\n    {}",
155                    transferArgs.getRulename(), e.getMessage(), message);
156       throw new Reply421Exception(
157           "Cannot get Rule: " + transferArgs.getRulename() + "\n    " +
158           message);
159     }
160     int mode = rule.getMode();
161     if (transferArgs.isMD5()) {
162       mode = RequestPacket.getModeMD5(mode);
163     }
164     final String sep =
165         PartnerConfiguration.getSeparator(transferArgs.getRemoteHost());
166     long originalSize = -1;
167     if (RequestPacket.isSendMode(mode) && !RequestPacket.isThroughMode(mode)) {
168       final File file = new File(transferArgs.getFilename());
169       if (canRead(file)) {
170         originalSize = file.length();
171       }
172     }
173     final RequestPacket request =
174         new RequestPacket(transferArgs.getRulename(), mode,
175                           transferArgs.getFilename(),
176                           transferArgs.getBlockSize(), 0, ILLEGALVALUE,
177                           transferArgs.getTransferInfo(), originalSize, sep);
178     // Not isRecv since it is the requester, so send => isRetrieve is true
179     final boolean isRetrieve = !RequestPacket.isRecvMode(request.getMode());
180     logger.debug("Will prepare: {}", request);
181     final DbTaskRunner taskRunner;
182     try {
183       taskRunner = new DbTaskRunner(rule, isRetrieve, request,
184                                     transferArgs.getRemoteHost(),
185                                     transferArgs.getStartTime());
186     } catch (final WaarpDatabaseException e) {
187       logger.error("Cannot get new task since {}\n    {}", e.getMessage(),
188                    message);
189       throw new Reply421Exception(CANNOT_GET_NEW_TASK + message);
190     }
191     taskRunner.changeUpdatedInfo(UpdatedInfo.TOSUBMIT);
192     if (!taskRunner.forceSaveStatus()) {
193       try {
194         if (!taskRunner.specialSubmit()) {
195           logger.error("Cannot prepare task: " + message);
196           throw new Reply421Exception(CANNOT_GET_NEW_TASK + message);
197         }
198       } catch (final WaarpDatabaseException e) {
199         logger.error("Cannot prepare task since {}\n    {}", e.getMessage(),
200                      message);
201         throw new Reply421Exception(CANNOT_GET_NEW_TASK + message);
202       }
203     }
204     logger.debug("R66PreparedTransfer prepared: {}", request);
205     future.setSuccess();
206   }
207 }