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.server;
21  
22  import org.waarp.common.database.exception.WaarpDatabaseException;
23  import org.waarp.common.logging.WaarpLogger;
24  import org.waarp.common.logging.WaarpLoggerFactory;
25  import org.waarp.common.logging.WaarpSlf4JLoggerFactory;
26  import org.waarp.common.utility.ParametersChecker;
27  import org.waarp.common.utility.WaarpStringUtils;
28  import org.waarp.openr66.client.AbstractTransfer;
29  import org.waarp.openr66.client.DirectTransfer;
30  import org.waarp.openr66.configuration.FileBasedConfiguration;
31  import org.waarp.openr66.context.ErrorCode;
32  import org.waarp.openr66.context.R66FiniteDualStates;
33  import org.waarp.openr66.context.R66Result;
34  import org.waarp.openr66.database.data.DbHostAuth;
35  import org.waarp.openr66.database.data.DbTaskRunner;
36  import org.waarp.openr66.protocol.configuration.Configuration;
37  import org.waarp.openr66.protocol.exception.OpenR66ProtocolBusinessException;
38  import org.waarp.openr66.protocol.exception.OpenR66ProtocolNoDataException;
39  import org.waarp.openr66.protocol.exception.OpenR66ProtocolPacketException;
40  import org.waarp.openr66.protocol.localhandler.LocalChannelReference;
41  import org.waarp.openr66.protocol.localhandler.packet.JsonCommandPacket;
42  import org.waarp.openr66.protocol.localhandler.packet.LocalPacketFactory;
43  import org.waarp.openr66.protocol.localhandler.packet.json.LogJsonPacket;
44  import org.waarp.openr66.protocol.localhandler.packet.json.LogResponseJsonPacket;
45  import org.waarp.openr66.protocol.networkhandler.NetworkTransaction;
46  import org.waarp.openr66.protocol.utils.ChannelUtils;
47  import org.waarp.openr66.protocol.utils.R66Future;
48  
49  import java.io.File;
50  import java.sql.Timestamp;
51  
52  import static org.waarp.common.database.DbConstant.*;
53  
54  /**
55   * Log Export from a client (local or allowed)
56   */
57  public class LogExtendedExport implements Runnable {
58    /**
59     * Internal Logger
60     */
61    static volatile WaarpLogger logger;
62  
63    protected static final String INFO_ARGS =
64        "Need at least the configuration file as first argument then optionally\n" +
65        "    -purge\n    -clean\n    -startid id\n    -stopid id\n    -rule rule\n    -request host\n" +
66        "    -pending\n    -transfer\n    -done\n    -error\n" +
67        "    -start timestamp in format yyyyMMddHHmmssSSS possibly truncated and where one of ':-. ' can be separators\n" +
68        "    -stop timestamp in same format than start\n" +
69        "If not start and no stop are given, stop is Today Midnight (00:00:00)\n" +
70        "If start is equals or greater than stop, stop is start+24H\n" +
71        "    -host host (optional additional options:\n" +
72        "      -ruleDownload ruleDownload if set, will try to download the exported logs\n" +
73        "      -import that will try to import exported logs using ruleDownload to download the logs)";
74  
75    protected final R66Future future;
76    protected final boolean clean;
77    protected final boolean purgeLog;
78    protected final Timestamp start;
79    protected final Timestamp stop;
80    protected final String startid;
81    protected final String stopid;
82    protected final String rule;
83    protected final String request;
84    protected final boolean statuspending;
85    protected final boolean statustransfer;
86    protected final boolean statusdone;
87    protected final boolean statuserror;
88    protected String ruleDownload;
89    protected boolean tryimport;
90    protected final NetworkTransaction networkTransaction;
91    protected DbHostAuth host;
92  
93    /**
94     * @param future
95     * @param clean
96     * @param purgeLog
97     * @param start
98     * @param stop
99     * @param startid
100    * @param stopid
101    * @param rule
102    * @param request
103    * @param statuspending
104    * @param statustransfer
105    * @param statusdone
106    * @param statuserror
107    * @param networkTransaction
108    * @param host
109    */
110   public LogExtendedExport(final R66Future future, final boolean clean,
111                            final boolean purgeLog, final Timestamp start,
112                            final Timestamp stop, final String startid,
113                            final String stopid, final String rule,
114                            final String request, final boolean statuspending,
115                            final boolean statustransfer,
116                            final boolean statusdone, final boolean statuserror,
117                            final NetworkTransaction networkTransaction,
118                            final DbHostAuth host) {
119     this.future = future;
120     this.clean = clean;
121     this.purgeLog = purgeLog;
122     this.start = start;
123     this.stop = stop;
124     this.startid = startid;
125     this.stopid = stopid;
126     this.rule = rule;
127     this.request = request;
128     this.statuspending = statuspending;
129     this.statustransfer = statustransfer;
130     this.statusdone = statusdone;
131     this.statuserror = statuserror;
132     this.networkTransaction = networkTransaction;
133     this.host = host;
134     if (logger == null) {
135       logger = WaarpLoggerFactory.getLogger(LogExtendedExport.class);
136     }
137   }
138 
139   /**
140    * Try first to download the exported logs, then to import (must be a host
141    * different than the source one)
142    *
143    * @param ruleDownload
144    * @param tryimport
145    */
146   public void setDownloadTryImport(final String ruleDownload,
147                                    final boolean tryimport) {
148     this.ruleDownload = ruleDownload;
149     this.tryimport = ruleDownload != null && tryimport && !host.getHostid()
150                                                                .equals(
151                                                                    Configuration.configuration.getHostId()) &&
152                      !host.getHostid()
153                           .equals(Configuration.configuration.getHostSslId());
154   }
155 
156   /**
157    * Prior to call this method, the pipeline and NetworkTransaction must have
158    * been initialized. It is the
159    * responsibility of the caller to finish all network resources.
160    */
161   @Override
162   public void run() {
163     if (logger == null) {
164       logger = WaarpLoggerFactory.getLogger(LogExtendedExport.class);
165     }
166     if (!(statusdone || statuserror || statuspending || statustransfer)) {
167       logger.error("No action required");
168       future.setResult(new R66Result(
169           new OpenR66ProtocolNoDataException("No action required"), null, true,
170           ErrorCode.IncorrectCommand, null));
171       future.setFailure(future.getResult().getException());
172       return;
173     }
174 
175     final byte type = purgeLog? LocalPacketFactory.LOGPURGEPACKET :
176         LocalPacketFactory.LOGPACKET;
177     final LogJsonPacket node = new LogJsonPacket();
178     node.setClean(clean);
179     node.setPurge(purgeLog);
180     node.setStart(start);
181     node.setStop(stop);
182     node.setStartid(startid);
183     node.setStopid(stopid);
184     node.setRule(rule);
185     node.setRequest(request);
186     node.setStatuspending(statuspending);
187     node.setStatustransfer(statustransfer);
188     node.setStatuserror(statuserror);
189     node.setStatusdone(statusdone);
190 
191     final JsonCommandPacket valid = new JsonCommandPacket(node, type);
192     logger.debug("ExtendedLogCommand: {}", valid.getRequest());
193     final R66Future newFuture = new R66Future(true);
194     final LocalChannelReference localChannelReference =
195         AbstractTransfer.tryConnect(host, newFuture, networkTransaction);
196     if (localChannelReference == null) {
197       future.setResult(newFuture.getResult());
198       future.setFailure(future.getCause());
199       return;
200     }
201     localChannelReference.sessionNewState(R66FiniteDualStates.VALIDOTHER);
202     try {
203       ChannelUtils.writeAbstractLocalPacket(localChannelReference, valid, true);
204     } catch (final OpenR66ProtocolPacketException e) {
205       logger.error("Bad Protocol", e);
206       localChannelReference.close();
207       host = null;
208       future.setResult(
209           new R66Result(e, null, true, ErrorCode.TransferError, null));
210       future.setFailure(e);
211       return;
212     }
213     host = null;
214     newFuture.awaitOrInterruptible();
215     logger.info("Request done with {}",
216                 newFuture.isSuccess()? "success" : "error");
217     if (newFuture.isSuccess() && ParametersChecker.isNotEmpty(ruleDownload)) {
218       try {
219         importLog(newFuture);
220       } catch (final OpenR66ProtocolBusinessException e) {
221         localChannelReference.close();
222         return;
223       }
224     }
225     future.setFilesize(newFuture.getFilesize());
226     future.setRunner(newFuture.getRunner());
227     future.setResult(newFuture.getResult());
228     if (newFuture.isSuccess()) {
229       future.setSuccess();
230     } else {
231       if (newFuture.getCause() != null) {
232         future.setFailure(newFuture.getCause());
233       }
234       future.cancel();
235     }
236     localChannelReference.close();
237   }
238 
239   public void importLog(final R66Future future)
240       throws OpenR66ProtocolBusinessException {
241     if (future.isSuccess()) {
242       final JsonCommandPacket packet =
243           (JsonCommandPacket) future.getResult().getOther();
244       if (packet != null) {
245         final LogResponseJsonPacket res =
246             (LogResponseJsonPacket) packet.getJsonRequest();
247         final String fileExported = res.getFilename();
248         // download logs
249         if (ParametersChecker.isNotEmpty(fileExported)) {
250           final String ruleToExport = ruleDownload;
251           final R66Future futuretemp = new R66Future(true);
252           final DirectTransfer transfer =
253               new DirectTransfer(futuretemp, host.getHostid(), fileExported,
254                                  ruleToExport, "Get Exported Logs from " +
255                                                Configuration.configuration.getHostId(),
256                                  false,
257                                  Configuration.configuration.getBlockSize(),
258                                  ILLEGALVALUE, networkTransaction);
259           transfer.run();
260           final File logsFile;
261           if (!futuretemp.isSuccess()) {
262             if (futuretemp.getCause() != null) {
263               throw new OpenR66ProtocolBusinessException(futuretemp.getCause());
264             }
265             throw new OpenR66ProtocolBusinessException(
266                 "Download of exported logs in error");
267           } else {
268             logsFile = futuretemp.getResult().getFile().getTrueFile();
269           }
270           if (tryimport) {
271             try {
272               DbTaskRunner.loadXml(logsFile);
273             } catch (final OpenR66ProtocolBusinessException e) {
274               logger.warn(
275                   "Cannot load the logs from " + logsFile.getAbsolutePath() +
276                   " since: " + e.getMessage());
277               throw new OpenR66ProtocolBusinessException(
278                   "Cannot load the logs from " + logsFile.getAbsolutePath(), e);
279             }
280           }
281         } else {
282           throw new OpenR66ProtocolBusinessException(
283               "Export log with no file result");
284         }
285       } else {
286         throw new OpenR66ProtocolBusinessException(
287             "Export log with no file result");
288       }
289     } else {
290       if (future.getCause() != null) {
291         throw new OpenR66ProtocolBusinessException(future.getCause());
292       }
293       throw new OpenR66ProtocolBusinessException("Export log in error");
294     }
295   }
296 
297   protected static boolean sclean;
298   protected static boolean spurgeLog;
299   protected static Timestamp sstart;
300   protected static Timestamp sstop;
301   protected static String sstartid;
302   protected static String sstopid;
303   protected static String srule;
304   protected static String srequest;
305   protected static boolean sstatuspending;
306   protected static boolean sstatustransfer;
307   protected static boolean sstatusdone = true;
308   protected static boolean sstatuserror;
309   protected static String stohost;
310   protected static String sruleDownload;
311   protected static boolean stryimport;
312 
313   protected static boolean getParams(final String[] args) {
314     if (logger == null) {
315       logger = WaarpLoggerFactory.getLogger(LogExtendedExport.class);
316     }
317     if (args.length < 1) {
318       logger.error(INFO_ARGS);
319       return false;
320     }
321     if (!FileBasedConfiguration.setClientConfigurationFromXml(
322         Configuration.configuration, args[0])) {
323       logger.error(INFO_ARGS);
324       return false;
325     }
326     String ssstart = null;
327     String ssstop = null;
328     for (int i = 1; i < args.length; i++) {
329       if ("-purge".equalsIgnoreCase(args[i])) {
330         spurgeLog = true;
331       } else if ("-clean".equalsIgnoreCase(args[i])) {
332         sclean = true;
333       } else if ("-start".equalsIgnoreCase(args[i])) {
334         i++;
335         ssstart = args[i];
336       } else if ("-stop".equalsIgnoreCase(args[i])) {
337         i++;
338         ssstop = args[i];
339       } else if ("-startid".equalsIgnoreCase(args[i])) {
340         i++;
341         sstartid = args[i];
342       } else if ("-stopid".equalsIgnoreCase(args[i])) {
343         i++;
344         sstopid = args[i];
345       } else if ("-rule".equalsIgnoreCase(args[i])) {
346         i++;
347         srule = args[i];
348       } else if ("-request".equalsIgnoreCase(args[i])) {
349         i++;
350         srequest = args[i];
351       } else if ("-pending".equalsIgnoreCase(args[i])) {
352         sstatuspending = true;
353       } else if ("-transfer".equalsIgnoreCase(args[i])) {
354         sstatustransfer = true;
355       } else if ("-done".equalsIgnoreCase(args[i])) {
356         sstatusdone = true;
357       } else if ("-error".equalsIgnoreCase(args[i])) {
358         sstatuserror = true;
359       } else if ("-import".equalsIgnoreCase(args[i])) {
360         stryimport = true;
361       } else if ("-host".equalsIgnoreCase(args[i])) {
362         i++;
363         stohost = args[i];
364       } else if ("-ruleDownload".equalsIgnoreCase(args[i])) {
365         i++;
366         sruleDownload = args[i];
367       }
368     }
369     if (ssstart != null) {
370       final Timestamp tstart = WaarpStringUtils.fixDate(ssstart);
371       if (tstart != null) {
372         sstart = tstart;
373       }
374     }
375     if (ssstop != null) {
376       final Timestamp tstop = WaarpStringUtils.fixDate(ssstop, sstart);
377       if (tstop != null) {
378         sstop = tstop;
379       }
380     }
381     if (ssstart == null && ssstop == null) {
382       sstop = WaarpStringUtils.getTodayMidnight();
383     }
384     if (stohost == null) {
385       stryimport = false;
386     }
387     return true;
388   }
389 
390   public static void main(final String[] args) {
391     WaarpLoggerFactory.setDefaultFactoryIfNotSame(
392         new WaarpSlf4JLoggerFactory(null));
393     if (logger == null) {
394       logger = WaarpLoggerFactory.getLogger(LogExtendedExport.class);
395     }
396     if (!getParams(args)) {
397       logger.error("Wrong initialization");
398       if (admin != null) {
399         admin.close();
400       }
401       System.exit(1);//NOSONAR
402     }
403     final long time1 = System.currentTimeMillis();
404     DbHostAuth dbhost = null;
405     if (stohost != null) {
406       try {
407         dbhost = new DbHostAuth(stohost);
408       } catch (final WaarpDatabaseException e) {
409         logger.error("Wrong initialization");
410         if (admin != null) {
411           admin.close();
412         }
413         System.exit(2);//NOSONAR
414       }
415     } else {
416       dbhost = Configuration.configuration.getHostSslAuth();
417       stohost = Configuration.configuration.getHostSslId();
418     }
419     final R66Future future = new R66Future(true);
420 
421     Configuration.configuration.pipelineInit();
422     final NetworkTransaction networkTransaction = new NetworkTransaction();
423     try {
424       final LogExtendedExport transaction =
425           new LogExtendedExport(future, sclean, spurgeLog, sstart, sstop,
426                                 sstartid, sstopid, srule, srequest,
427                                 sstatuspending, sstatustransfer, sstatusdone,
428                                 sstatuserror, networkTransaction, dbhost);
429       transaction.setDownloadTryImport(sruleDownload, stryimport);
430       transaction.run();
431       future.awaitOrInterruptible();
432       final long time2 = System.currentTimeMillis();
433       final long delay = time2 - time1;
434       final R66Result result = future.getResult();
435       if (future.isSuccess()) {
436         if (result.getCode() == ErrorCode.Warning) {
437           logger.warn("WARNED on file:     " + (result.getOther() != null?
438               ((JsonCommandPacket) result.getOther()).getRequest() :
439               "no file") + "     delay: " + delay);
440         } else {
441           logger.warn("SUCCESS on Final file:     " +
442                       (result.getOther() != null?
443                           ((JsonCommandPacket) result.getOther()).getRequest() :
444                           "no file") + "     delay: " + delay);
445         }
446       } else {
447         if (result.getCode() == ErrorCode.Warning) {
448           logger.warn("LogExtendedExport is     WARNED" + " : {}",
449                       future.getCause() != null?
450                           future.getCause().getMessage() : "");
451         } else {
452           logger.error("LogExtendedExport in     FAILURE" + " : {}",
453                        future.getCause() != null?
454                            future.getCause().getMessage() : "");
455         }
456         networkTransaction.closeAll();
457         System.exit(result.getCode().ordinal());//NOSONAR
458       }
459     } finally {
460       networkTransaction.closeAll();
461       System.exit(0);//NOSONAR
462     }
463   }
464 
465 }