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  package org.waarp.openr66.context.task;
21  
22  import org.apache.commons.exec.CommandLine;
23  import org.waarp.common.logging.WaarpLogger;
24  import org.waarp.common.logging.WaarpLoggerFactory;
25  import org.waarp.icap.IcapScanFile;
26  import org.waarp.openr66.context.R66Session;
27  import org.waarp.openr66.context.task.exception.OpenR66RunnerErrorException;
28  
29  /**
30   * ICAP task:<br>
31   * <p>
32   * List of arguments will be as follow.<br>
33   * -file filename <br>
34   * -to hostname <br>
35   * [-port port, default 1344] <br>
36   * -service name | -model name <br>
37   * [-previewSize size, default none] <br>
38   * [-blockSize size, default 8192] <br>
39   * [-receiveSize size, default 65536] <br>
40   * [-maxSize size, default MAX_INTEGER] <br>
41   * [-timeout in_ms, default equiv to 10 min] <br>
42   * [-keyPreview key -stringPreview string, default none] <br>
43   * [-key204 key -string204 string, default none] <br>
44   * [-key200 key -string200 string, default none] <br>
45   * [-stringHttp string, default none] <br>
46   * [-logger DEBUG|INFO|WARN|ERROR, default none] <br>
47   * [-errorMove path | -errorDelete | -sendOnError] <br>
48   * [-ignoreNetworkError] <br>
49   * [-ignoreTooBigFileError] <br>
50   * <br>
51   * Then if r66send command in case of -sendOnError option is specified, the
52   * very last option of ICAP must be "--" then followed by usual r66send
53   * options.<br>
54   * Format is like r66send command in any order except "-info" which should be
55   * the last item, and "-copyinfo"
56   * will copy at first place the original transfer information as the new one,
57   * while still having the
58   * possibility to add new informations through "-info":<br>
59   * "-file filepath -to requestedHost -rule rule [-md5] [-start yyyyMMddHHmmss or
60   * -delay (delay or +delay)] [-nofollow)
61   * [-copyinfo] [-info information]" <br>
62   * <br>
63   * INFO is the only one field that can contains blank character.<br>
64   * <br>
65   * Example:<br>
66   * -file #TRUEFULLPATH# -to hostname -service name -previewSize size
67   * -blockSize size -receiveSize size -maxSize size -timeout in_ms -keyPreview
68   * key -stringPreview string -key204 key -string204 string -key200 key
69   * -string200 string -stringHttp string -logger WARN -errorDelete
70   * -ignoreNetworkError<br>
71   * <br>
72   * -file #TRUEFULLPATH# -to hostname -model name -previewSize size
73   * -blockSize size -receiveSize size -maxSize size -timeout in_ms -keyPreview
74   * key -stringPreview string -key204 key -string204 string -key200 key
75   * -string200 string -stringHttp string -logger WARN -errorMove path
76   * -ignoreNetworkError<br>
77   * <br>
78   * -file #TRUEFULLPATH# -to hostname -model name -previewSize size
79   * -blockSize size -receiveSize size -maxSize size -timeout in_ms -keyPreview
80   * key -stringPreview string -key204 key -string204 string -key200 key
81   * -string200 string -stringHttp string -logger WARN -sendOnError
82   * -ignoreNetworkError -- -file #TRUEFULLPATH# -to
83   * requestedHost -rule rule [-copyinfo] [-info information]<br>
84   */
85  public class IcapTask extends AbstractTask {
86    /**
87     * Internal Logger
88     */
89    private static final WaarpLogger logger =
90        WaarpLoggerFactory.getLogger(IcapTask.class);
91  
92    /**
93     * @param argRule
94     * @param delay
95     * @param argTransfer
96     * @param session
97     */
98    public IcapTask(final String argRule, final int delay,
99                    final String argTransfer, final R66Session session) {
100     super(TaskType.ICAP, delay, argRule, argTransfer, session);
101   }
102 
103   @Override
104   public final void run() {
105     logger.info("ICAP with " + argRule + ':' + argTransfer + " and {}",
106                 session);
107     String finalname = applyTransferSubstitutions(argRule);
108     finalname = finalname.replaceAll("#([A-Z]+)#", "\\${$1}");
109     final CommandLine commandLine = new CommandLine("dummy");
110     commandLine.setSubstitutionMap(getSubstitutionMap());
111     commandLine.addArguments(finalname, false);
112     final String[] args = commandLine.getArguments();
113 
114     if (args.length < 6) {
115       futureCompletion.setFailure(
116           new OpenR66RunnerErrorException("Not enough argument in ICAP"));
117       return;
118     }
119     final int status = IcapScanFile.scanFile(args);
120     switch (status) {
121       case IcapScanFile.STATUS_OK:
122         futureCompletion.setSuccess();
123         return;
124       case IcapScanFile.STATUS_BAD_ARGUMENT:
125         logger.error(
126             "ICAP Bad argument error with " + argRule + ':' + argTransfer +
127             ':' + delay + " and " + session);
128         futureCompletion.setFailure(
129             new OpenR66RunnerErrorException("ICAP Bad argument error"));
130         return;
131       case IcapScanFile.STATUS_ICAP_ISSUE:
132         logger.error(
133             "ICAP Bad protocol error with " + argRule + ':' + argTransfer +
134             ':' + delay + " and " + session);
135         futureCompletion.setFailure(
136             new OpenR66RunnerErrorException("ICAP Bad protocol error"));
137         return;
138       case IcapScanFile.STATUS_NETWORK_ISSUE:
139         logger.error(
140             "ICAP Network error with " + argRule + ':' + argTransfer + ':' +
141             delay + " and " + session);
142         futureCompletion.setFailure(
143             new OpenR66RunnerErrorException("ICAP Network error"));
144         return;
145       case IcapScanFile.STATUS_KO_SCAN:
146         if (finalizeIcapOnError(args)) {
147           return;
148         }
149         // No send required so real error
150         logger.error(
151             "ICAP KO error with " + argRule + ':' + argTransfer + ':' + delay +
152             " and " + session);
153         futureCompletion.setFailure(
154             new OpenR66RunnerErrorException("ICAP KO error"));
155         return;
156       case IcapScanFile.STATUS_KO_SCAN_POST_ACTION_ERROR:
157         logger.error(
158             "ICAP KO post error with " + argRule + ':' + argTransfer + ':' +
159             delay + " and " + session);
160         futureCompletion.setFailure(
161             new OpenR66RunnerErrorException("ICAP KO post error"));
162         return;
163       default:
164         logger.error(
165             "ICAP Unknown error with " + argRule + ':' + argTransfer + ':' +
166             delay + " and " + session);
167         futureCompletion.setFailure(
168             new OpenR66RunnerErrorException("ICAP Unknown error"));
169     }
170   }
171 
172   /**
173    * finalize Icap on Error
174    *
175    * @param args
176    *
177    * @return True if OK
178    */
179   private boolean finalizeIcapOnError(final String[] args) {
180     for (int i = 0; i < args.length; i++) {
181       if (IcapScanFile.ERROR_SEND_ARG.equalsIgnoreCase(args[i])) {
182         for (i++; i < args.length; i++) {
183           if (IcapScanFile.SEPARATOR_SEND.equals(args[i])) {
184             final StringBuilder newArgs = new StringBuilder();
185             for (i++; i < args.length; i++) {
186               newArgs.append(args[i]).append(' ');
187             }
188             // Now launch send
189             final TransferTask transferTask =
190                 new TransferTask(newArgs.toString(), 0, argTransfer, session);
191             transferTask.run();
192             transferTask.futureCompletion.awaitOrInterruptible();
193             if (transferTask.futureCompletion.isSuccess()) {
194               futureCompletion.setResult(
195                   transferTask.futureCompletion.getResult());
196               logger.info(
197                   "ICAP ended in KO on file but resend as requested is OK for {}",
198                   session.getFile().getTrueFile().getAbsolutePath());
199               futureCompletion.setFailure(new OpenR66RunnerErrorException(
200                   "ICAP ended in KO on file but resend as requested is OK"));
201             } else {
202               logger.error(
203                   "ICAP KO with Resend in error with " + argRule + ':' +
204                   argTransfer + ':' + delay + " and " + session,
205                   transferTask.futureCompletion.getCause());
206               if (transferTask.futureCompletion.getCause() == null) {
207                 futureCompletion.setFailure(new OpenR66RunnerErrorException(
208                     "ICAP ended in KO on file and Resend is KO too"));
209               } else {
210                 futureCompletion.setFailure(new OpenR66RunnerErrorException(
211                     "ICAP ended in KO on file and Resend is KO too",
212                     transferTask.futureCompletion.getCause()));
213               }
214             }
215             return true;
216           }
217         }
218       }
219     }
220     return false;
221   }
222 
223 }