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