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.waarp.common.command.exception.CommandAbstractException;
23  import org.waarp.common.logging.WaarpLogger;
24  import org.waarp.common.logging.WaarpLoggerFactory;
25  import org.waarp.common.utility.WaarpStringUtils;
26  import org.waarp.openr66.context.ErrorCode;
27  import org.waarp.openr66.context.R66Session;
28  import org.waarp.openr66.context.filesystem.R66Dir;
29  import org.waarp.openr66.context.filesystem.R66File;
30  import org.waarp.openr66.database.data.DbTaskRunner;
31  import org.waarp.openr66.protocol.configuration.Configuration;
32  import org.waarp.openr66.protocol.exception.OpenR66ProtocolNoSslException;
33  import org.waarp.openr66.protocol.utils.R66Future;
34  
35  import java.io.File;
36  import java.text.DateFormat;
37  import java.text.SimpleDateFormat;
38  import java.util.Date;
39  import java.util.HashMap;
40  import java.util.Map;
41  import java.util.regex.Matcher;
42  import java.util.regex.Pattern;
43  
44  /**
45   * Abstract implementation of task
46   */
47  public abstract class AbstractTask implements Runnable {
48    /**
49     * Internal Logger
50     */
51    private static final WaarpLogger logger =
52        WaarpLoggerFactory.getLogger(AbstractTask.class);
53    protected static final Pattern BLANK = WaarpStringUtils.BLANK;
54    private static final Pattern COMPILE_HASH =
55        Pattern.compile("#", Pattern.LITERAL);
56    /**
57     * Current full path of current FILENAME
58     */
59    public static final String TRUEFULLPATH = "#TRUEFULLPATH#";
60  
61    /**
62     * Current FILENAME (basename) (change in retrieval part)
63     */
64    public static final String TRUEFILENAME = "#TRUEFILENAME#";
65    /**
66     * Current full path of Original FILENAME (as transmitted) (before changing
67     * in
68     * retrieval part)
69     */
70    public static final String ORIGINALFULLPATH = "#ORIGINALFULLPATH#";
71  
72    /**
73     * Original FILENAME (basename) (before changing in retrieval part)
74     */
75    public static final String ORIGINALFILENAME = "#ORIGINALFILENAME#";
76  
77    /**
78     * Size of the current FILE
79     */
80    public static final String FILESIZE = "#FILESIZE#";
81  
82    /**
83     * Current full path of current RULE
84     */
85    public static final String RULE = "#RULE#";
86  
87    /**
88     * Date in yyyyMMdd format
89     */
90    public static final String DATE = "#DATE#";
91  
92    /**
93     * Hour in HHmmss format
94     */
95    public static final String HOUR = "#HOUR#";
96  
97    /**
98     * Remote host id (if not the initiator of the call)
99     */
100   public static final String REMOTEHOST = "#REMOTEHOST#";
101 
102   /**
103    * Remote host address
104    */
105   public static final String REMOTEHOSTADDR = "#REMOTEHOSTADDR#";
106 
107   /**
108    * Local host id
109    */
110   public static final String LOCALHOST = "#LOCALHOST#";
111 
112   /**
113    * Local host address
114    */
115   public static final String LOCALHOSTADDR = "#LOCALHOSTADDR#";
116 
117   /**
118    * Transfer id
119    */
120   public static final String TRANSFERID = "#TRANSFERID#";
121 
122   /**
123    * Requester Host
124    */
125   public static final String REQUESTERHOST = "#REQUESTERHOST#";
126 
127   /**
128    * Requested Host
129    */
130   public static final String REQUESTEDHOST = "#REQUESTEDHOST#";
131 
132   /**
133    * Full Transfer id (TRANSFERID_REQUESTERHOST_REQUESTEDHOST)
134    */
135   public static final String FULLTRANSFERID = "#FULLTRANSFERID#";
136 
137   /**
138    * Current or final RANK of block
139    */
140   public static final String RANKTRANSFER = "#RANKTRANSFER#";
141 
142   /**
143    * Block size used
144    */
145   public static final String BLOCKSIZE = "#BLOCKSIZE#";
146 
147   /**
148    * IN Path used
149    */
150   public static final String INPATH = "#INPATH#";
151 
152   /**
153    * OUT Path used
154    */
155   public static final String OUTPATH = "#OUTPATH#";
156 
157   /**
158    * WORK Path used
159    */
160   public static final String WORKPATH = "#WORKPATH#";
161 
162   /**
163    * ARCH Path used
164    */
165   public static final String ARCHPATH = "#ARCHPATH#";
166 
167   /**
168    * HOME Path used
169    */
170   public static final String HOMEPATH = "#HOMEPATH#";
171   /**
172    * Last Current Error Message
173    */
174   public static final String ERRORMSG = "#ERRORMSG#";
175   /**
176    * Last Current Error Code
177    */
178   public static final String ERRORCODE = "#ERRORCODE#";
179   /**
180    * Last Current Error Code in Full String
181    */
182   public static final String ERRORSTRCODE = "#ERRORSTRCODE#";
183   /**
184    * If specified, no Wait for Task Validation (default is wait)
185    */
186   public static final String NOWAIT = "#NOWAIT#";
187   /**
188    * If specified, use the LocalExec Daemon specified in the global
189    * configuration (default no usage of
190    * LocalExec)
191    */
192   public static final String LOCALEXEC = "#LOCALEXEC#";
193   /**
194    * If specified, and if the partner allows Compression (from 3.6.0 and
195    * if compression is enabled), this will allow one transfer through
196    * TransferInformation to use compression by block.
197    */
198   public static final String COMPRESS = "#COMPRESS#";
199 
200   /**
201    * Type of operation
202    */
203   final TaskType type;
204 
205   /**
206    * Argument from Rule
207    */
208   final String argRule;
209 
210   /**
211    * Delay from Rule (if applicable)
212    */
213   final int delay;
214 
215   /**
216    * Argument from Transfer
217    */
218   final String argTransfer;
219 
220   /**
221    * Current session
222    */
223   final R66Session session;
224 
225   /**
226    * R66Future of completion
227    */
228   final R66Future futureCompletion;
229   /**
230    * Do we wait for a validation of the task ? Default = True
231    */
232   boolean waitForValidation = true;
233   /**
234    * Do we need to use LocalExec for an Exec Task ? Default = False
235    */
236   boolean useLocalExec;
237 
238   /**
239    * Constructor
240    *
241    * @param type
242    * @param delay
243    * @param argRule
244    * @param argTransfer
245    * @param session
246    */
247   AbstractTask(final TaskType type, final int delay, final String argRule,
248                final String argTransfer, final R66Session session) {
249     this.type = type;
250     this.delay = delay;
251     if (argRule != null) {
252       this.argRule = argRule.replaceAll(WaarpStringUtils.BLANK_REGEX, " ");
253     } else {
254       this.argRule = null;
255     }
256     if (argTransfer != null) {
257       this.argTransfer =
258           argTransfer.replaceAll(WaarpStringUtils.BLANK_REGEX, " ");
259     } else {
260       this.argTransfer = null;
261     }
262     this.session = session;
263     futureCompletion = new R66Future(true);
264   }
265 
266   /**
267    * @return the TaskType of this AbstractTask
268    */
269   public final TaskType getType() {
270     return type;
271   }
272 
273   /**
274    * @return True if the operation is in success status
275    */
276   public final boolean isSuccess() {
277     futureCompletion.awaitOrInterruptible();
278     return futureCompletion.isSuccess();
279   }
280 
281   /**
282    * @return the R66Future of completion
283    */
284   public final R66Future getFutureCompletion() {
285     return futureCompletion;
286   }
287 
288   /**
289    * @param arg
290    * @param session
291    *
292    * @return True if the argument contains #COMPRESS# and if the current host
293    *     allow compression
294    */
295   public static boolean isCompressionRequested(final String arg,
296                                                final R66Session session) {
297     logger.debug("isCompEnabled {} {}",
298                  Configuration.configuration.isCompressionAvailable(),
299                  arg.contains(COMPRESS));
300     if (session == null) {
301       return Configuration.configuration.isCompressionAvailable() &&
302              arg.contains(COMPRESS);
303     } else {
304       return Configuration.configuration.isCompressionAvailable() &&
305              session.isCompressionEnabled() && arg.contains(COMPRESS);
306     }
307   }
308 
309   /**
310    * @param arg as the Format string where FIXED items will be
311    *     replaced by
312    *     context values and next using
313    *     argFormat as format second argument; this arg comes from the
314    *     rule
315    *     itself
316    * @param argFormat as format second argument; this argFormat comes
317    *     from
318    *     the transfer Information itself
319    *
320    * @return The string with replaced values from context and second argument
321    */
322   protected final String getReplacedValue(final String arg,
323                                           final Object[] argFormat) {
324     final StringBuilder builder = new StringBuilder(arg);
325     // check NOWAIT and LOCALEXEC and COMPRESS
326     if (arg.contains(NOWAIT)) {
327       waitForValidation = false;
328       WaarpStringUtils.replaceAll(builder, NOWAIT, "");
329     }
330     if (arg.contains(LOCALEXEC)) {
331       useLocalExec = true;
332       WaarpStringUtils.replaceAll(builder, LOCALEXEC, "");
333     }
334     if (arg.contains(COMPRESS)) {
335       WaarpStringUtils.replaceAll(builder, COMPRESS, "");
336     }
337     substituteFile(builder);
338     final DbTaskRunner runner = substituteRunner(builder);
339     substituteDate(builder);
340     substituteHost(builder);
341     WaarpStringUtils.replaceAll(builder, BLOCKSIZE,
342                                 Integer.toString(session.getBlockSize()));
343     substitutePath(builder, runner);
344     WaarpStringUtils.replaceAll(builder, HOMEPATH,
345                                 Configuration.configuration.getBaseDirectory());
346     substituteErrorCode(builder);
347     // finalname
348     if (argFormat != null && argFormat.length > 0) {
349       try {
350         return String.format(builder.toString(), argFormat);
351       } catch (final Exception e) {
352         // ignored error since bad argument in static rule info
353         logger.error("Bad format in Rule: {" + builder + "} " + e.getMessage());
354       }
355     }
356     return builder.toString();
357   }
358 
359   /**
360    * Apply transferInfo substitutions
361    *
362    * @param line the line to format
363    *
364    * @return the line after substitutions
365    */
366   protected final String applyTransferSubstitutions(final String line) {
367     final Object[] argFormat = BLANK.split(argTransfer);
368     if (argFormat != null && argFormat.length > 0) {
369       try {
370         return String.format(line, argFormat);
371       } catch (final Exception e) {
372         // ignored error since bad argument in static rule info
373         logger.error("Bad format in Rule: {" + line + "} " + e.getMessage());
374       }
375     }
376     return line;
377   }
378 
379   private void substituteErrorCode(final StringBuilder builder) {
380     if (session.getLocalChannelReference() == null) {
381       WaarpStringUtils.replaceAll(builder, ERRORMSG, "NoError");
382       WaarpStringUtils.replaceAll(builder, ERRORCODE, "-");
383       WaarpStringUtils.replaceAll(builder, ERRORSTRCODE,
384                                   ErrorCode.Unknown.name());
385     } else {
386       try {
387         WaarpStringUtils.replaceAll(builder, ERRORMSG,
388                                     session.getLocalChannelReference()
389                                            .getErrorMessage());
390       } catch (final NullPointerException e) {
391         WaarpStringUtils.replaceAll(builder, ERRORMSG, "NoError");
392       }
393       try {
394         WaarpStringUtils.replaceAll(builder, ERRORCODE,
395                                     session.getLocalChannelReference()
396                                            .getCurrentCode().getCode());
397       } catch (final NullPointerException e) {
398         WaarpStringUtils.replaceAll(builder, ERRORCODE, "-");
399       }
400       try {
401         WaarpStringUtils.replaceAll(builder, ERRORSTRCODE,
402                                     session.getLocalChannelReference()
403                                            .getCurrentCode().name());
404       } catch (final NullPointerException e) {
405         WaarpStringUtils.replaceAll(builder, ERRORSTRCODE,
406                                     ErrorCode.Unknown.name());
407       }
408     }
409   }
410 
411   private void substitutePath(final StringBuilder builder,
412                               final DbTaskRunner runner) {
413     R66Dir dir = new R66Dir(session);
414     if (runner != null) {
415       if (runner.isRecvThrough() || runner.isSendThrough()) {
416         try {
417           dir.changeDirectoryNotChecked(runner.getRule().getRecvPath());
418           WaarpStringUtils.replaceAll(builder, INPATH, dir.getFullPath());
419         } catch (final CommandAbstractException ignored) {
420           // nothing
421         }
422         dir = new R66Dir(session);
423         try {
424           dir.changeDirectoryNotChecked(runner.getRule().getSendPath());
425           WaarpStringUtils.replaceAll(builder, OUTPATH, dir.getFullPath());
426         } catch (final CommandAbstractException ignored) {
427           // nothing
428         }
429         dir = new R66Dir(session);
430         try {
431           dir.changeDirectoryNotChecked(runner.getRule().getWorkPath());
432           WaarpStringUtils.replaceAll(builder, WORKPATH, dir.getFullPath());
433         } catch (final CommandAbstractException ignored) {
434           // nothing
435         }
436         dir = new R66Dir(session);
437         try {
438           dir.changeDirectoryNotChecked(runner.getRule().getArchivePath());
439           WaarpStringUtils.replaceAll(builder, ARCHPATH, dir.getFullPath());
440         } catch (final CommandAbstractException ignored) {
441           // nothing
442         }
443       } else {
444         try {
445           dir.changeDirectory(runner.getRule().getRecvPath());
446           WaarpStringUtils.replaceAll(builder, INPATH, dir.getFullPath());
447         } catch (final CommandAbstractException ignored) {
448           // nothing
449         }
450         dir = new R66Dir(session);
451         try {
452           dir.changeDirectory(runner.getRule().getSendPath());
453           WaarpStringUtils.replaceAll(builder, OUTPATH, dir.getFullPath());
454         } catch (final CommandAbstractException ignored) {
455           // nothing
456         }
457         dir = new R66Dir(session);
458         try {
459           dir.changeDirectory(runner.getRule().getWorkPath());
460           WaarpStringUtils.replaceAll(builder, WORKPATH, dir.getFullPath());
461         } catch (final CommandAbstractException ignored) {
462           // nothing
463         }
464         dir = new R66Dir(session);
465         try {
466           dir.changeDirectory(runner.getRule().getArchivePath());
467           WaarpStringUtils.replaceAll(builder, ARCHPATH, dir.getFullPath());
468         } catch (final CommandAbstractException ignored) {
469           // nothing
470         }
471       }
472     } else {
473       try {
474         dir.changeDirectory(Configuration.configuration.getInPath());
475         WaarpStringUtils.replaceAll(builder, INPATH, dir.getFullPath());
476       } catch (final CommandAbstractException ignored) {
477         // nothing
478       }
479       dir = new R66Dir(session);
480       try {
481         dir.changeDirectory(Configuration.configuration.getOutPath());
482         WaarpStringUtils.replaceAll(builder, OUTPATH, dir.getFullPath());
483       } catch (final CommandAbstractException ignored) {
484         // nothing
485       }
486       dir = new R66Dir(session);
487       try {
488         dir.changeDirectory(Configuration.configuration.getWorkingPath());
489         WaarpStringUtils.replaceAll(builder, WORKPATH, dir.getFullPath());
490       } catch (final CommandAbstractException ignored) {
491         // nothing
492       }
493       dir = new R66Dir(session);
494       try {
495         dir.changeDirectory(Configuration.configuration.getArchivePath());
496         WaarpStringUtils.replaceAll(builder, ARCHPATH, dir.getFullPath());
497       } catch (final CommandAbstractException ignored) {
498         // nothing
499       }
500     }
501   }
502 
503   private void substituteHost(final StringBuilder builder) {
504     if (session.getAuth() != null) {
505       WaarpStringUtils.replaceAll(builder, REMOTEHOST,
506                                   session.getAuth().getUser());
507       try {
508         WaarpStringUtils.replaceAll(builder, LOCALHOST,
509                                     Configuration.configuration.getHostId(
510                                         session.getAuth().isSsl()));
511       } catch (final OpenR66ProtocolNoSslException e) {
512         // replace by standard name
513         WaarpStringUtils.replaceAll(builder, LOCALHOST,
514                                     Configuration.configuration.getHostId());
515       }
516     }
517     if (session.getRemoteAddress() != null) {
518       WaarpStringUtils.replaceAll(builder, REMOTEHOSTADDR,
519                                   session.getRemoteAddress().toString());
520       WaarpStringUtils.replaceAll(builder, LOCALHOSTADDR,
521                                   session.getLocalAddress().toString());
522     } else {
523       WaarpStringUtils.replaceAll(builder, REMOTEHOSTADDR, "unknown");
524       WaarpStringUtils.replaceAll(builder, LOCALHOSTADDR, "unknown");
525     }
526   }
527 
528   private void substituteDate(final StringBuilder builder) {
529     DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
530     final Date date = new Date();
531     WaarpStringUtils.replaceAll(builder, DATE, dateFormat.format(date));
532     dateFormat = new SimpleDateFormat("HHmmss");
533     WaarpStringUtils.replaceAll(builder, HOUR, dateFormat.format(date));
534   }
535 
536   private DbTaskRunner substituteRunner(final StringBuilder builder) {
537     final DbTaskRunner runner = session.getRunner();
538     if (runner != null) {
539       WaarpStringUtils.replaceAll(builder, ORIGINALFULLPATH,
540                                   runner.getOriginalFilename());
541       WaarpStringUtils.replaceAll(builder, ORIGINALFILENAME,
542                                   R66File.getBasename(
543                                       runner.getOriginalFilename()));
544       WaarpStringUtils.replaceAll(builder, RULE, runner.getRuleId());
545       WaarpStringUtils.replaceAll(builder, TRANSFERID,
546                                   Long.toString(runner.getSpecialId()));
547       final String requester = runner.getRequester();
548       WaarpStringUtils.replaceAll(builder, REQUESTERHOST, requester);
549       final String requested = runner.getRequested();
550       WaarpStringUtils.replaceAll(builder, REQUESTEDHOST, requested);
551       WaarpStringUtils.replaceAll(builder, FULLTRANSFERID,
552                                   runner.getSpecialId() + "_" + requester +
553                                   '_' + requested);
554       WaarpStringUtils.replaceAll(builder, RANKTRANSFER,
555                                   Integer.toString(runner.getRank()));
556     }
557     return runner;
558   }
559 
560   private void substituteFile(final StringBuilder builder) {
561     File trueFile = null;
562     if (session.getFile() != null) {
563       trueFile = session.getFile().getTrueFile();
564     }
565     if (trueFile != null) {
566       WaarpStringUtils.replaceAll(builder, TRUEFULLPATH,
567                                   trueFile.getAbsolutePath());
568       WaarpStringUtils.replaceAll(builder, TRUEFILENAME,
569                                   R66Dir.getFinalUniqueFilename(
570                                       session.getFile()));
571       WaarpStringUtils.replaceAll(builder, FILESIZE,
572                                   Long.toString(trueFile.length()));
573     } else {
574       WaarpStringUtils.replaceAll(builder, TRUEFULLPATH, "nofile");
575       WaarpStringUtils.replaceAll(builder, TRUEFILENAME, "nofile");
576       WaarpStringUtils.replaceAll(builder, FILESIZE, "0");
577     }
578   }
579 
580   // Using CommentLine format
581 
582   /**
583    * Generates a substitution map as expected by Apache Commons Exec
584    * CommandLine
585    */
586   protected final Map<String, Object> getSubstitutionMap() {
587     final Map<String, Object> rv = new HashMap<String, Object>();
588     rv.put(
589         COMPILE_HASH.matcher(NOWAIT).replaceAll(Matcher.quoteReplacement("")),
590         "");
591     rv.put(COMPILE_HASH.matcher(LOCALEXEC)
592                        .replaceAll(Matcher.quoteReplacement("")), "");
593     rv.put(
594         COMPILE_HASH.matcher(COMPRESS).replaceAll(Matcher.quoteReplacement("")),
595         "");
596 
597     substituteFile(rv);
598 
599     final DbTaskRunner runner = substituteRunner(rv);
600 
601     substituteDate(rv);
602 
603     substituteHost(rv);
604     rv.put(COMPILE_HASH.matcher(BLOCKSIZE)
605                        .replaceAll(Matcher.quoteReplacement("")),
606            session.getBlockSize());
607 
608     final R66Dir dir = new R66Dir(session);
609     substitutePath(rv, runner, dir);
610     rv.put(
611         COMPILE_HASH.matcher(HOMEPATH).replaceAll(Matcher.quoteReplacement("")),
612         Configuration.configuration.getBaseDirectory());
613     substituteErrorCode(rv);
614     return rv;
615   }
616 
617   private void substituteErrorCode(final Map<String, Object> rv) {
618     if (session.getLocalChannelReference() == null) {
619       rv.put(COMPILE_HASH.matcher(ERRORMSG)
620                          .replaceAll(Matcher.quoteReplacement("")), "NoError");
621       rv.put(COMPILE_HASH.matcher(ERRORCODE)
622                          .replaceAll(Matcher.quoteReplacement("")), "-");
623       rv.put(COMPILE_HASH.matcher(ERRORSTRCODE)
624                          .replaceAll(Matcher.quoteReplacement("")),
625              ErrorCode.Unknown.name());
626     } else {
627       try {
628         rv.put(COMPILE_HASH.matcher(ERRORMSG)
629                            .replaceAll(Matcher.quoteReplacement("")),
630                session.getLocalChannelReference().getErrorMessage());
631       } catch (final NullPointerException e) {
632         rv.put(COMPILE_HASH.matcher(ERRORMSG)
633                            .replaceAll(Matcher.quoteReplacement("")),
634                "NoError");
635       }
636       try {
637         rv.put(COMPILE_HASH.matcher(ERRORCODE)
638                            .replaceAll(Matcher.quoteReplacement("")),
639                session.getLocalChannelReference().getCurrentCode().getCode());
640       } catch (final NullPointerException e) {
641         rv.put(COMPILE_HASH.matcher(ERRORCODE)
642                            .replaceAll(Matcher.quoteReplacement("")), "-");
643       }
644       try {
645         rv.put(COMPILE_HASH.matcher(ERRORSTRCODE)
646                            .replaceAll(Matcher.quoteReplacement("")),
647                session.getLocalChannelReference().getCurrentCode().name());
648       } catch (final NullPointerException e) {
649         rv.put(COMPILE_HASH.matcher(ERRORSTRCODE)
650                            .replaceAll(Matcher.quoteReplacement("")),
651                ErrorCode.Unknown.name());
652       }
653     }
654   }
655 
656   private void substitutePath(final Map<String, Object> rv,
657                               final DbTaskRunner runner, R66Dir dir) {
658     if (runner != null) {
659       if (runner.isRecvThrough() || runner.isSendThrough()) {
660         try {
661           dir.changeDirectoryNotChecked(runner.getRule().getRecvPath());
662           rv.put(COMPILE_HASH.matcher(INPATH)
663                              .replaceAll(Matcher.quoteReplacement("")),
664                  dir.getFullPath());
665         } catch (final CommandAbstractException ignored) {
666           // nothing
667         }
668         dir = new R66Dir(session);
669         try {
670           dir.changeDirectoryNotChecked(runner.getRule().getSendPath());
671           rv.put(COMPILE_HASH.matcher(OUTPATH)
672                              .replaceAll(Matcher.quoteReplacement("")),
673                  dir.getFullPath());
674         } catch (final CommandAbstractException ignored) {
675           // nothing
676         }
677         dir = new R66Dir(session);
678         try {
679           dir.changeDirectoryNotChecked(runner.getRule().getWorkPath());
680           rv.put(COMPILE_HASH.matcher(WORKPATH)
681                              .replaceAll(Matcher.quoteReplacement("")),
682                  dir.getFullPath());
683         } catch (final CommandAbstractException ignored) {
684           // nothing
685         }
686         dir = new R66Dir(session);
687         try {
688           dir.changeDirectoryNotChecked(runner.getRule().getArchivePath());
689           rv.put(COMPILE_HASH.matcher(ARCHPATH)
690                              .replaceAll(Matcher.quoteReplacement("")),
691                  dir.getFullPath());
692         } catch (final CommandAbstractException ignored) {
693           // nothing
694         }
695       } else {
696         try {
697           dir.changeDirectory(runner.getRule().getRecvPath());
698           rv.put(COMPILE_HASH.matcher(INPATH)
699                              .replaceAll(Matcher.quoteReplacement("")),
700                  dir.getFullPath());
701         } catch (final CommandAbstractException ignored) {
702           // nothing
703         }
704         dir = new R66Dir(session);
705         try {
706           dir.changeDirectory(runner.getRule().getSendPath());
707           rv.put(COMPILE_HASH.matcher(OUTPATH)
708                              .replaceAll(Matcher.quoteReplacement("")),
709                  dir.getFullPath());
710         } catch (final CommandAbstractException ignored) {
711           // nothing
712         }
713         dir = new R66Dir(session);
714         try {
715           dir.changeDirectory(runner.getRule().getWorkPath());
716           rv.put(COMPILE_HASH.matcher(WORKPATH)
717                              .replaceAll(Matcher.quoteReplacement("")),
718                  dir.getFullPath());
719         } catch (final CommandAbstractException ignored) {
720           // nothing
721         }
722         dir = new R66Dir(session);
723         try {
724           dir.changeDirectory(runner.getRule().getArchivePath());
725           rv.put(COMPILE_HASH.matcher(ARCHPATH)
726                              .replaceAll(Matcher.quoteReplacement("")),
727                  dir.getFullPath());
728         } catch (final CommandAbstractException ignored) {
729           // nothing
730         }
731       }
732     } else {
733       try {
734         dir.changeDirectory(Configuration.configuration.getInPath());
735         rv.put(COMPILE_HASH.matcher(INPATH)
736                            .replaceAll(Matcher.quoteReplacement("")),
737                dir.getFullPath());
738       } catch (final CommandAbstractException ignored) {
739         // nothing
740       }
741       dir = new R66Dir(session);
742       try {
743         dir.changeDirectory(Configuration.configuration.getOutPath());
744         rv.put(COMPILE_HASH.matcher(OUTPATH)
745                            .replaceAll(Matcher.quoteReplacement("")),
746                dir.getFullPath());
747       } catch (final CommandAbstractException ignored) {
748         // nothing
749       }
750       dir = new R66Dir(session);
751       try {
752         dir.changeDirectory(Configuration.configuration.getWorkingPath());
753         rv.put(COMPILE_HASH.matcher(WORKPATH)
754                            .replaceAll(Matcher.quoteReplacement("")),
755                dir.getFullPath());
756       } catch (final CommandAbstractException ignored) {
757         // nothing
758       }
759       dir = new R66Dir(session);
760       try {
761         dir.changeDirectory(Configuration.configuration.getArchivePath());
762         rv.put(COMPILE_HASH.matcher(ARCHPATH)
763                            .replaceAll(Matcher.quoteReplacement("")),
764                dir.getFullPath());
765       } catch (final CommandAbstractException ignored) {
766         // nothing
767       }
768     }
769   }
770 
771   private void substituteHost(final Map<String, Object> rv) {
772     if (session.getAuth() != null) {
773       rv.put(COMPILE_HASH.matcher(REMOTEHOST)
774                          .replaceAll(Matcher.quoteReplacement("")),
775              session.getAuth().getUser());
776       String localhost;
777       try {
778         localhost =
779             Configuration.configuration.getHostId(session.getAuth().isSsl());
780       } catch (final OpenR66ProtocolNoSslException e) {
781         // replace by standard name
782         localhost = Configuration.configuration.getHostId();
783       }
784       rv.put(COMPILE_HASH.matcher(LOCALHOST)
785                          .replaceAll(Matcher.quoteReplacement("")), localhost);
786     }
787     if (session.getRemoteAddress() != null) {
788       rv.put(COMPILE_HASH.matcher(REMOTEHOSTADDR)
789                          .replaceAll(Matcher.quoteReplacement("")),
790              session.getRemoteAddress().toString());
791       rv.put(COMPILE_HASH.matcher(LOCALHOSTADDR)
792                          .replaceAll(Matcher.quoteReplacement("")),
793              session.getLocalAddress().toString());
794     } else {
795       rv.put(COMPILE_HASH.matcher(REMOTEHOSTADDR)
796                          .replaceAll(Matcher.quoteReplacement("")), "unknown");
797       rv.put(COMPILE_HASH.matcher(LOCALHOSTADDR)
798                          .replaceAll(Matcher.quoteReplacement("")), "unknown");
799     }
800   }
801 
802   private void substituteDate(final Map<String, Object> rv) {
803     DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
804     final Date date = new Date();
805     rv.put(COMPILE_HASH.matcher(DATE).replaceAll(Matcher.quoteReplacement("")),
806            dateFormat.format(date));
807     dateFormat = new SimpleDateFormat("HHmmss");
808     rv.put(COMPILE_HASH.matcher(HOUR).replaceAll(Matcher.quoteReplacement("")),
809            dateFormat.format(date));
810   }
811 
812   private DbTaskRunner substituteRunner(final Map<String, Object> rv) {
813     final DbTaskRunner runner = session.getRunner();
814     if (runner != null) {
815       rv.put(COMPILE_HASH.matcher(ORIGINALFULLPATH)
816                          .replaceAll(Matcher.quoteReplacement("")),
817              runner.getOriginalFilename());
818       rv.put(COMPILE_HASH.matcher(ORIGINALFILENAME)
819                          .replaceAll(Matcher.quoteReplacement("")),
820              R66File.getBasename(runner.getOriginalFilename()));
821       rv.put(
822           COMPILE_HASH.matcher(RULE).replaceAll(Matcher.quoteReplacement("")),
823           runner.getRuleId());
824     }
825     if (runner != null) {
826       rv.put(COMPILE_HASH.matcher(TRANSFERID)
827                          .replaceAll(Matcher.quoteReplacement("")),
828              runner.getSpecialId());
829       rv.put(COMPILE_HASH.matcher(REQUESTERHOST)
830                          .replaceAll(Matcher.quoteReplacement("")),
831              runner.getRequester());
832       rv.put(COMPILE_HASH.matcher(REQUESTEDHOST)
833                          .replaceAll(Matcher.quoteReplacement("")),
834              runner.getRequested());
835       rv.put(COMPILE_HASH.matcher(FULLTRANSFERID)
836                          .replaceAll(Matcher.quoteReplacement("")),
837              runner.getSpecialId() + "_" + runner.getRequester() + '_' +
838              runner.getRequested());
839       rv.put(COMPILE_HASH.matcher(RANKTRANSFER)
840                          .replaceAll(Matcher.quoteReplacement("")),
841              Integer.toString(runner.getRank()));
842     }
843     return runner;
844   }
845 
846   private void substituteFile(final Map<String, Object> rv) {
847     File trueFile = null;
848     if (session.getFile() != null) {
849       trueFile = session.getFile().getTrueFile();
850     }
851     if (trueFile != null) {
852       rv.put(COMPILE_HASH.matcher(TRUEFULLPATH)
853                          .replaceAll(Matcher.quoteReplacement("")),
854              trueFile.getAbsolutePath());
855       rv.put(COMPILE_HASH.matcher(TRUEFILENAME)
856                          .replaceAll(Matcher.quoteReplacement("")),
857              R66Dir.getFinalUniqueFilename(session.getFile()));
858       rv.put(COMPILE_HASH.matcher(FILESIZE)
859                          .replaceAll(Matcher.quoteReplacement("")),
860              Long.toString(trueFile.length()));
861     } else {
862       rv.put(COMPILE_HASH.matcher(TRUEFULLPATH)
863                          .replaceAll(Matcher.quoteReplacement("")), "nofile");
864       rv.put(COMPILE_HASH.matcher(TRUEFILENAME)
865                          .replaceAll(Matcher.quoteReplacement("")), "nofile");
866       rv.put(COMPILE_HASH.matcher(FILESIZE)
867                          .replaceAll(Matcher.quoteReplacement("")), "0");
868     }
869   }
870 
871 }