1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.waarp.openr66.context.task;
21
22 import com.fasterxml.jackson.core.JsonParseException;
23 import com.fasterxml.jackson.databind.JsonMappingException;
24 import com.fasterxml.jackson.databind.node.ArrayNode;
25 import com.fasterxml.jackson.databind.node.ObjectNode;
26 import org.waarp.common.digest.FilesystemBasedDigest;
27 import org.waarp.common.filemonitor.FileMonitor.FileItem;
28 import org.waarp.common.filemonitor.FileMonitor.FileMonitorInformation;
29 import org.waarp.common.json.JsonHandler;
30 import org.waarp.common.logging.WaarpLogger;
31 import org.waarp.common.logging.WaarpLoggerFactory;
32 import org.waarp.common.utility.ParametersChecker;
33 import org.waarp.common.utility.WaarpStringUtils;
34 import org.waarp.openr66.client.SpooledDirectoryTransfer;
35 import org.waarp.openr66.protocol.configuration.Configuration;
36 import org.waarp.openr66.protocol.configuration.Messages;
37 import org.waarp.openr66.protocol.exception.OpenR66ProtocolPacketException;
38 import org.waarp.openr66.protocol.localhandler.packet.BusinessRequestPacket;
39 import org.waarp.openr66.protocol.utils.ChannelUtils;
40
41 import java.io.File;
42 import java.io.IOException;
43 import java.text.DateFormat;
44 import java.util.Date;
45 import java.util.Set;
46 import java.util.TreeMap;
47
48 import static org.waarp.common.database.DbConstant.*;
49
50
51
52
53 public class SpooledInformTask extends AbstractExecJavaTask {
54
55 private static final String TD_TD = "</TD><TD>";
56
57 private static final String TH_TH = "</TH><TH>";
58
59
60
61
62 private static final WaarpLogger logger =
63 WaarpLoggerFactory.getLogger(SpooledInformTask.class);
64
65 static final TreeMap<String, SpooledInformation> spooledInformationMap =
66 new TreeMap<String, SpooledInformation>();
67
68 public static class SpooledInformation {
69 public final String host;
70 public FileMonitorInformation fileMonitorInformation;
71 public Date lastUpdate = new Date();
72
73
74
75
76
77 private SpooledInformation(final String host,
78 final FileMonitorInformation fileMonitorInformation) {
79 this.host = host;
80 this.fileMonitorInformation = fileMonitorInformation;
81 }
82 }
83
84 @Override
85 public final void run() {
86 if (callFromBusiness) {
87
88 String validated = SpooledDirectoryTransfer.PARTIALOK;
89 if (isToValidate) {
90 try {
91 final FileMonitorInformation fileMonitorInformation =
92 JsonHandler.mapper.readValue(fullarg,
93 FileMonitorInformation.class);
94 logger.info(
95 "Receive SpooledInform of size: " + fullarg.length() + " (" +
96 fileMonitorInformation.fileItems.size() + ", " +
97 (fileMonitorInformation.removedFileItems != null?
98 fileMonitorInformation.removedFileItems.size() : -1) + ')');
99 final String host = session.getAuth().getUser();
100 synchronized (spooledInformationMap) {
101 if (fileMonitorInformation.removedFileItems == null ||
102 fileMonitorInformation.removedFileItems.isEmpty()) {
103 final SpooledInformation old =
104 spooledInformationMap.put(fileMonitorInformation.name,
105 new SpooledInformation(host,
106 fileMonitorInformation));
107 if (old != null && old.fileMonitorInformation != null) {
108 if (old.fileMonitorInformation.directories != null) {
109 old.fileMonitorInformation.directories.clear();
110 }
111 if (old.fileMonitorInformation.fileItems != null) {
112 old.fileMonitorInformation.fileItems.clear();
113 }
114 old.fileMonitorInformation = null;
115 }
116 } else {
117
118 final SpooledInformation update =
119 spooledInformationMap.get(fileMonitorInformation.name);
120 if (update == null) {
121
122 spooledInformationMap.put(fileMonitorInformation.name,
123 new SpooledInformation(host,
124 fileMonitorInformation));
125 validated = SpooledDirectoryTransfer.NEEDFULL;
126 } else {
127 for (final String item : fileMonitorInformation.removedFileItems) {
128 update.fileMonitorInformation.fileItems.remove(item);
129 }
130 update.fileMonitorInformation.fileItems.putAll(
131 fileMonitorInformation.fileItems);
132 update.lastUpdate = new Date();
133 }
134 }
135 }
136 } catch (final JsonParseException e1) {
137 logger.warn("Cannot parse SpooledInformation: " + fullarg + ' ' +
138 e1.getMessage());
139 } catch (final JsonMappingException e1) {
140 logger.warn("Cannot parse SpooledInformation: " + fullarg + ' ' +
141 e1.getMessage());
142 } catch (final IOException e1) {
143 logger.warn("Cannot parse SpooledInformation: " + e1.getMessage());
144 }
145 final BusinessRequestPacket packet =
146 new BusinessRequestPacket(getClass().getName() + " informed", 0);
147 if (!validate(packet)) {
148
149 try {
150 ChannelUtils.writeAbstractLocalPacket(
151 session.getLocalChannelReference(), packet, true);
152 } catch (final OpenR66ProtocolPacketException ignored) {
153
154 }
155 }
156 status = 0;
157 }
158 finalValidate(validated);
159 } else {
160
161 logger.warn("SpooledInformTask not allowed as Java Task: " + fullarg);
162 invalid();
163 }
164 }
165
166
167
168
169
170
171
172
173
174 public static StringBuilder buildSpooledTable(final boolean detailed,
175 final int status,
176 final String uri) {
177 final StringBuilder builder = beginSpooledTable(detailed, uri);
178
179 synchronized (spooledInformationMap) {
180 final Set<String> names = spooledInformationMap.keySet();
181 for (final String name : names) {
182
183 buildSpooledTableElement(detailed, status, builder, name);
184 }
185 }
186 endSpooledTable(builder);
187 return builder;
188 }
189
190
191
192
193
194
195
196
197 public static StringBuilder buildSpooledUniqueTable(final String uri,
198 final String name) {
199 final StringBuilder builder = beginSpooledTable(false, uri);
200
201 synchronized (spooledInformationMap) {
202
203 final SpooledInformation inform =
204 buildSpooledTableElement(false, 0, builder, name);
205 endSpooledTable(builder);
206 builder.append("<BR>");
207 if (inform != null) {
208 buildSpooledTableFiles(builder, inform);
209 }
210 }
211 return builder;
212 }
213
214
215
216
217 private static void endSpooledTable(final StringBuilder builder) {
218 builder.append("</TBODY></TABLE></small>");
219 }
220
221
222
223
224
225
226
227 private static StringBuilder beginSpooledTable(final boolean detailed,
228 final String uri) {
229 final StringBuilder builder = new StringBuilder();
230 builder.append(
231 "<small><TABLE class='table table-condensed table-bordered' BORDER=1><CAPTION><A HREF=");
232 builder.append(uri);
233 if (detailed) {
234 builder.append(
235 Messages.getString("SpooledInformTask.TitleDetailed"));
236 } else {
237 builder.append(
238 Messages.getString("SpooledInformTask.TitleNormal"));
239 }
240
241 builder.append("<THEAD><TR><TH>")
242 .append(Messages.getString("SpooledInformTask.0"))
243 .append(TH_TH)
244 .append(Messages.getString("SpooledInformTask.1"))
245 .append(TH_TH)
246 .append(Messages.getString("SpooledInformTask.2"))
247 .append(TH_TH)
248 .append(Messages.getString("SpooledInformTask.3"))
249 .append(TH_TH)
250 .append(Messages.getString("SpooledInformTask.4"))
251 .append(TH_TH)
252 .append(Messages.getString("SpooledInformTask.5"))
253 .append(TH_TH)
254 .append(Messages.getString("SpooledInformTask.6"))
255 .append(TH_TH)
256 .append(Messages.getString("SpooledInformTask.7"))
257 .append(TH_TH)
258 .append(Messages.getString("SpooledInformTask.8"))
259 .append(TH_TH)
260 .append(Messages.getString("SpooledInformTask.9"))
261 .append("</TH></TR></THEAD><TBODY>");
262 return builder;
263 }
264
265
266
267
268
269
270
271 private static SpooledInformation buildSpooledTableElement(
272 final boolean detailed, final int status, final StringBuilder builder,
273 final String name) {
274 final SpooledInformation inform = spooledInformationMap.get(name);
275 if (inform == null) {
276 return null;
277 }
278 final long time = inform.lastUpdate.getTime() +
279 Configuration.configuration.getTimeoutCon();
280 final long curtime = System.currentTimeMillis();
281 if (time + Configuration.configuration.getTimeoutCon() < curtime) {
282 if (status > 0) {
283 return inform;
284 }
285 } else {
286 if (status < 0) {
287 return inform;
288 }
289 }
290 builder.append("<TR><TH>").append(name.replace(',', ' '))
291 .append("</TH><TD>").append(inform.host).append("</TD>");
292 if (time + Configuration.configuration.getTimeoutCon() < curtime) {
293 builder.append("<TD bgcolor=Red>");
294 } else if (time < curtime) {
295 builder.append("<TD bgcolor=Orange>");
296 } else {
297 builder.append("<TD bgcolor=LightGreen>");
298 }
299 final DateFormat dateFormat =
300 DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.LONG);
301 builder.append(dateFormat.format(inform.lastUpdate)).append("</TD>");
302 if (inform.fileMonitorInformation != null) {
303 builder.append(
304 Messages.getString("SpooledInformTask.AllOk"))
305 .append(inform.fileMonitorInformation.globalok).append(
306 Messages.getString("SpooledInformTask.AllError"))
307 .append(inform.fileMonitorInformation.globalerror).append(
308 Messages.getString("SpooledInformTask.TodayOk"))
309 .append(inform.fileMonitorInformation.todayok).append(
310 Messages.getString("SpooledInformTask.TodayError"))
311 .append(inform.fileMonitorInformation.todayerror).append(TD_TD)
312 .append(inform.fileMonitorInformation.elapseTime).append(TD_TD)
313 .append(inform.fileMonitorInformation.stopFile).append(TD_TD)
314 .append(inform.fileMonitorInformation.statusFile).append(TD_TD)
315 .append(inform.fileMonitorInformation.scanSubDir).append("</TD>");
316 final StringBuilder dirs =
317 new StringBuilder("<ul class='list-unstyled'>");
318 for (final File dir : inform.fileMonitorInformation.directories) {
319 dirs.append("<li>").append(dir).append("</li>");
320 }
321 dirs.append("</ul>");
322 builder.append("<TD>").append(dirs).append(TD_TD);
323 if (detailed && inform.fileMonitorInformation.fileItems != null) {
324 buildSpooledTableFiles(builder, inform);
325 } else {
326
327 if (inform.fileMonitorInformation.fileItems != null) {
328 builder.append(inform.fileMonitorInformation.fileItems.size());
329 } else {
330 builder.append(0);
331 }
332
333 builder.append(
334 "<FORM class='form-inline' name='DETAIL' method='GET' action='/SpooledDetailed.html'><input type=hidden name='name' value='")
335 .append(name).append(
336 "'/><INPUT type='submit' class='btn btn-info btn-sm' value='DETAIL'/></FORM>");
337 }
338 }
339 builder.append("</TD></TR>");
340 return inform;
341 }
342
343
344
345
346
347 private static void buildSpooledTableFiles(final StringBuilder builder,
348 final SpooledInformation inform) {
349 builder.append(
350 "<small><TABLE class='table table-condensed table-bordered' BORDER=1><THEAD><TR><TH>")
351 .append(Messages.getString("SpooledInformTask.10")).append(TH_TH)
352 .append(Messages.getString("SpooledInformTask.11"))
353 .append(TH_TH)
354 .append(Messages.getString("SpooledInformTask.12"))
355 .append(TH_TH)
356 .append(Messages.getString("SpooledInformTask.13"))
357 .append(TH_TH)
358 .append(Messages.getString("SpooledInformTask.14"))
359 .append(TH_TH)
360 .append(Messages.getString("SpooledInformTask.15"))
361 .append("</TH></TR></THEAD><TBODY>");
362 final DateFormat dateFormat =
363 DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.LONG);
364 for (final FileItem fileItem : inform.fileMonitorInformation.fileItems.values()) {
365 builder.append("<TR><TD>").append(fileItem.file).append(TD_TD);
366 if (fileItem.hash != null) {
367 builder.append(FilesystemBasedDigest.getHex(fileItem.hash));
368 }
369 builder.append(TD_TD);
370 if (fileItem.lastTime > 0) {
371 builder.append(dateFormat.format(new Date(fileItem.lastTime)));
372 }
373 builder.append(TD_TD);
374 if (fileItem.timeUsed > 0) {
375 builder.append(dateFormat.format(new Date(fileItem.timeUsed)));
376 }
377 builder.append(TD_TD).append(fileItem.used).append(TD_TD)
378 .append(fileItem.specialId).append("</TD></TR>");
379 }
380 builder.append("</TBODY></TABLE></small>");
381 }
382
383
384
385
386
387
388
389
390
391 public static String buildSpooledJson(final boolean detailed,
392 final int status, final String uri) {
393 final ArrayNode array = JsonHandler.createArrayNode();
394
395 synchronized (spooledInformationMap) {
396 final Set<String> names = spooledInformationMap.keySet();
397 for (final String name : names) {
398
399 buildSpooledJsonElement(detailed, status, array, name, false);
400 }
401 }
402 return WaarpStringUtils.cleanJsonForHtml(JsonHandler.writeAsString(array));
403 }
404
405
406
407
408
409
410
411
412 public static String buildSpooledUniqueJson(final String uri,
413 final String name) {
414 final ArrayNode array = JsonHandler.createArrayNode();
415
416 synchronized (spooledInformationMap) {
417
418 buildSpooledJsonElement(true, 0, array, name, false);
419 }
420 return WaarpStringUtils.cleanJsonForHtml(JsonHandler.writeAsString(array));
421 }
422
423
424
425
426
427
428
429
430
431
432 public static int getSpooledJsonEntriesNumber(final int status,
433 final String name) {
434 int nb = 0;
435 if (ParametersChecker.isEmpty(name)) {
436 synchronized (spooledInformationMap) {
437 final Set<String> names = spooledInformationMap.keySet();
438 for (final String nameInternal : names) {
439
440 if (checkValidEntrySpooled(status, nameInternal) != null) {
441 nb++;
442 }
443 }
444 }
445 } else {
446 synchronized (spooledInformationMap) {
447
448 nb = checkValidEntrySpooled(status, name) != null? 1 : 0;
449 }
450 }
451 return nb;
452 }
453
454
455
456
457
458
459
460
461
462
463
464 public static int buildSpooledJson(final ArrayNode array, final int status,
465 final String name) {
466 int nb = 0;
467 if (ParametersChecker.isEmpty(name)) {
468 synchronized (spooledInformationMap) {
469 final Set<String> names = spooledInformationMap.keySet();
470 for (final String nameInternal : names) {
471
472 nb +=
473 buildSpooledJsonElement(true, status, array, nameInternal, true);
474 }
475 }
476 } else {
477 synchronized (spooledInformationMap) {
478
479 nb += buildSpooledJsonElement(true, status, array, name, true);
480 }
481 }
482 return nb;
483 }
484
485
486
487
488
489
490
491
492
493 private static SpooledInformation checkValidEntrySpooled(final int status,
494 final String name) {
495 final SpooledInformation inform = spooledInformationMap.get(name);
496 if (inform == null) {
497 return null;
498 }
499 final long time = inform.lastUpdate.getTime() +
500 Configuration.configuration.getTimeoutCon();
501 final long curtime = System.currentTimeMillis();
502 if (status != 0) {
503 if (time + Configuration.configuration.getTimeoutCon() < curtime) {
504 if (status < 0) {
505 return null;
506 }
507 } else if (status > 0) {
508 return null;
509 }
510 }
511 return inform;
512 }
513
514
515
516
517
518
519
520
521
522
523 private static int buildSpooledJsonElement(final boolean detailed,
524 final int status,
525 final ArrayNode array,
526 final String name,
527 final boolean strict) {
528 final SpooledInformation inform = checkValidEntrySpooled(status, name);
529 if (inform == null) {
530 return 0;
531 }
532 final long time = inform.lastUpdate.getTime() +
533 Configuration.configuration.getTimeoutCon();
534 final long curtime = System.currentTimeMillis();
535 int nb = 0;
536 if (array == null) {
537 if (inform.fileMonitorInformation != null &&
538 inform.fileMonitorInformation.fileItems != null) {
539 nb = inform.fileMonitorInformation.fileItems.size();
540 }
541 } else {
542 final ObjectNode elt = JsonHandler.createObjectNode();
543 elt.put("NAME", name.replace(',', ' '));
544 elt.put("HOST", inform.host);
545 if (strict) {
546 elt.put("LAST_UPDATE", inform.lastUpdate.getTime());
547 } else {
548 final String val;
549 if (time + Configuration.configuration.getTimeoutCon() < curtime) {
550 val = "bg-danger";
551 } else if (time < curtime) {
552 val = "bg-warning";
553 } else {
554 val = "bg-success";
555 }
556 elt.put("LAST_UPDATE", val + ' ' + inform.lastUpdate.getTime());
557 }
558 if (inform.fileMonitorInformation != null) {
559 elt.put("GLOBALOK", inform.fileMonitorInformation.globalok.get());
560 elt.put("GLOBALERROR", inform.fileMonitorInformation.globalerror.get());
561 elt.put("TODAYOK", inform.fileMonitorInformation.todayok.get());
562 elt.put("TODAYERROR", inform.fileMonitorInformation.todayerror.get());
563 elt.put("INTERVAL", inform.fileMonitorInformation.elapseTime);
564 elt.put("STOPFILE", inform.fileMonitorInformation.stopFile.getPath());
565 elt.put("STATUSFILE",
566 inform.fileMonitorInformation.statusFile.getPath());
567 elt.put("SUBDIRS", inform.fileMonitorInformation.scanSubDir);
568 final StringBuilder dirs = new StringBuilder();
569 final StringBuilder dirs2 = new StringBuilder();
570 int i = 0;
571 for (final File dir : inform.fileMonitorInformation.directories) {
572 i++;
573 dirs.append(dir).append('(').append(i).append(") ");
574 dirs2.append(dir).append(' ');
575 }
576 elt.put("DIRECTORIES", dirs.toString());
577 if (detailed && inform.fileMonitorInformation.fileItems != null) {
578 buildSpooledJsonFiles(elt, inform, dirs2.toString().split(" "),
579 strict);
580 } else {
581
582 if (inform.fileMonitorInformation.fileItems != null) {
583 elt.putArray("FILES")
584 .add(inform.fileMonitorInformation.fileItems.size());
585 } else {
586 elt.putArray("FILES").add(0);
587 }
588 }
589 nb = inform.fileMonitorInformation.fileItems.size();
590 }
591 array.add(elt);
592 }
593 return nb;
594 }
595
596
597
598
599
600
601 private static void buildSpooledJsonFiles(final ObjectNode node,
602 final SpooledInformation inform,
603 final String[] dirs,
604 final boolean strict) {
605 final ArrayNode array = node.putArray("FILES");
606 if (inform.fileMonitorInformation.fileItems.isEmpty()) {
607 array.add(0);
608 return;
609 }
610 if (!strict) {
611 final ArrayNode header = JsonHandler.createArrayNode();
612 header.add("FILE");
613 header.add("HASH");
614 header.add("LASTTIME");
615 header.add("USEDTIME");
616 header.add("USED");
617 header.add("ID");
618 array.add(header);
619 }
620 for (final FileItem fileItem : inform.fileMonitorInformation.fileItems.values()) {
621 final ObjectNode elt = JsonHandler.createObjectNode();
622 int i = 0;
623 String path = fileItem.file.getPath();
624 final String sep = path.lastIndexOf('/') >= 0? "/" : "\\";
625 for (final String dir : dirs) {
626 i++;
627 if (path.startsWith(dir + sep)) {
628 path = "(" + i + ')' + path.substring(dir.length());
629 break;
630 }
631 }
632 elt.put("FILE", path);
633 if (fileItem.hash != null) {
634 elt.put("HASH", FilesystemBasedDigest.getHex(fileItem.hash));
635 } else {
636 elt.putNull("HASH");
637 }
638 if (fileItem.lastTime > 0) {
639 elt.put("LASTTIME", fileItem.lastTime);
640 } else {
641 elt.putNull("LASTTIME");
642 }
643 if (fileItem.timeUsed > 0) {
644 elt.put("USEDTIME", fileItem.timeUsed);
645 } else {
646 elt.putNull("USEDTIME");
647 }
648 elt.put("USED", fileItem.used);
649 if (fileItem.specialId == ILLEGALVALUE) {
650 elt.put("ID", "");
651 } else {
652 elt.put("ID", Long.toString(fileItem.specialId));
653 }
654 array.add(elt);
655 }
656 }
657 }