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.database.data;
21  
22  import com.fasterxml.jackson.databind.JsonNode;
23  import com.fasterxml.jackson.databind.node.ArrayNode;
24  import com.fasterxml.jackson.databind.node.ObjectNode;
25  import org.dom4j.Document;
26  import org.dom4j.DocumentException;
27  import org.waarp.common.database.DbConstant;
28  import org.waarp.common.database.DbPreparedStatement;
29  import org.waarp.common.database.DbSession;
30  import org.waarp.common.database.exception.WaarpDatabaseException;
31  import org.waarp.common.database.exception.WaarpDatabaseNoConnectionException;
32  import org.waarp.common.database.exception.WaarpDatabaseNoDataException;
33  import org.waarp.common.database.exception.WaarpDatabaseSqlException;
34  import org.waarp.common.file.DirInterface;
35  import org.waarp.common.file.FileUtils;
36  import org.waarp.common.json.JsonHandler;
37  import org.waarp.common.logging.WaarpLogger;
38  import org.waarp.common.logging.WaarpLoggerFactory;
39  import org.waarp.common.utility.ParametersChecker;
40  import org.waarp.common.utility.WaarpStringUtils;
41  import org.waarp.common.xml.XmlUtil;
42  import org.waarp.common.xml.XmlValue;
43  import org.waarp.openr66.configuration.RuleFileBasedConfiguration;
44  import org.waarp.openr66.context.R66Session;
45  import org.waarp.openr66.dao.AbstractDAO;
46  import org.waarp.openr66.dao.DAOFactory;
47  import org.waarp.openr66.dao.Filter;
48  import org.waarp.openr66.dao.RuleDAO;
49  import org.waarp.openr66.dao.database.DBRuleDAO;
50  import org.waarp.openr66.dao.database.StatementExecutor;
51  import org.waarp.openr66.dao.exception.DAOConnectionException;
52  import org.waarp.openr66.dao.exception.DAONoDataException;
53  import org.waarp.openr66.database.data.DbTaskRunner.TASKSTEP;
54  import org.waarp.openr66.pojo.Rule;
55  import org.waarp.openr66.pojo.RuleTask;
56  import org.waarp.openr66.pojo.Transfer;
57  import org.waarp.openr66.protocol.configuration.Configuration;
58  import org.waarp.openr66.protocol.localhandler.packet.RequestPacket;
59  
60  import java.io.File;
61  import java.io.StringReader;
62  import java.sql.SQLException;
63  import java.sql.Types;
64  import java.util.ArrayList;
65  import java.util.Arrays;
66  import java.util.List;
67  
68  /**
69   * Rule Table object
70   */
71  public class DbRule extends AbstractDbDataDao<Rule> {
72    private static final String RULE_NOT_FOUND = "Rule not found";
73    /**
74     * Internal Logger
75     */
76    private static final WaarpLogger logger =
77        WaarpLoggerFactory.getLogger(DbRule.class);
78    private static final String[] STRING_0_LENGTH = new String[0];
79    private static final String[][] STRINGS_0_0_LENGTH = new String[0][0];
80  
81    public enum Columns {
82      HOSTIDS, MODETRANS, RECVPATH, SENDPATH, ARCHIVEPATH, WORKPATH, RPRETASKS,
83      RPOSTTASKS, RERRORTASKS, SPRETASKS, SPOSTTASKS, SERRORTASKS, UPDATEDINFO,
84      IDRULE
85    }
86  
87    public static final int[] dbTypes = {
88        Types.LONGVARCHAR, Types.INTEGER, Types.VARCHAR, Types.VARCHAR,
89        Types.VARCHAR, Types.VARCHAR, Types.LONGVARCHAR, Types.LONGVARCHAR,
90        Types.LONGVARCHAR, Types.LONGVARCHAR, Types.LONGVARCHAR,
91        Types.LONGVARCHAR, Types.INTEGER, Types.NVARCHAR
92    };
93  
94    public static final String table = " RULES ";
95  
96    public static final Columns[] indexes = {
97        Columns.UPDATEDINFO
98    };
99  
100   /**
101    * Internal context XML fields
102    */
103   public static final String TASK_TYPE = "type";
104 
105   /**
106    * Internal context XML fields
107    */
108   public static final String TASK_PATH = "path";
109 
110   /**
111    * Internal context XML fields
112    */
113   public static final String TASK_DELAY = "delay";
114   /**
115    * Internal context XML fields
116    */
117   public static final String TASK_RANK = "rank";
118   /**
119    * Internal context XML fields
120    */
121   public static final String TASK_COMMENT = "comment";
122 
123   protected static final String selectAllFields =
124       Columns.HOSTIDS.name() + ',' + Columns.MODETRANS.name() + ',' +
125       Columns.RECVPATH.name() + ',' + Columns.SENDPATH.name() + ',' +
126       Columns.ARCHIVEPATH.name() + ',' + Columns.WORKPATH.name() + ',' +
127       Columns.RPRETASKS.name() + ',' + Columns.RPOSTTASKS.name() + ',' +
128       Columns.RERRORTASKS.name() + ',' + Columns.SPRETASKS.name() + ',' +
129       Columns.SPOSTTASKS.name() + ',' + Columns.SERRORTASKS.name() + ',' +
130       Columns.UPDATEDINFO.name() + ',' + Columns.IDRULE.name();
131 
132   @Override
133   protected final void initObject() {
134     // Nothing
135   }
136 
137   @Override
138   protected final String getTable() {
139     return table;
140   }
141 
142   @Override
143   protected final AbstractDAO<Rule> getDao(final boolean isCacheable)
144       throws DAOConnectionException {
145     return DAOFactory.getInstance().getRuleDAO(isCacheable);
146   }
147 
148   @Override
149   protected final String getPrimaryKey() {
150     if (pojo != null) {
151       return pojo.getName();
152     }
153     throw new IllegalArgumentException("pojo is null");
154   }
155 
156   @Override
157   protected final String getPrimaryField() {
158     return Columns.IDRULE.name();
159   }
160 
161   protected final void checkPathes() throws WaarpDatabaseSqlException {
162     if (ParametersChecker.isNotEmpty(getRecvPath()) &&
163         getRecvPath().charAt(0) != DirInterface.SEPARATORCHAR) {
164       pojo.setRecvPath(DirInterface.SEPARATOR + getRecvPath());
165     }
166     if (ParametersChecker.isNotEmpty(getSendPath()) &&
167         getSendPath().charAt(0) != DirInterface.SEPARATORCHAR) {
168       pojo.setSendPath(DirInterface.SEPARATOR + getSendPath());
169     }
170     if (ParametersChecker.isNotEmpty(getArchivePath()) &&
171         getArchivePath().charAt(0) != DirInterface.SEPARATORCHAR) {
172       pojo.setArchivePath(DirInterface.SEPARATOR + getArchivePath());
173     }
174     if (ParametersChecker.isNotEmpty(getWorkPath()) &&
175         getWorkPath().charAt(0) != DirInterface.SEPARATORCHAR) {
176       pojo.setWorkPath(DirInterface.SEPARATOR + getWorkPath());
177     }
178   }
179 
180   /**
181    * @param idRule
182    * @param ids
183    * @param mode
184    * @param recvPath
185    * @param sendPath
186    * @param archivePath
187    * @param workPath
188    * @param rpreTasks
189    * @param rpostTasks
190    * @param rerrorTasks
191    * @param spreTasks
192    * @param spostTasks
193    * @param serrorTasks
194    */
195   public DbRule(final String idRule, final String ids, final int mode,
196                 final String recvPath, final String sendPath,
197                 final String archivePath, final String workPath,
198                 final String rpreTasks, final String rpostTasks,
199                 final String rerrorTasks, final String spreTasks,
200                 final String spostTasks, final String serrorTasks)
201       throws WaarpDatabaseSqlException {
202     pojo = new Rule(idRule, mode, Arrays.asList(getIdsRule(ids)), recvPath,
203                     sendPath, archivePath, workPath,
204                     fromLegacyTasks(getTasksRule(rpreTasks)),
205                     fromLegacyTasks(getTasksRule(rpostTasks)),
206                     fromLegacyTasks(getTasksRule(rerrorTasks)),
207                     fromLegacyTasks(getTasksRule(spreTasks)),
208                     fromLegacyTasks(getTasksRule(spostTasks)),
209                     fromLegacyTasks(getTasksRule(serrorTasks)));
210     checkPathes();
211   }
212 
213   /**
214    * @param idRule
215    *
216    * @throws WaarpDatabaseException
217    */
218   public DbRule(final String idRule) throws WaarpDatabaseException {
219     RuleDAO ruleAccess = null;
220     try {
221       ruleAccess = DAOFactory.getInstance().getRuleDAO(true);
222       pojo = ruleAccess.select(idRule);
223     } catch (final DAOConnectionException e) {
224       throw new WaarpDatabaseException(e);
225     } catch (final DAONoDataException e) {
226       throw new WaarpDatabaseNoDataException(RULE_NOT_FOUND + " " + idRule, e);
227     } finally {
228       DAOFactory.closeDAO(ruleAccess);
229     }
230     checkPathes();
231   }
232 
233   public DbRule(final Rule rule) {
234     if (rule == null) {
235       throw new IllegalArgumentException(
236           "Argument in constructor cannot be null");
237     }
238     this.pojo = rule;
239     try {
240       checkPathes();
241     } catch (final WaarpDatabaseSqlException e) {
242       throw new IllegalArgumentException(e);
243     }
244   }
245 
246   /**
247    * Constructor used from XML file
248    *
249    * @param idrule
250    * @param idsArrayRef
251    * @param recvpath
252    * @param sendpath
253    * @param archivepath
254    * @param workpath
255    * @param rpretasksArray
256    * @param rposttasksArray
257    * @param rerrortasksArray
258    * @param spretasksArray
259    * @param sposttasksArray
260    * @param serrortasksArray
261    */
262   public DbRule(final String idrule, String[] idsArrayRef, final int mode,
263                 final String recvpath, final String sendpath,
264                 final String archivepath, final String workpath,
265                 final String[][] rpretasksArray,
266                 final String[][] rposttasksArray,
267                 final String[][] rerrortasksArray,
268                 final String[][] spretasksArray,
269                 final String[][] sposttasksArray,
270                 final String[][] serrortasksArray)
271       throws WaarpDatabaseSqlException {
272     if (idsArrayRef == null) {
273       idsArrayRef = STRING_0_LENGTH;
274     }
275     pojo =
276         new Rule(idrule, mode, Arrays.asList(idsArrayRef), recvpath, sendpath,
277                  archivepath, workpath, fromLegacyTasks(rpretasksArray),
278                  fromLegacyTasks(rposttasksArray),
279                  fromLegacyTasks(rerrortasksArray),
280                  fromLegacyTasks(spretasksArray),
281                  fromLegacyTasks(sposttasksArray),
282                  fromLegacyTasks(serrortasksArray));
283     checkPathes();
284   }
285 
286   /**
287    * Constructor from Json
288    *
289    * @param source
290    *
291    * @throws WaarpDatabaseSqlException
292    */
293   public DbRule(final ObjectNode source) throws WaarpDatabaseSqlException {
294     pojo = new Rule();
295     setFromJson(source, false);
296     if (ParametersChecker.isEmpty(getIdRule())) {
297       throw new WaarpDatabaseSqlException(
298           "Not enough argument to create the object");
299     }
300     checkPathes();
301   }
302 
303   @Override
304   protected final void checkValues() throws WaarpDatabaseSqlException {
305     pojo.checkValues();
306   }
307 
308   @Override
309   public final void setFromJson(final ObjectNode node,
310                                 final boolean ignorePrimaryKey)
311       throws WaarpDatabaseSqlException {
312     super.setFromJson(node, ignorePrimaryKey);
313     checkPathes();
314   }
315 
316   @Override
317   protected final void setFromJson(final String field, final JsonNode value)
318       throws WaarpDatabaseSqlException {
319     if (value == null) {
320       return;
321     }
322     for (final Columns column : Columns.values()) {
323       if (column.name().equalsIgnoreCase(field)) {
324         switch (column) {
325           case ARCHIVEPATH:
326             pojo.setArchivePath(value.asText());
327             break;
328           case HOSTIDS:
329             pojo.setHostids(Arrays.asList(getIdsRule(value.asText())));
330             break;
331           case IDRULE:
332             pojo.setName(value.asText());
333             break;
334           case MODETRANS:
335             pojo.setMode(value.asInt());
336             break;
337           case RECVPATH:
338             pojo.setRecvPath(value.asText());
339             break;
340           case RERRORTASKS:
341             pojo.setRErrorTasks(fromLegacyTasks(getTasksRule(value.asText())));
342             break;
343           case RPOSTTASKS:
344             pojo.setRPostTasks(fromLegacyTasks(getTasksRule(value.asText())));
345             break;
346           case RPRETASKS:
347             pojo.setRPreTasks(fromLegacyTasks(getTasksRule(value.asText())));
348             break;
349           case SENDPATH:
350             pojo.setSendPath(value.asText());
351             break;
352           case SERRORTASKS:
353             pojo.setSErrorTasks(fromLegacyTasks(getTasksRule(value.asText())));
354             break;
355           case SPOSTTASKS:
356             pojo.setSPostTasks(fromLegacyTasks(getTasksRule(value.asText())));
357             break;
358           case SPRETASKS:
359             pojo.setSPreTasks(fromLegacyTasks(getTasksRule(value.asText())));
360             break;
361           case WORKPATH:
362             pojo.setWorkPath(value.asText());
363             break;
364           case UPDATEDINFO:
365             pojo.setUpdatedInfo(
366                 org.waarp.openr66.pojo.UpdatedInfo.valueOf(value.asInt()));
367             break;
368         }
369       }
370     }
371     checkPathes();
372   }
373 
374   /**
375    * Private constructor for Commander only
376    */
377   private DbRule() {
378     pojo = new Rule();
379   }
380 
381   /**
382    * Delete object from table DbRule only if no DbTaskRunner is using it.
383    *
384    * @throws WaarpDatabaseException
385    */
386   @Override
387   public final void delete() throws WaarpDatabaseException {
388     AbstractDAO<Transfer> transferDAO = null;
389     try {
390       transferDAO = DAOFactory.getInstance().getTransferDAO();
391       final List<Filter> filters = new ArrayList<Filter>();
392       final Filter filter =
393           new Filter(DbTaskRunner.Columns.IDRULE.name(), "=", this.getIdRule());
394       filters.add(filter);
395       final long nb = transferDAO.count(filters);
396       if (nb > 0) {
397         throw new WaarpDatabaseNoDataException("Rule " + this.getIdRule() +
398                                                " is still used by TaskRunner therefore it cannot be deleted.");
399       }
400     } catch (final DAOConnectionException e) {
401       throw new WaarpDatabaseNoConnectionException(e);
402     } finally {
403       DAOFactory.closeDAO(transferDAO);
404     }
405     super.delete();
406   }
407 
408   /**
409    * Delete all Rules but returns original one, therefore not checking if
410    * any TaskRunner are using it (used by reloading rules)
411    *
412    * @return the previously existing DbRule
413    *
414    * @throws WaarpDatabaseException
415    */
416   public static DbRule[] deleteAll() throws WaarpDatabaseException {
417     RuleDAO ruleAccess = null;
418     List<Rule> rules;
419     try {
420       ruleAccess = DAOFactory.getInstance().getRuleDAO(false);
421       rules = ruleAccess.getAll();
422       ruleAccess.deleteAll();
423     } catch (final DAOConnectionException e) {
424       throw new WaarpDatabaseException(e);
425     } finally {
426       DAOFactory.closeDAO(ruleAccess);
427     }
428     final DbRule[] res = new DbRule[rules.size()];
429     int i = 0;
430     for (final Rule rule : rules) {
431       res[i] = new DbRule(rule);
432       res[i].isSaved = false;
433       i++;
434     }
435     return res;
436   }
437 
438   /**
439    * Get All DbRule from database or from internal hashMap in case of no
440    * database support
441    *
442    * @return the array of DbRule
443    *
444    * @throws WaarpDatabaseNoConnectionException
445    * @throws WaarpDatabaseSqlException
446    */
447   public static DbRule[] getAllRules()
448       throws WaarpDatabaseNoConnectionException {
449     RuleDAO ruleAccess = null;
450     List<Rule> rules;
451     try {
452       ruleAccess = DAOFactory.getInstance().getRuleDAO(false);
453       rules = ruleAccess.getAll();
454     } catch (final DAOConnectionException e) {
455       throw new WaarpDatabaseNoConnectionException(e);
456     } finally {
457       DAOFactory.closeDAO(ruleAccess);
458     }
459     final DbRule[] res = new DbRule[rules.size()];
460     int i = 0;
461     for (final Rule rule : rules) {
462       res[i] = new DbRule(rule);
463       i++;
464     }
465     return res;
466   }
467 
468   /**
469    * For instance from Commander when getting updated information
470    *
471    * @param preparedStatement
472    *
473    * @return the next updated DbRule
474    *
475    * @throws WaarpDatabaseNoConnectionException
476    * @throws WaarpDatabaseSqlException
477    */
478   public static DbRule getFromStatement(
479       final DbPreparedStatement preparedStatement)
480       throws WaarpDatabaseNoConnectionException, WaarpDatabaseSqlException {
481     final DbRule dbRule = new DbRule();
482     AbstractDAO<Rule> ruleDAO = null;
483     try {
484       ruleDAO = dbRule.getDao(false);
485       dbRule.pojo = ((StatementExecutor<Rule>) ruleDAO).getFromResultSet(
486           preparedStatement.getResultSet());
487       return dbRule;
488     } catch (final SQLException e) {
489       DbConstant.error(e);
490       throw new WaarpDatabaseSqlException("Getting values in error", e);
491     } catch (final DAOConnectionException e) {
492       throw new WaarpDatabaseSqlException("Getting values in error", e);
493     } finally {
494       DAOFactory.closeDAO(ruleDAO);
495     }
496   }
497 
498   /**
499    * @return the DbPreparedStatement for getting Updated Object
500    *
501    * @throws WaarpDatabaseNoConnectionException
502    */
503   public static DbRule[] getUpdatedPrepareStament()
504       throws WaarpDatabaseNoConnectionException {
505     final List<Filter> filters = new ArrayList<Filter>(1);
506     filters.add(new Filter(DBRuleDAO.UPDATED_INFO_FIELD, "=",
507                            org.waarp.openr66.pojo.UpdatedInfo.fromLegacy(
508                                UpdatedInfo.TOSUBMIT).ordinal()));
509     RuleDAO ruleAccess = null;
510     List<Rule> rules;
511     try {
512       ruleAccess = DAOFactory.getInstance().getRuleDAO(false);
513       rules = ruleAccess.find(filters);
514     } catch (final DAOConnectionException e) {
515       throw new WaarpDatabaseNoConnectionException(e);
516     } finally {
517       DAOFactory.closeDAO(ruleAccess);
518     }
519     final DbRule[] res = new DbRule[rules.size()];
520     int i = 0;
521     for (final Rule rule : rules) {
522       res[i] = new DbRule(rule);
523       i++;
524     }
525     return res;
526   }
527 
528   @Override
529   public final void changeUpdatedInfo(final UpdatedInfo info) {
530     isSaved = false;
531     pojo.setUpdatedInfo(org.waarp.openr66.pojo.UpdatedInfo.fromLegacy(info));
532   }
533 
534   /**
535    * Get Ids from String. If it is not ok, then it sets the default values and
536    * return False, else returns True.
537    *
538    * @param idsref
539    *
540    * @return True if ok, else False (default values).
541    */
542   private String[] getIdsRule(final String idsref) {
543     if (ParametersChecker.isEmpty(idsref)) {
544       // No ids so setting to the default!
545       return STRING_0_LENGTH;
546     }
547     final StringReader reader = new StringReader(idsref);
548     final Document document;
549     try {
550       document = XmlUtil.getNewSaxReader().read(reader);
551       final XmlValue[] values =
552           XmlUtil.read(document, RuleFileBasedConfiguration.hostsDecls);
553       return RuleFileBasedConfiguration.getHostIds(values[0]);
554     } catch (final DocumentException e) {
555       logger.warn("Unable to read the ids for Rule: " + idsref + " : {}",
556                   e.getMessage());
557       // No ids so setting to the default!
558       return STRING_0_LENGTH;
559     } finally {
560       FileUtils.close(reader);
561     }
562   }
563 
564   /**
565    * Get Tasks from String. If it is not ok, then it sets the default values
566    * and
567    * return new array of Tasks or
568    * null if in error.
569    *
570    * @param tasks
571    *
572    * @return Array of tasks or empty array if in error.
573    */
574   private String[][] getTasksRule(final String tasks) {
575     if (ParametersChecker.isEmpty(tasks)) {
576       // No tasks so setting to the default!
577       return STRINGS_0_0_LENGTH;
578     }
579     final StringReader reader = new StringReader(tasks);
580     final Document document;
581     try {
582       document = XmlUtil.getNewSaxReader().read(reader);
583     } catch (final DocumentException e) {
584       // No tasks so setting to the default!
585       FileUtils.close(reader);
586       return STRINGS_0_0_LENGTH;
587     }
588     final XmlValue[] values =
589         XmlUtil.read(document, RuleFileBasedConfiguration.tasksDecl);
590     final String[][] result =
591         RuleFileBasedConfiguration.getTasksRule(values[0]);
592     FileUtils.close(reader);
593     return result;
594   }
595 
596   /**
597    * Get the full path from RecvPath (used only in copy MODETRANS)
598    *
599    * @param filename
600    *
601    * @return the full String path
602    */
603   public final String setRecvPath(final String filename) {
604     if (ParametersChecker.isNotEmpty(pojo.getRecvPath())) {
605       return pojo.getRecvPath() + DirInterface.SEPARATOR + filename;
606     }
607     return Configuration.configuration.getInPath() + DirInterface.SEPARATOR +
608            filename;
609   }
610 
611   /**
612    * Get the full path from sendPath
613    *
614    * @param filename
615    *
616    * @return the full String path
617    */
618   public final String setSendPath(final String filename) {
619     if (pojo.getSendPath() != null) {
620       final File file = new File(filename);
621       final String basename = file.getName();
622       return pojo.getSendPath() + DirInterface.SEPARATOR + basename;
623     }
624     return Configuration.configuration.getOutPath() + DirInterface.SEPARATOR +
625            filename;
626   }
627 
628   /**
629    * Get the full path from archivePath
630    *
631    * @param filename
632    *
633    * @return the full String path
634    */
635   public final String setArchivePath(final String filename) {
636     if (pojo.getArchivePath() != null) {
637       return pojo.getArchivePath() + DirInterface.SEPARATOR + filename;
638     }
639     return Configuration.configuration.getArchivePath() +
640            DirInterface.SEPARATOR + filename;
641   }
642 
643   /**
644    * Get the full path from workPath
645    *
646    * @param filename
647    *
648    * @return the full String path
649    */
650   public final String setWorkingPath(final String filename) {
651     if (pojo.getWorkPath() != null) {
652       return pojo.getWorkPath() + DirInterface.SEPARATOR + filename +
653              Configuration.EXT_R66;
654     }
655     return Configuration.configuration.getWorkingPath() +
656            DirInterface.SEPARATOR + filename;
657   }
658 
659   /**
660    * Check if the given hostTo is in the allowed list
661    *
662    * @param hostId
663    *
664    * @return True if allow, else False
665    */
666   public final boolean checkHostAllow(final String hostId) {
667     if (getIdsArray() == null || getIdsArray().length == 0) {
668       return true; // always true in this case
669     }
670     for (final String element : getIdsArray()) {
671       if (element.equalsIgnoreCase(hostId)) {
672         return true;
673       }
674     }
675     return false;
676   }
677 
678   /**
679    * @return True if this rule is adapted for SENDMODE
680    */
681   public final boolean isSendMode() {
682     return !RequestPacket.isRecvMode(getMode());
683   }
684 
685   /**
686    * @return True if this rule is adapted for RECVMODE
687    */
688   public final boolean isRecvMode() {
689     return RequestPacket.isRecvMode(getMode());
690   }
691 
692   /**
693    * Object to String
694    *
695    * @return the string that displays this object
696    *
697    * @see Object#toString()
698    */
699   @Override
700   public final String toString() {
701     return "Rule Name:" + getIdRule() + " IDS:" + pojo.getXMLHostids() +
702            " MODETRANS: " + RequestPacket.TRANSFERMODE.values()[getMode()] +
703            " RECV:" + getRecvPath() + " SEND:" + getSendPath() + " ARCHIVE:" +
704            getArchivePath() + " WORK:" + getWorkPath() + " RPRET:{" +
705            pojo.getXMLRPreTasks().replace('\n', ' ') + "} RPOST:{" +
706            pojo.getXMLRPostTasks().replace('\n', ' ') + "} RERROR:{" +
707            pojo.getXMLRErrorTasks().replace('\n', ' ') + "} SPRET:{" +
708            pojo.getXMLSPreTasks().replace('\n', ' ') + "} SPOST:{" +
709            pojo.getXMLSPostTasks().replace('\n', ' ') + "} SERROR:{" +
710            pojo.getXMLSErrorTasks().replace('\n', ' ') + '}';
711   }
712 
713   /**
714    * @param isSender
715    * @param step
716    *
717    * @return a string that prints (debug) the tasks to execute
718    */
719   public final String printTasks(final boolean isSender, final TASKSTEP step) {
720     if (isSender) {
721       switch (step) {
722         case PRETASK:
723           return "S:{" + pojo.getXMLSPreTasks().replace('\n', ' ') + '}';
724         case POSTTASK:
725           return "S:{" + pojo.getXMLSPostTasks().replace('\n', ' ') + '}';
726         case ERRORTASK:
727           return "S:{" + pojo.getXMLSErrorTasks().replace('\n', ' ') + '}';
728         default:
729           return "S:{no task}";
730       }
731     } else {
732       switch (step) {
733         case PRETASK:
734           return "R:{" + pojo.getXMLRPreTasks().replace('\n', ' ') + '}';
735         case POSTTASK:
736           return "R:{" + pojo.getXMLRPostTasks().replace('\n', ' ') + '}';
737         case ERRORTASK:
738           return "R:{" + pojo.getXMLRErrorTasks().replace('\n', ' ') + '}';
739         default:
740           return "R:{no task}";
741       }
742     }
743   }
744 
745   /**
746    * Object to String
747    *
748    * @return the string that displays this object
749    *
750    * @see Object#toString()
751    */
752   public final String toShortString() {
753     return "Rule Name:" + getIdRule() + " MODETRANS: " +
754            RequestPacket.TRANSFERMODE.values()[getMode()];
755   }
756 
757   /**
758    * @param session
759    * @param rule
760    * @param mode
761    *
762    * @return the DbPreparedStatement according to the filter
763    *
764    * @throws WaarpDatabaseNoConnectionException
765    * @throws WaarpDatabaseSqlException
766    */
767   public static DbPreparedStatement getFilterPrepareStament(
768       final DbSession session, final String rule, final int mode)
769       throws WaarpDatabaseNoConnectionException, WaarpDatabaseSqlException {
770     final DbPreparedStatement preparedStatement =
771         new DbPreparedStatement(session);
772     final String request = "SELECT " + selectAllFields + " FROM " + table;
773     String condition = null;
774     if (ParametersChecker.isNotEmpty(rule)) {
775       condition = " WHERE " + Columns.IDRULE.name() + " = '" + rule + "' ";
776     }
777     if (mode >= 0) {
778       if (condition != null) {
779         condition += " AND ";
780       } else {
781         condition = " WHERE ";
782       }
783       condition += Columns.MODETRANS.name() + " = ?";
784     } else {
785       condition = "";
786     }
787     preparedStatement.createPrepareStatement(
788         request + condition + " ORDER BY " + Columns.IDRULE.name());
789     if (mode >= 0) {
790       try {
791         preparedStatement.getPreparedStatement().setInt(1, mode);
792       } catch (final SQLException e) {
793         preparedStatement.realClose();
794         throw new WaarpDatabaseSqlException(e);
795       }
796     }
797     return preparedStatement;
798   }
799 
800   /**
801    * Write selected DbRule to a Json String
802    *
803    * @param preparedStatement
804    *
805    * @return the associated Json String
806    *
807    * @throws WaarpDatabaseNoConnectionException
808    * @throws WaarpDatabaseSqlException
809    */
810   public static String getJson(final DbPreparedStatement preparedStatement,
811                                final int limit)
812       throws WaarpDatabaseNoConnectionException, WaarpDatabaseSqlException {
813     final ArrayNode arrayNode = JsonHandler.createArrayNode();
814     try {
815       preparedStatement.executeQuery();
816       int nb = 0;
817       while (preparedStatement.getNext()) {
818         final DbRule rule = getFromStatement(preparedStatement);
819         final ObjectNode node = rule.getInternalJson();
820         arrayNode.add(node);
821         nb++;
822         if (nb >= limit) {
823           break;
824         }
825       }
826     } finally {
827       preparedStatement.realClose();
828     }
829     // \n is not correctly parsed within HTML so put double \\n in fine
830     return WaarpStringUtils.cleanJsonForHtml(
831         JsonHandler.writeAsString(arrayNode));
832   }
833 
834   private ObjectNode getInternalJson() {
835     final ObjectNode node = getJson();
836     if (pojo.getHostids().isEmpty()) {
837       node.put(Columns.HOSTIDS.name(), "");
838     }
839     if (pojo.getRecvPath() == null) {
840       node.put(Columns.RECVPATH.name(), "");
841     }
842     if (pojo.getSendPath() == null) {
843       node.put(Columns.SENDPATH.name(), "");
844     }
845     if (pojo.getArchivePath() == null) {
846       node.put(Columns.ARCHIVEPATH.name(), "");
847     }
848     if (pojo.getWorkPath() == null) {
849       node.put(Columns.WORKPATH.name(), "");
850     }
851     if (pojo.getRPreTasks().isEmpty()) {
852       node.put(Columns.RPRETASKS.name(), "");
853     }
854     if (pojo.getRPostTasks().isEmpty()) {
855       node.put(Columns.RPOSTTASKS.name(), "");
856     }
857     if (pojo.getRErrorTasks().isEmpty()) {
858       node.put(Columns.RERRORTASKS.name(), "");
859     }
860     if (pojo.getSPreTasks().isEmpty()) {
861       node.put(Columns.SPRETASKS.name(), "");
862     }
863     if (pojo.getSPostTasks().isEmpty()) {
864       node.put(Columns.SPOSTTASKS.name(), "");
865     }
866     if (pojo.getSErrorTasks().isEmpty()) {
867       node.put(Columns.SERRORTASKS.name(), "");
868     }
869     return node;
870   }
871 
872   /**
873    * @return the Json string for this
874    */
875   public final String getJsonAsString() {
876     final ObjectNode node = getInternalJson();
877     return WaarpStringUtils.cleanJsonForHtml(JsonHandler.writeAsString(node));
878   }
879 
880   /**
881    * @param session
882    * @param body
883    *
884    * @return the runner in Html format specified by body by replacing all
885    *     instance of fields
886    */
887   public final String toSpecializedHtml(final R66Session session,
888                                         final String body) {
889     final StringBuilder builder = new StringBuilder(body);
890     WaarpStringUtils.replace(builder, "XXXRULEXXX", getIdRule());
891     WaarpStringUtils.replace(builder, "XXXIDSXXX",
892                              pojo.getXMLHostids() == null? "" :
893                                  pojo.getXMLHostids());
894     if (getMode() == RequestPacket.TRANSFERMODE.RECVMODE.ordinal()) {
895       WaarpStringUtils.replace(builder, "XXXRECVXXX", "checked");
896     } else if (getMode() == RequestPacket.TRANSFERMODE.SENDMODE.ordinal()) {
897       WaarpStringUtils.replace(builder, "XXXSENDXXX", "checked");
898     } else if (getMode() == RequestPacket.TRANSFERMODE.RECVMD5MODE.ordinal()) {
899       WaarpStringUtils.replace(builder, "XXXRECVMXXX", "checked");
900     } else if (getMode() == RequestPacket.TRANSFERMODE.SENDMD5MODE.ordinal()) {
901       WaarpStringUtils.replace(builder, "XXXSENDMXXX", "checked");
902     } else if (getMode() ==
903                RequestPacket.TRANSFERMODE.RECVTHROUGHMODE.ordinal()) {
904       WaarpStringUtils.replace(builder, "XXXRECVTXXX", "checked");
905     } else if (getMode() ==
906                RequestPacket.TRANSFERMODE.SENDTHROUGHMODE.ordinal()) {
907       WaarpStringUtils.replace(builder, "XXXSENDTXXX", "checked");
908     } else if (getMode() ==
909                RequestPacket.TRANSFERMODE.RECVMD5THROUGHMODE.ordinal()) {
910       WaarpStringUtils.replace(builder, "XXXRECVMTXXX", "checked");
911     } else if (getMode() ==
912                RequestPacket.TRANSFERMODE.SENDMD5THROUGHMODE.ordinal()) {
913       WaarpStringUtils.replace(builder, "XXXSENDMTXXX", "checked");
914     }
915     WaarpStringUtils.replace(builder, "XXXRPXXX",
916                              pojo.getRecvPath() == null? "" :
917                                  pojo.getRecvPath());
918     WaarpStringUtils.replace(builder, "XXXSPXXX",
919                              pojo.getSendPath() == null? "" :
920                                  pojo.getSendPath());
921     WaarpStringUtils.replace(builder, "XXXAPXXX",
922                              pojo.getArchivePath() == null? "" :
923                                  pojo.getArchivePath());
924     WaarpStringUtils.replace(builder, "XXXWPXXX",
925                              pojo.getWorkPath() == null? "" :
926                                  pojo.getWorkPath());
927     WaarpStringUtils.replace(builder, "XXXRPTXXX",
928                              pojo.getXMLRPreTasks() == null? "" :
929                                  pojo.getXMLRPreTasks());
930     WaarpStringUtils.replace(builder, "XXXRSTXXX",
931                              pojo.getXMLRPostTasks() == null? "" :
932                                  pojo.getXMLRPostTasks());
933     WaarpStringUtils.replace(builder, "XXXRETXXX",
934                              pojo.getXMLRErrorTasks() == null? "" :
935                                  pojo.getXMLRErrorTasks());
936     WaarpStringUtils.replace(builder, "XXXSPTXXX",
937                              pojo.getXMLSPreTasks() == null? "" :
938                                  pojo.getXMLSPreTasks());
939     WaarpStringUtils.replace(builder, "XXXSSTXXX",
940                              pojo.getXMLSPostTasks() == null? "" :
941                                  pojo.getXMLSPostTasks());
942     WaarpStringUtils.replace(builder, "XXXSETXXX",
943                              pojo.getXMLSErrorTasks() == null? "" :
944                                  pojo.getXMLSErrorTasks());
945     return builder.toString();
946   }
947 
948   /**
949    * @return the recvPath
950    */
951   public final String getRecvPath() {
952     if (ParametersChecker.isEmpty(getRuleRecvPath())) {
953       return Configuration.configuration.getInPath();
954     }
955     return getRuleRecvPath();
956   }
957 
958   /**
959    * @return the sendPath
960    */
961   public final String getSendPath() {
962     if (ParametersChecker.isEmpty(getRuleSendPath())) {
963       return Configuration.configuration.getOutPath();
964     }
965     return getRuleSendPath();
966   }
967 
968   /**
969    * @return the archivePath
970    */
971   public final String getArchivePath() {
972     if (ParametersChecker.isEmpty(getRuleArchivePath())) {
973       return Configuration.configuration.getArchivePath();
974     }
975     return getRuleArchivePath();
976   }
977 
978   /**
979    * @return the workPath
980    */
981   public final String getWorkPath() {
982     if (ParametersChecker.isEmpty(getRuleWorkPath())) {
983       return Configuration.configuration.getWorkingPath();
984     }
985     return getRuleWorkPath();
986   }
987 
988   /**
989    * @return the Rule recvPath
990    */
991   public final String getRuleRecvPath() {
992     return pojo.getRecvPath();
993   }
994 
995   /**
996    * @return the Rule sendPath
997    */
998   public final String getRuleSendPath() {
999     return pojo.getSendPath();
1000   }
1001 
1002   /**
1003    * @return the Rule archivePath
1004    */
1005   public final String getRuleArchivePath() {
1006     return pojo.getArchivePath();
1007   }
1008 
1009   /**
1010    * @return the Rule workPath
1011    */
1012   public final String getRuleWorkPath() {
1013     return pojo.getWorkPath();
1014   }
1015 
1016   /**
1017    * @return the idRule
1018    */
1019   public final String getIdRule() {
1020     return pojo.getName();
1021   }
1022 
1023   /**
1024    * @return the mode
1025    */
1026   public final int getMode() {
1027     return pojo.getMode();
1028   }
1029 
1030   /**
1031    * @return the idsArray
1032    */
1033   public final String[] getIdsArray() {
1034     return pojo.getHostids().toArray(STRING_0_LENGTH);
1035   }
1036 
1037   /**
1038    * @return the rpreTasksArray
1039    */
1040   public final String[][] getRpreTasksArray() {
1041     return toLegacyTasks(pojo.getRPreTasks());
1042   }
1043 
1044   /**
1045    * @return the rpostTasksArray
1046    */
1047   public final String[][] getRpostTasksArray() {
1048     return toLegacyTasks(pojo.getRPostTasks());
1049   }
1050 
1051   /**
1052    * @return the rerrorTasksArray
1053    */
1054   public final String[][] getRerrorTasksArray() {
1055     return toLegacyTasks(pojo.getRErrorTasks());
1056   }
1057 
1058   /**
1059    * @return the spreTasksArray
1060    */
1061   public final String[][] getSpreTasksArray() {
1062     return toLegacyTasks(pojo.getSPreTasks());
1063   }
1064 
1065   /**
1066    * @return the spostTasksArray
1067    */
1068   public final String[][] getSpostTasksArray() {
1069     return toLegacyTasks(pojo.getSPostTasks());
1070   }
1071 
1072   /**
1073    * @return the serrorTasksArray
1074    */
1075   public final String[][] getSerrorTasksArray() {
1076     return toLegacyTasks(pojo.getSErrorTasks());
1077   }
1078 
1079   private List<RuleTask> fromLegacyTasks(final String[][] tasks) {
1080     final int size = tasks.length;
1081     final List<RuleTask> res = new ArrayList<RuleTask>(size);
1082     for (final String[] task : tasks) {
1083       if (task.length >= 3) {
1084         res.add(new RuleTask(task[0], task[1], Integer.parseInt(task[2])));
1085       }
1086     }
1087     return res;
1088   }
1089 
1090   private String[][] toLegacyTasks(final List<RuleTask> tasks) {
1091     final int size = tasks.size();
1092     final String[][] res = new String[size][];
1093     int i = 0;
1094     for (final RuleTask task : tasks) {
1095       res[i] = new String[3];
1096       res[i][0] = task.getType();
1097       res[i][1] = task.getPath();
1098       res[i][2] = String.valueOf(task.getDelay());
1099       i++;
1100     }
1101     return res;
1102   }
1103 }