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.gateway.kernel.database.data;
21  
22  import io.netty.handler.codec.http.HttpResponseStatus;
23  import org.dom4j.Document;
24  import org.waarp.common.database.DbPreparedStatement;
25  import org.waarp.common.database.DbSession;
26  import org.waarp.common.database.data.AbstractDbData;
27  import org.waarp.common.database.data.DbValue;
28  import org.waarp.common.database.exception.WaarpDatabaseException;
29  import org.waarp.common.database.exception.WaarpDatabaseNoConnectionException;
30  import org.waarp.common.database.exception.WaarpDatabaseNoDataException;
31  import org.waarp.common.database.exception.WaarpDatabaseSqlException;
32  import org.waarp.common.exception.InvalidArgumentException;
33  import org.waarp.common.json.JsonHandler;
34  import org.waarp.common.logging.WaarpLogger;
35  import org.waarp.common.logging.WaarpLoggerFactory;
36  import org.waarp.common.xml.XmlDecl;
37  import org.waarp.common.xml.XmlType;
38  import org.waarp.common.xml.XmlUtil;
39  import org.waarp.common.xml.XmlValue;
40  import org.waarp.gateway.kernel.HttpPage.PageRole;
41  import org.waarp.gateway.kernel.HttpPageHandler;
42  import org.waarp.gateway.kernel.database.DbConstantGateway;
43  
44  import java.io.IOException;
45  import java.io.InvalidObjectException;
46  import java.sql.SQLException;
47  import java.sql.Timestamp;
48  import java.sql.Types;
49  import java.util.HashMap;
50  import java.util.HashSet;
51  import java.util.Map;
52  import java.util.Set;
53  
54  /**
55   * Transfer Log for Gateway for Http
56   */
57  public class DbTransferLog extends AbstractDbData {
58    private static final String ERROR_DURING_PURGE = "Error during purge";
59  
60    private static final String NO_ROW_FOUND2 = "No row found";
61  
62    /**
63     * Internal Logger
64     */
65    private static final WaarpLogger logger =
66        WaarpLoggerFactory.getLogger(DbTransferLog.class);
67  
68    public enum Columns {
69      FILENAME, MODETRANS, STARTTRANS, STOPTRANS, TRANSINFO, INFOSTATUS,
70      UPDATEDINFO, USERID, ACCOUNTID, HOSTID, SPECIALID
71    }
72  
73    public static final int[] dbTypes = {
74        Types.VARCHAR, Types.NVARCHAR, Types.TIMESTAMP, Types.TIMESTAMP,
75        Types.VARCHAR, Types.INTEGER, Types.INTEGER, Types.NVARCHAR,
76        Types.NVARCHAR, Types.NVARCHAR, Types.BIGINT
77    };
78  
79    public static final String table = " TRANSFLOG ";
80  
81    public static final String fieldseq = "TRANSSEQ";
82  
83    public static final Columns[] indexes =
84        { Columns.STARTTRANS, Columns.UPDATEDINFO, Columns.INFOSTATUS };
85  
86    public static final String XMLRUNNERS = "transferlogs";
87    public static final String XMLRUNNER = "log";
88  
89    // Values
90    private String user;
91  
92    private String account;
93  
94    private long specialId;
95  
96    private boolean isSender;
97  
98    private String filename;
99  
100   private String mode;
101 
102   private Timestamp start;
103 
104   private Timestamp stop;
105 
106   private String infotransf;
107 
108   private String hostid;
109 
110   /**
111    * Info status error code
112    */
113   private HttpResponseStatus infostatus = HttpResponseStatus.OK;
114 
115   /**
116    * The global status for running
117    */
118   private int updatedInfo = UpdatedInfo.UNKNOWN.ordinal();
119 
120   /**
121    * Special For DbTransferLog
122    */
123   public static final int NBPRKEY = 4;
124   // ALL TABLE SHOULD IMPLEMENT THIS
125 
126   protected static final String selectAllFields =
127       Columns.FILENAME.name() + ',' + Columns.MODETRANS.name() + ',' +
128       Columns.STARTTRANS.name() + ',' + Columns.STOPTRANS.name() + ',' +
129       Columns.TRANSINFO.name() + ',' + Columns.INFOSTATUS.name() + ',' +
130       Columns.UPDATEDINFO.name() + ',' + Columns.USERID.name() + ',' +
131       Columns.ACCOUNTID.name() + ',' + Columns.HOSTID.name() + ',' +
132       Columns.SPECIALID.name();
133 
134   protected static final String updateAllFields =
135       Columns.FILENAME.name() + "=?," + Columns.MODETRANS.name() + "=?," +
136       Columns.STARTTRANS.name() + "=?," + Columns.STOPTRANS.name() + "=?," +
137       Columns.TRANSINFO.name() + "=?," + Columns.INFOSTATUS.name() + "=?," +
138       Columns.UPDATEDINFO.name() + "=?";
139 
140   protected static final String insertAllValues = " (?,?,?,?,?,?,?,?,?,?,?) ";
141 
142   private static final Set<Long> clientNoDbSpecialId = new HashSet<Long>();
143 
144   /**
145    * Insert into database
146    *
147    * @param dbSession
148    * @param user
149    * @param account
150    * @param specialId
151    * @param isSender
152    * @param filename
153    * @param mode
154    * @param infostatus
155    * @param info
156    * @param updatedInfo
157    *
158    * @throws WaarpDatabaseException
159    */
160   public DbTransferLog(final DbSession dbSession, final String user,
161                        final String account, final long specialId,
162                        final boolean isSender, final String filename,
163                        final String mode, final HttpResponseStatus infostatus,
164                        final String info, final UpdatedInfo updatedInfo)
165       throws WaarpDatabaseException {
166     super(dbSession);
167     this.user = user;
168     this.account = account;
169     this.specialId = specialId;
170     this.isSender = isSender;
171     this.filename = filename;
172     this.mode = mode;
173     start = new Timestamp(System.currentTimeMillis());
174     this.infostatus = infostatus;
175     infotransf = info;
176     this.updatedInfo = updatedInfo.ordinal();
177     hostid = HttpPageHandler.hostid;
178     setToArray();
179     isSaved = false;
180     insert();
181   }
182 
183   /**
184    * Load from database
185    *
186    * @param dbSession
187    * @param user
188    * @param account
189    * @param specialId
190    *
191    * @throws WaarpDatabaseException
192    */
193   public DbTransferLog(final DbSession dbSession, final String user,
194                        final String account, final long specialId)
195       throws WaarpDatabaseException {
196     super(dbSession);
197     this.user = user;
198     this.account = account;
199     this.specialId = specialId;
200     hostid = HttpPageHandler.hostid;
201     select();
202   }
203 
204   @Override
205   protected final void initObject() {
206     primaryKey = new DbValue[] {
207         new DbValue(user, Columns.USERID.name()),
208         new DbValue(account, Columns.ACCOUNTID.name()),
209         new DbValue(hostid, Columns.HOSTID.name()),
210         new DbValue(specialId, Columns.SPECIALID.name())
211     };
212     otherFields = new DbValue[] {
213         // FILENAME, MODETRANS,
214         // STARTTRANS, STOPTRANS, TRANSINFO
215         // INFOSTATUS, UPDATEDINFO
216         new DbValue(filename, Columns.FILENAME.name()),
217         new DbValue(mode, Columns.MODETRANS.name()),
218         new DbValue(start, Columns.STARTTRANS.name()),
219         new DbValue(stop, Columns.STOPTRANS.name()),
220         new DbValue(infotransf, Columns.TRANSINFO.name()),
221         new DbValue(HttpResponseStatus.OK.code(), Columns.INFOSTATUS.name()),
222         // infostatus.getCode()
223         new DbValue(updatedInfo, Columns.UPDATEDINFO.name())
224     };
225     allFields = new DbValue[] {
226         otherFields[0], otherFields[1], otherFields[2], otherFields[3],
227         otherFields[4], otherFields[5], otherFields[6], primaryKey[0],
228         primaryKey[1], primaryKey[2], primaryKey[3]
229     };
230   }
231 
232   @Override
233   protected final String getSelectAllFields() {
234     return selectAllFields;
235   }
236 
237   @Override
238   protected final String getTable() {
239     return table;
240   }
241 
242   @Override
243   protected final String getInsertAllValues() {
244     return insertAllValues;
245   }
246 
247   @Override
248   protected final String getUpdateAllFields() {
249     return updateAllFields;
250   }
251 
252   @Override
253   protected final void setToArray() throws WaarpDatabaseSqlException {
254     // FILENAME, MODETRANS,
255     // STARTTRANS, STOPTRANS, TRANSINFO
256     // INFOSTATUS, UPDATEDINFO
257     // USERID, ACCOUNTID, SPECIALID
258     validateLength(Types.VARCHAR, filename, infotransf);
259     validateLength(Types.NVARCHAR, mode, user, account, hostid);
260     allFields[Columns.FILENAME.ordinal()].setValue(filename);
261     allFields[Columns.MODETRANS.ordinal()].setValue(mode);
262     allFields[Columns.STARTTRANS.ordinal()].setValue(start);
263     stop = new Timestamp(System.currentTimeMillis());
264     allFields[Columns.STOPTRANS.ordinal()].setValue(stop);
265     allFields[Columns.TRANSINFO.ordinal()].setValue(infotransf);
266     allFields[Columns.INFOSTATUS.ordinal()].setValue(infostatus.code());
267     allFields[Columns.UPDATEDINFO.ordinal()].setValue(updatedInfo);
268     allFields[Columns.USERID.ordinal()].setValue(user);
269     allFields[Columns.ACCOUNTID.ordinal()].setValue(account);
270     allFields[Columns.HOSTID.ordinal()].setValue(hostid);
271     allFields[Columns.SPECIALID.ordinal()].setValue(specialId);
272   }
273 
274   @Override
275   protected final void setFromArray() {
276     filename = (String) allFields[Columns.FILENAME.ordinal()].getValue();
277     mode = (String) allFields[Columns.MODETRANS.ordinal()].getValue();
278     start = (Timestamp) allFields[Columns.STARTTRANS.ordinal()].getValue();
279     stop = (Timestamp) allFields[Columns.STOPTRANS.ordinal()].getValue();
280     infostatus = HttpResponseStatus.valueOf(
281         (Integer) allFields[Columns.INFOSTATUS.ordinal()].getValue());
282     infotransf = (String) allFields[Columns.TRANSINFO.ordinal()].getValue();
283     updatedInfo = (Integer) allFields[Columns.UPDATEDINFO.ordinal()].getValue();
284     user = (String) allFields[Columns.USERID.ordinal()].getValue();
285     account = (String) allFields[Columns.ACCOUNTID.ordinal()].getValue();
286     hostid = (String) allFields[Columns.HOSTID.ordinal()].getValue();
287     specialId = (Long) allFields[Columns.SPECIALID.ordinal()].getValue();
288   }
289 
290   /**
291    * @return The Where condition on Primary Key
292    */
293   @Override
294   protected final String getWherePrimaryKey() {
295     return primaryKey[0].getColumn() + " = ? AND " + primaryKey[1].getColumn() +
296            " = ? AND " + primaryKey[2].getColumn() + " = ? AND " +
297            primaryKey[3].getColumn() + " = ? ";
298   }
299 
300   /**
301    * Set the primary Key as current value
302    */
303   @Override
304   protected final void setPrimaryKey() {
305     primaryKey[0].setValue(user);
306     primaryKey[1].setValue(account);
307     primaryKey[2].setValue(hostid);
308     primaryKey[3].setValue(specialId);
309   }
310 
311   /**
312    * @return the condition to limit access to the row concerned by the Host
313    */
314   private static String getLimitWhereCondition() {
315     return " " + Columns.HOSTID + " = '" + HttpPageHandler.hostid + "' ";
316   }
317 
318   /**
319    * Create a Special Id for NoDb client
320    */
321   private void createNoDbSpecialId() {
322     synchronized (clientNoDbSpecialId) {
323       // New SpecialId is not possible with No Database Model
324       specialId = System.currentTimeMillis();
325       Long newOne = specialId;
326       while (clientNoDbSpecialId.contains(newOne)) {
327         newOne = specialId++;
328       }
329       clientNoDbSpecialId.add(newOne);
330     }
331   }
332 
333   /**
334    * Remove a Special Id for NoDb Client
335    */
336   private void removeNoDbSpecialId() {
337     synchronized (clientNoDbSpecialId) {
338       final Long oldOne = specialId;
339       clientNoDbSpecialId.remove(oldOne);
340     }
341   }
342 
343   @Override
344   public final void delete() throws WaarpDatabaseException {
345     if (dbSession == null) {
346       removeNoDbSpecialId();
347       return;
348     }
349     super.delete();
350   }
351 
352   @Override
353   public final void insert() throws WaarpDatabaseException {
354     if (isSaved) {
355       return;
356     }
357     if (dbSession == null) {
358       if (specialId == DbConstantGateway.ILLEGALVALUE) {
359         // New SpecialId is not possible with No Database Model
360         createNoDbSpecialId();
361       }
362       isSaved = true;
363       return;
364     }
365     // First need to find a new id if id is not ok
366     if (specialId == DbConstantGateway.ILLEGALVALUE) {
367       specialId = dbSession.getAdmin().getDbModel().nextSequence(dbSession);
368       logger.debug("Try Insert create a new Id from sequence: {}", specialId);
369       setPrimaryKey();
370     }
371     super.insert();
372   }
373 
374   /**
375    * As insert but with the ability to change the SpecialId
376    *
377    * @throws WaarpDatabaseException
378    */
379   public final void create() throws WaarpDatabaseException {
380     if (isSaved) {
381       return;
382     }
383     if (dbSession == null) {
384       if (specialId == DbConstantGateway.ILLEGALVALUE) {
385         // New SpecialId is not possible with No Database Model
386         createNoDbSpecialId();
387       }
388       isSaved = true;
389       return;
390     }
391     // First need to find a new id if id is not ok
392     if (specialId == DbConstantGateway.ILLEGALVALUE) {
393       specialId = dbSession.getAdmin().getDbModel().nextSequence(dbSession);
394       logger.debug("Try Insert create a new Id from sequence: {}", specialId);
395       setPrimaryKey();
396     }
397     setToArray();
398     final DbPreparedStatement preparedStatement =
399         new DbPreparedStatement(dbSession);
400     try {
401       preparedStatement.createPrepareStatement(
402           "INSERT INTO " + table + " (" + selectAllFields + ") VALUES " +
403           insertAllValues);
404       setValues(preparedStatement, allFields);
405       try {
406         final int count = preparedStatement.executeUpdate();
407         if (count <= 0) {
408           throw new WaarpDatabaseNoDataException(NO_ROW_FOUND2);
409         }
410       } catch (final WaarpDatabaseSqlException e) {
411         logger.error("Problem while inserting: {}", e.getMessage());
412         final DbPreparedStatement find = new DbPreparedStatement(dbSession);
413         try {
414           find.createPrepareStatement(
415               "SELECT MAX(" + primaryKey[3].getColumn() + ") FROM " + table +
416               " WHERE " + primaryKey[0].getColumn() + " = ? AND " +
417               primaryKey[1].getColumn() + " = ? AND " +
418               primaryKey[2].getColumn() + " = ? AND " +
419               primaryKey[3].getColumn() + " != ? ");
420           setPrimaryKey();
421           setValues(find, primaryKey);
422           find.executeQuery();
423           if (find.getNext()) {
424             final long result;
425             try {
426               result = find.getResultSet().getLong(1);
427             } catch (final SQLException e1) {
428               throw new WaarpDatabaseSqlException(e1);
429             }
430             specialId = result + 1;
431             dbSession.getAdmin().getDbModel()
432                      .resetSequence(dbSession, specialId + 1);
433             setToArray();
434             preparedStatement.close();
435             setValues(preparedStatement, allFields);
436             final int count = preparedStatement.executeUpdate();
437             if (count <= 0) {
438               throw new WaarpDatabaseNoDataException(NO_ROW_FOUND2);
439             }
440           } else {
441             throw new WaarpDatabaseNoDataException(NO_ROW_FOUND2);
442           }
443         } finally {
444           find.realClose();
445         }
446       }
447       isSaved = true;
448     } finally {
449       preparedStatement.realClose();
450     }
451   }
452 
453   /**
454    * Private constructor
455    *
456    * @param dBsession
457    */
458   public DbTransferLog(final DbSession dBsession) {
459     super(dBsession);
460   }
461 
462   /**
463    * For instance when getting updated information
464    *
465    * @param preparedStatement
466    *
467    * @return the next updated DbTaskRunner
468    *
469    * @throws WaarpDatabaseNoConnectionException
470    * @throws WaarpDatabaseSqlException
471    */
472   public static DbTransferLog getFromStatement(
473       final DbPreparedStatement preparedStatement)
474       throws WaarpDatabaseNoConnectionException, WaarpDatabaseSqlException {
475     final DbTransferLog dbTaskRunner =
476         new DbTransferLog(preparedStatement.getDbSession());
477     dbTaskRunner.getValues(preparedStatement, dbTaskRunner.allFields);
478     dbTaskRunner.setFromArray();
479     dbTaskRunner.isSaved = true;
480     return dbTaskRunner;
481   }
482 
483   /**
484    * @param session
485    * @param status
486    * @param limit limit the number of rows
487    *
488    * @return the DbPreparedStatement for getting TransferLog according to
489    *     status
490    *     ordered by start
491    *
492    * @throws WaarpDatabaseNoConnectionException
493    * @throws WaarpDatabaseSqlException
494    */
495   public static DbPreparedStatement getStatusPrepareStament(
496       final DbSession session, final HttpResponseStatus status, final int limit)
497       throws WaarpDatabaseNoConnectionException, WaarpDatabaseSqlException {
498     String request = "SELECT " + selectAllFields + " FROM " + table;
499     if (status != null) {
500       request += " WHERE " + Columns.INFOSTATUS.name() + " = " + status.code() +
501                  " AND " + getLimitWhereCondition();
502     } else {
503       request += " WHERE " + getLimitWhereCondition();
504     }
505     request += " ORDER BY " + Columns.STARTTRANS.name() + " DESC ";
506     if (limit > 0) {
507       request = session.getAdmin().getDbModel()
508                        .limitRequest(selectAllFields, request, limit);
509     }
510     return new DbPreparedStatement(session, request);
511   }
512 
513   public static DbPreparedStatement getFilterPrepareStament(
514       final DbSession session, final String modetrans, final String accountid,
515       final String userid, final String filename, final String status)
516       throws WaarpDatabaseNoConnectionException, WaarpDatabaseSqlException {
517     String request = "SELECT " + selectAllFields + " FROM " + table;
518     String where = null;
519     if (status != null) {
520       where = " WHERE " + Columns.INFOSTATUS.name() + " = " + status;
521     }
522     if (modetrans != null) {
523       if (where == null) {
524         where = " WHERE " + Columns.MODETRANS.name() + " = " + modetrans;
525       } else {
526         where = " AND " + Columns.MODETRANS.name() + " = " + modetrans;
527       }
528     }
529     if (accountid != null) {
530       if (where == null) {
531         where = " WHERE " + Columns.ACCOUNTID.name() + " = " + accountid;
532       } else {
533         where = " AND " + Columns.ACCOUNTID.name() + " = " + accountid;
534       }
535     }
536     if (userid != null) {
537       if (where == null) {
538         where = " WHERE " + Columns.USERID.name() + " = " + userid;
539       } else {
540         where = " AND " + Columns.USERID.name() + " = " + userid;
541       }
542     }
543     if (filename != null) {
544       if (where == null) {
545         where = " WHERE " + Columns.FILENAME.name() + " = " + filename;
546       } else {
547         where = " AND " + Columns.FILENAME.name() + " = " + filename;
548       }
549     }
550     if (where == null) {
551       request += " WHERE " + getLimitWhereCondition();
552     } else {
553       request += where + ' ' + getLimitWhereCondition();
554     }
555     request += " ORDER BY " + Columns.STARTTRANS.name() + " DESC ";
556     return new DbPreparedStatement(session, request);
557   }
558 
559   /**
560    * @param session
561    * @param start
562    * @param stop
563    *
564    * @return the DbPreparedStatement for getting Selected Object, whatever
565    *     their
566    *     status
567    *
568    * @throws WaarpDatabaseNoConnectionException
569    * @throws WaarpDatabaseSqlException
570    */
571   public static DbPreparedStatement getLogPrepareStament(
572       final DbSession session, final Timestamp start, final Timestamp stop)
573       throws WaarpDatabaseNoConnectionException, WaarpDatabaseSqlException {
574     final DbPreparedStatement preparedStatement =
575         new DbPreparedStatement(session);
576     String request = "SELECT " + selectAllFields + " FROM " + table;
577     if (start != null && stop != null) {
578       request += " WHERE " + Columns.STARTTRANS.name() + " >= ? AND " +
579                  Columns.STARTTRANS.name() + " <= ? AND " +
580                  getLimitWhereCondition() + " ORDER BY " +
581                  Columns.SPECIALID.name() + " DESC ";
582       preparedStatement.createPrepareStatement(request);
583       try {
584         preparedStatement.getPreparedStatement().setTimestamp(1, start);
585         preparedStatement.getPreparedStatement().setTimestamp(2, stop);
586       } catch (final SQLException e) {
587         preparedStatement.realClose();
588         throw new WaarpDatabaseSqlException(e);
589       }
590     } else if (start != null) {
591       request += " WHERE " + Columns.STARTTRANS.name() + " >= ? AND " +
592                  getLimitWhereCondition() + " ORDER BY " +
593                  Columns.SPECIALID.name() + " DESC ";
594       preparedStatement.createPrepareStatement(request);
595       try {
596         preparedStatement.getPreparedStatement().setTimestamp(1, start);
597       } catch (final SQLException e) {
598         preparedStatement.realClose();
599         throw new WaarpDatabaseSqlException(e);
600       }
601     } else if (stop != null) {
602       request += " WHERE " + Columns.STARTTRANS.name() + " <= ? AND " +
603                  getLimitWhereCondition() + " ORDER BY " +
604                  Columns.SPECIALID.name() + " DESC ";
605       preparedStatement.createPrepareStatement(request);
606       try {
607         preparedStatement.getPreparedStatement().setTimestamp(1, stop);
608       } catch (final SQLException e) {
609         preparedStatement.realClose();
610         throw new WaarpDatabaseSqlException(e);
611       }
612     } else {
613       request += " WHERE " + getLimitWhereCondition() + " ORDER BY " +
614                  Columns.SPECIALID.name() + " DESC ";
615       preparedStatement.createPrepareStatement(request);
616     }
617     return preparedStatement;
618   }
619 
620   /**
621    * @param session
622    *
623    * @return the DbPreparedStatement for getting Updated Object
624    *
625    * @throws WaarpDatabaseNoConnectionException
626    * @throws WaarpDatabaseSqlException
627    */
628   public static DbPreparedStatement getCountInfoPrepareStatement(
629       final DbSession session)
630       throws WaarpDatabaseNoConnectionException, WaarpDatabaseSqlException {
631     final String request =
632         "SELECT COUNT(" + Columns.SPECIALID.name() + ") FROM " + table +
633         " WHERE " + Columns.STARTTRANS.name() + " >= ? AND " +
634         getLimitWhereCondition() + " AND " + Columns.UPDATEDINFO.name() +
635         " = ? ";
636     final DbPreparedStatement pstt = new DbPreparedStatement(session, request);
637     session.addLongTermPreparedStatement(pstt);
638     return pstt;
639   }
640 
641   /**
642    * @param pstt
643    * @param info
644    * @param time
645    *
646    * @return the number of elements (COUNT) from the statement
647    */
648   public static long getResultCountPrepareStatement(
649       final DbPreparedStatement pstt, final UpdatedInfo info, final long time) {
650     long result = 0;
651     try {
652       finishSelectOrCountPrepareStatement(pstt, time);
653       pstt.getPreparedStatement().setInt(2, info.ordinal());
654       pstt.executeQuery();
655       if (pstt.getNext()) {
656         result = pstt.getResultSet().getLong(1);
657       }
658     } catch (final WaarpDatabaseNoConnectionException ignored) {
659       // nothing
660     } catch (final WaarpDatabaseSqlException ignored) {
661       // nothing
662     } catch (final SQLException ignored) {
663       // nothing
664     } finally {
665       pstt.close();
666     }
667     return result;
668   }
669 
670   /**
671    * @param session
672    *
673    * @return the DbPreparedStatement for getting Runner according to status
674    *     ordered by start
675    *
676    * @throws WaarpDatabaseNoConnectionException
677    * @throws WaarpDatabaseSqlException
678    */
679   public static DbPreparedStatement getCountStatusPrepareStatement(
680       final DbSession session)
681       throws WaarpDatabaseNoConnectionException, WaarpDatabaseSqlException {
682     String request =
683         "SELECT COUNT(" + Columns.SPECIALID.name() + ") FROM " + table;
684     request += " WHERE " + Columns.STARTTRANS.name() + " >= ? ";
685     request += " AND " + Columns.INFOSTATUS.name() + " = ? AND " +
686                getLimitWhereCondition();
687     final DbPreparedStatement prep = new DbPreparedStatement(session, request);
688     session.addLongTermPreparedStatement(prep);
689     return prep;
690   }
691 
692   /**
693    * @param session
694    *
695    * @return the DbPreparedStatement for getting All according to status
696    *     ordered
697    *     by start
698    *
699    * @throws WaarpDatabaseNoConnectionException
700    * @throws WaarpDatabaseSqlException
701    */
702   public static DbPreparedStatement getCountAllPrepareStatement(
703       final DbSession session)
704       throws WaarpDatabaseNoConnectionException, WaarpDatabaseSqlException {
705     String request =
706         "SELECT COUNT(" + Columns.SPECIALID.name() + ") FROM " + table;
707     request += " WHERE " + Columns.STARTTRANS.name() + " >= ? ";
708     request += " AND " + getLimitWhereCondition();
709     final DbPreparedStatement prep = new DbPreparedStatement(session, request);
710     session.addLongTermPreparedStatement(prep);
711     return prep;
712   }
713 
714   /**
715    * @param pstt
716    * @param error
717    * @param time
718    *
719    * @return the number of elements (COUNT) from the statement
720    */
721   public static long getResultCountPrepareStatement(
722       final DbPreparedStatement pstt, final HttpResponseStatus error,
723       final long time) {
724     long result = 0;
725     try {
726       finishSelectOrCountPrepareStatement(pstt, time);
727       pstt.getPreparedStatement().setInt(2, error.code());
728       pstt.executeQuery();
729       if (pstt.getNext()) {
730         result = pstt.getResultSet().getLong(1);
731       }
732     } catch (final WaarpDatabaseNoConnectionException ignored) {
733       // nothing
734     } catch (final WaarpDatabaseSqlException ignored) {
735       // nothing
736     } catch (final SQLException ignored) {
737       // nothing
738     } finally {
739       pstt.close();
740     }
741     return result;
742   }
743 
744   /**
745    * @param pstt
746    *
747    * @return the number of elements (COUNT) from the statement
748    */
749   public static long getResultCountPrepareStatement(
750       final DbPreparedStatement pstt) {
751     long result = 0;
752     try {
753       pstt.executeQuery();
754       if (pstt.getNext()) {
755         result = pstt.getResultSet().getLong(1);
756       }
757     } catch (final WaarpDatabaseNoConnectionException ignored) {
758       // nothing
759     } catch (final WaarpDatabaseSqlException ignored) {
760       // nothing
761     } catch (final SQLException ignored) {
762       // nothing
763     } finally {
764       pstt.close();
765     }
766     return result;
767   }
768 
769   /**
770    * Set the current time in the given updatedPreparedStatement
771    *
772    * @param pstt
773    *
774    * @throws WaarpDatabaseNoConnectionException
775    * @throws WaarpDatabaseSqlException
776    */
777   public static void finishSelectOrCountPrepareStatement(
778       final DbPreparedStatement pstt)
779       throws WaarpDatabaseNoConnectionException, WaarpDatabaseSqlException {
780     finishSelectOrCountPrepareStatement(pstt, System.currentTimeMillis());
781   }
782 
783   /**
784    * Set the current time in the given updatedPreparedStatement
785    *
786    * @param pstt
787    *
788    * @throws WaarpDatabaseNoConnectionException
789    * @throws WaarpDatabaseSqlException
790    */
791   public static void finishSelectOrCountPrepareStatement(
792       final DbPreparedStatement pstt, final long time)
793       throws WaarpDatabaseNoConnectionException, WaarpDatabaseSqlException {
794     final Timestamp startlimit = new Timestamp(time);
795     try {
796       pstt.getPreparedStatement().setTimestamp(1, startlimit);
797     } catch (final SQLException e) {
798       logger.error("Database SQL Error: Cannot set timestamp: {}",
799                    e.getMessage());
800       throw new WaarpDatabaseSqlException("Cannot set timestamp", e);
801     }
802   }
803 
804   /**
805    * Running or not transfers are concerned
806    *
807    * @param session
808    * @param in True for Incoming, False for Outgoing
809    *
810    * @return the DbPreparedStatement for getting Runner according to in or out
811    *     going way and Error
812    *
813    * @throws WaarpDatabaseNoConnectionException
814    * @throws WaarpDatabaseSqlException
815    */
816   public static DbPreparedStatement getCountInOutErrorPrepareStatement(
817       final DbSession session, final boolean in)
818       throws WaarpDatabaseNoConnectionException, WaarpDatabaseSqlException {
819     String request =
820         "SELECT COUNT(" + Columns.SPECIALID.name() + ") FROM " + table;
821     final String inCond;
822     if (in) {
823       inCond =
824           " (" + Columns.MODETRANS.name() + " = '" + PageRole.DELETE.name() +
825           "' OR " + Columns.MODETRANS.name() + " = '" + PageRole.PUT.name() +
826           "' OR " + Columns.MODETRANS.name() + " = '" + PageRole.POST.name() +
827           "' OR " + Columns.MODETRANS.name() + " = '" +
828           PageRole.POSTUPLOAD.name() + "') ";
829     } else {
830       inCond = " (" + Columns.MODETRANS.name() + " = '" +
831                PageRole.GETDOWNLOAD.name() + "') ";
832     }
833     request += " WHERE " + inCond;
834     request += " AND " + getLimitWhereCondition() + ' ';
835     request += " AND " + Columns.STARTTRANS.name() + " >= ? ";
836     request += " AND " + Columns.UPDATEDINFO.name() + " = " +
837                UpdatedInfo.INERROR.ordinal();
838     final DbPreparedStatement prep = new DbPreparedStatement(session, request);
839     session.addLongTermPreparedStatement(prep);
840     return prep;
841   }
842 
843   /**
844    * Running or not transfers are concerned
845    *
846    * @param session
847    * @param in True for Incoming, False for Outgoing
848    * @param running True for Running only, False for all
849    *
850    * @return the DbPreparedStatement for getting Runner according to in or out
851    *     going way
852    *
853    * @throws WaarpDatabaseNoConnectionException
854    * @throws WaarpDatabaseSqlException
855    */
856   public static DbPreparedStatement getCountInOutRunningPrepareStatement(
857       final DbSession session, final boolean in, final boolean running)
858       throws WaarpDatabaseNoConnectionException, WaarpDatabaseSqlException {
859     String request =
860         "SELECT COUNT(" + Columns.SPECIALID.name() + ") FROM " + table;
861     final String inCond;
862     if (in) {
863       inCond =
864           " (" + Columns.MODETRANS.name() + " = '" + PageRole.DELETE.name() +
865           "' OR " + Columns.MODETRANS.name() + " = '" + PageRole.PUT.name() +
866           "' OR " + Columns.MODETRANS.name() + " = '" + PageRole.POST.name() +
867           "' OR " + Columns.MODETRANS.name() + " = '" +
868           PageRole.POSTUPLOAD.name() + "') ";
869     } else {
870       inCond = " (" + Columns.MODETRANS.name() + " = '" +
871                PageRole.GETDOWNLOAD.name() + "') ";
872     }
873     request += " WHERE " + inCond;
874     request += " AND " + getLimitWhereCondition() + ' ';
875     request += " AND " + Columns.STARTTRANS.name() + " >= ? ";
876     if (running) {
877       request += " AND " + Columns.UPDATEDINFO.name() + " = " +
878                  UpdatedInfo.RUNNING.ordinal();
879     }
880     final DbPreparedStatement prep = new DbPreparedStatement(session, request);
881     session.addLongTermPreparedStatement(prep);
882     return prep;
883   }
884 
885   @Override
886   public final void changeUpdatedInfo(final UpdatedInfo info) {
887     updatedInfo = info.ordinal();
888     allFields[Columns.UPDATEDINFO.ordinal()].setValue(updatedInfo);
889     isSaved = false;
890   }
891 
892   /**
893    * Set the HttpResponseStatus for the UpdatedInfo
894    *
895    * @param code
896    */
897   public final void setReplyCodeExecutionStatus(final HttpResponseStatus code) {
898     if (infostatus != code) {
899       infostatus = code;
900       allFields[Columns.INFOSTATUS.ordinal()].setValue(infostatus.code());
901       isSaved = false;
902     }
903   }
904 
905   /**
906    * @return The current UpdatedInfo value
907    */
908   public final UpdatedInfo getUpdatedInfo() {
909     return UpdatedInfo.values()[updatedInfo];
910   }
911 
912   /**
913    * @return the HttpResponseStatus code associated with the Updated Info
914    */
915   public final HttpResponseStatus getErrorInfo() {
916     return infostatus;
917   }
918 
919   /**
920    * @param filename the filename to set
921    */
922   public final void setFilename(final String filename) {
923     if (this.filename == null || !this.filename.equals(filename)) {
924       this.filename = filename;
925       allFields[Columns.FILENAME.ordinal()].setValue(this.filename);
926       isSaved = false;
927     }
928   }
929 
930   /**
931    * @return the isSender
932    */
933   public final boolean isSender() {
934     return isSender;
935   }
936 
937   /**
938    * @return the filename
939    */
940   public final String getFilename() {
941     return filename;
942   }
943 
944   /**
945    * @return the specialId
946    */
947   public final long getSpecialId() {
948     return specialId;
949   }
950 
951   /**
952    * @return the infotransf
953    */
954   public final String getInfotransf() {
955     return infotransf;
956   }
957 
958   /**
959    * @param infotransf the infotransf to set
960    */
961   public final void setInfotransf(final String infotransf) {
962     this.infotransf = infotransf;
963   }
964 
965   /**
966    * @return the user
967    */
968   public final String getUser() {
969     return user;
970   }
971 
972   /**
973    * @return the account
974    */
975   public final String getAccount() {
976     return account;
977   }
978 
979   /**
980    * @param stop the stop to set
981    */
982   public final void setStop(final Timestamp stop) {
983     this.stop = stop;
984   }
985 
986   /**
987    * @return the mode
988    */
989   public final String getMode() {
990     return mode;
991   }
992 
993   /**
994    * This method is to be called each time an operation is happening on Runner
995    *
996    * @throws WaarpDatabaseException
997    */
998   public final void saveStatus() throws WaarpDatabaseException {
999     update();
1000   }
1001 
1002   /**
1003    * Clear the runner
1004    */
1005   public final void clear() {
1006     // nothing
1007   }
1008 
1009   @Override
1010   public String toString() {
1011     final Map<String, Object> map = new HashMap<String, Object>();
1012     for (final Columns col : Columns.values()) {
1013       map.put(col.name(), allFields[col.ordinal()].getValue());
1014     }
1015     return JsonHandler.writeAsString(map);
1016   }
1017 
1018   /**
1019    * @return the start
1020    */
1021   public final Timestamp getStart() {
1022     return start;
1023   }
1024 
1025   /**
1026    * @return the stop
1027    */
1028   public final Timestamp getStop() {
1029     return stop;
1030   }
1031 
1032   /*
1033    * XXXIDXXX XXXUSERXXX XXXACCTXXX XXXFILEXXX XXXMODEXXX XXXSTATUSXXX XXXINFOXXX XXXUPINFXXX XXXSTARTXXX
1034    * XXXSTOPXXX
1035    */
1036   private static final String XML_IDX = "IDX";
1037   private static final String XML_USER = "USER";
1038   private static final String XML_ACCT = "ACCT";
1039   private static final String XML_FILE = "FILE";
1040   private static final String XML_MODE = "MODE";
1041   private static final String XML_STATUS = "STATUS";
1042   private static final String XML_INFO = "INFO";
1043   private static final String XML_UPDINFO = "UPDINFO";
1044   private static final String XML_START = "START";
1045   private static final String XML_STOP = "STOP";
1046   private static final String XML_ROOT = "LOGS";
1047   private static final String XML_ENTRY = "LOG";
1048   /**
1049    * Structure of the Configuration file
1050    */
1051   private static final XmlDecl[] logDecls = {
1052       // identity
1053       new XmlDecl(XmlType.STRING, XML_IDX),
1054       new XmlDecl(XmlType.STRING, XML_USER),
1055       new XmlDecl(XmlType.STRING, XML_ACCT),
1056       new XmlDecl(XmlType.STRING, XML_FILE),
1057       new XmlDecl(XmlType.STRING, XML_MODE),
1058       new XmlDecl(XmlType.STRING, XML_STATUS),
1059       new XmlDecl(XmlType.STRING, XML_INFO),
1060       new XmlDecl(XmlType.STRING, XML_UPDINFO),
1061       new XmlDecl(XmlType.STRING, XML_START),
1062       new XmlDecl(XmlType.STRING, XML_STOP),
1063   };
1064   /**
1065    * Global Structure for Server Configuration
1066    */
1067   private static final XmlDecl[] logsElements = {
1068       new XmlDecl(XML_ENTRY, XmlType.XVAL, XML_ROOT + '/' + XML_ENTRY, logDecls,
1069                   true)
1070   };
1071 
1072   /**
1073    * @return the associated XmlValue
1074    */
1075   private XmlValue[] saveIntoXmlValue() {
1076     final XmlValue[] values = new XmlValue[logDecls.length];
1077     for (int i = 0; i < logDecls.length; i++) {
1078       values[i] = new XmlValue(logDecls[i]);
1079     }
1080     try {
1081       values[0].setFromString(Long.toString(specialId));
1082       values[1].setFromString(user);
1083       values[2].setFromString(account);
1084       values[3].setFromString(filename);
1085       values[4].setFromString(mode);
1086       values[5].setFromString(getErrorInfo().reasonPhrase());
1087       values[6].setFromString(infotransf);
1088       values[7].setFromString(getUpdatedInfo().name());
1089       values[8].setFromString(start.toString());
1090       values[9].setFromString(stop.toString());
1091     } catch (final InvalidArgumentException e) {
1092       return null;
1093     }
1094     return values;
1095   }
1096 
1097   /**
1098    * Save the current DbTransferLog to a file
1099    *
1100    * @param filename
1101    *
1102    * @return The message for the HTTPS interface
1103    */
1104   public final String saveDbTransferLog(final String filename) {
1105     final Document document = XmlUtil.createEmptyDocument();
1106     final XmlValue[] roots = new XmlValue[1];
1107     final XmlValue root = new XmlValue(logsElements[0]);
1108     roots[0] = root;
1109     String message;
1110     final XmlValue[] values = saveIntoXmlValue();
1111     if (values == null) {
1112       return "Error during export";
1113     }
1114     try {
1115       root.addValue(values);
1116     } catch (final InvalidObjectException e) {
1117       logger.error("Error during Write DbTransferLog file: {}", e.getMessage());
1118       return ERROR_DURING_PURGE;
1119     }
1120     try {
1121       delete();
1122       message = "Purge Correct Logs successful";
1123     } catch (final WaarpDatabaseException e) {
1124       message = ERROR_DURING_PURGE;
1125     }
1126     XmlUtil.write(document, roots);
1127     try {
1128       XmlUtil.saveDocument(filename, document);
1129     } catch (final IOException e1) {
1130       logger.error("Cannot write to file: " + filename + " since {}",
1131                    e1.getMessage());
1132       return message + " but cannot save file as export";
1133     }
1134     return message;
1135   }
1136 
1137   /**
1138    * Export DbTransferLogs to a file and purge the corresponding
1139    * DbTransferLogs
1140    *
1141    * @param preparedStatement the DbTransferLog as SELECT command to
1142    *     export
1143    *     (and purge)
1144    * @param filename the filename where the DbLogs will be exported
1145    *
1146    * @return The message for the HTTPS interface
1147    */
1148   public static String saveDbTransferLogFile(
1149       final DbPreparedStatement preparedStatement, final String filename) {
1150     final Document document = XmlUtil.createEmptyDocument();
1151     final XmlValue[] roots = new XmlValue[1];
1152     final XmlValue root = new XmlValue(logsElements[0]);
1153     roots[0] = root;
1154     String message;
1155     try {
1156       try {
1157         preparedStatement.executeQuery();
1158         while (preparedStatement.getNext()) {
1159           final DbTransferLog log = getFromStatement(preparedStatement);
1160           final XmlValue[] values = log.saveIntoXmlValue();
1161           if (values == null) {
1162             return "Error during export";
1163           }
1164           try {
1165             root.addValue(values);
1166           } catch (final InvalidObjectException e) {
1167             logger.error("Error during Write DbTransferLog file: {}",
1168                          e.getMessage());
1169             return ERROR_DURING_PURGE;
1170           }
1171           log.delete();
1172         }
1173         message = "Purge Correct Logs successful";
1174       } catch (final WaarpDatabaseNoConnectionException e) {
1175         message = ERROR_DURING_PURGE;
1176       } catch (final WaarpDatabaseSqlException e) {
1177         message = ERROR_DURING_PURGE;
1178       } catch (final WaarpDatabaseException e) {
1179         message = ERROR_DURING_PURGE;
1180       }
1181     } finally {
1182       preparedStatement.realClose();
1183     }
1184     XmlUtil.write(document, roots);
1185     try {
1186       XmlUtil.saveDocument(filename, document);
1187     } catch (final IOException e1) {
1188       logger.error("Cannot write to file: " + filename + " since {}",
1189                    e1.getMessage());
1190       return message + " but cannot save file as export";
1191     }
1192     return message;
1193   }
1194 }