/**
* This file is part of Waarp Project.
*
* Copyright 2009, Frederic Bregier, and individual contributors by the @author tags. See the
* COPYRIGHT.txt in the distribution for a full listing of individual contributors.
*
* All Waarp Project is free software: you can redistribute it and/or modify it under the terms of
* the GNU General Public License as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* Waarp is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Waarp . If not, see
* <http://www.gnu.org/licenses/>.
*/
package org.waarp.openr66.context.task;
import java.io.File;
import java.io.IOException;
import java.text.DateFormat;
import java.util.Date;
import java.util.Set;
import java.util.TreeMap;
import org.waarp.common.digest.FilesystemBasedDigest;
import org.waarp.common.filemonitor.FileMonitor.FileItem;
import org.waarp.common.filemonitor.FileMonitor.FileMonitorInformation;
import org.waarp.common.json.JsonHandler;
import org.waarp.common.logging.WaarpLogger;
import org.waarp.common.logging.WaarpLoggerFactory;
import org.waarp.common.utility.WaarpStringUtils;
import org.waarp.openr66.client.SpooledDirectoryTransfer;
import org.waarp.openr66.database.DbConstant;
import org.waarp.openr66.protocol.configuration.Configuration;
import org.waarp.openr66.protocol.configuration.Messages;
import org.waarp.openr66.protocol.exception.OpenR66ProtocolPacketException;
import org.waarp.openr66.protocol.localhandler.packet.BusinessRequestPacket;
import org.waarp.openr66.protocol.utils.ChannelUtils;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
/**
* Java Task for SpooledDirectory information to the Waarp Server
*
* @author Frederic Bregier
*
*/
public class SpooledInformTask extends AbstractExecJavaTask {
/**
* Internal Logger
*/
private static final WaarpLogger logger = WaarpLoggerFactory
.getLogger(SpooledInformTask.class);
static final TreeMap<String, SpooledInformation> spooledInformationMap = new TreeMap<String, SpooledInformTask.SpooledInformation>();
public static class SpooledInformation {
public String host;
public FileMonitorInformation fileMonitorInformation;
public Date lastUpdate = new Date();
/**
* @param host
* @param fileItemHashMap
*/
private SpooledInformation(String host, FileMonitorInformation fileMonitorInformation) {
this.host = host;
this.fileMonitorInformation = fileMonitorInformation;
}
}
@Override
public void run() {
if (callFromBusiness) {
// Business Request to validate?
String validated = SpooledDirectoryTransfer.PARTIALOK;
if (isToValidate) {
try {
FileMonitorInformation fileMonitorInformation =
JsonHandler.mapper.readValue(fullarg, FileMonitorInformation.class);
logger.info("Receive SpooledInform of size: "
+ fullarg.length()
+ " ("
+ fileMonitorInformation.fileItems.size()
+ ", "
+
(fileMonitorInformation.removedFileItems != null ? fileMonitorInformation.removedFileItems
.size() : -1) + ")");
String host = this.session.getAuth().getUser();
synchronized (spooledInformationMap) {
if (fileMonitorInformation.removedFileItems == null
|| fileMonitorInformation.removedFileItems.isEmpty()) {
SpooledInformation old = spooledInformationMap.put(fileMonitorInformation.name,
new SpooledInformation(host, fileMonitorInformation));
if (old != null && old.fileMonitorInformation != null) {
if (old.fileMonitorInformation.directories != null) {
old.fileMonitorInformation.directories.clear();
}
if (old.fileMonitorInformation.fileItems != null) {
old.fileMonitorInformation.fileItems.clear();
}
old.fileMonitorInformation = null;
}
old = null;
} else {
// partial update
SpooledInformation update = spooledInformationMap.get(fileMonitorInformation.name);
if (update == null) {
// Issue since update is not existing so full update is needed next time
spooledInformationMap.put(fileMonitorInformation.name, new SpooledInformation(host,
fileMonitorInformation));
validated = SpooledDirectoryTransfer.NEEDFULL;
} else {
for (String item : fileMonitorInformation.removedFileItems) {
update.fileMonitorInformation.fileItems.remove(item);
}
update.fileMonitorInformation.fileItems.putAll(fileMonitorInformation.fileItems);
update.lastUpdate = new Date();
}
}
}
} catch (JsonParseException e1) {
logger.warn("Cannot parse SpooledInformation: " + fullarg + " " + e1.getMessage());
} catch (JsonMappingException e1) {
logger.warn("Cannot parse SpooledInformation: " + fullarg + " " + e1.getMessage());
} catch (IOException e1) {
logger.warn("Cannot parse SpooledInformation: " + e1.getMessage());
}
BusinessRequestPacket packet =
new BusinessRequestPacket(this.getClass().getName() + " informed", 0);
validate(packet);
try {
ChannelUtils.writeAbstractLocalPacket(session.getLocalChannelReference(),
packet, true);
} catch (OpenR66ProtocolPacketException e) {
}
this.status = 0;
}
finalValidate(validated);
} else {
// unallowed
logger.warn("SpooledInformTask not allowed as Java Task: " + fullarg);
invalid();
}
}
/**
* @param detailed
* @param status
* 1 for ok, -1 for ko, 0 for all
* @param uri
* @return the StringBuilder containing the HTML format as a Table of the current Spooled information
*/
public static StringBuilder buildSpooledTable(boolean detailed, int status, String uri) {
StringBuilder builder = beginSpooledTable(detailed, uri);
// get current information
synchronized (spooledInformationMap) {
Set<String> names = spooledInformationMap.keySet();
for (String name : names) {
// per Name
buildSpooledTableElement(detailed, status, builder, name);
}
}
endSpooledTable(builder);
return builder;
}
/**
* @param name
* @param uri
* @return the StringBuilder containing the HTML format as a Table of the current Spooled information
*/
public static StringBuilder buildSpooledUniqueTable(String uri, String name) {
StringBuilder builder = beginSpooledTable(false, uri);
// get current information
synchronized (spooledInformationMap) {
// per Name
SpooledInformation inform = buildSpooledTableElement(false, 0, builder, name);
endSpooledTable(builder);
builder.append("<BR>");
if (inform != null) {
buildSpooledTableFiles(builder, inform);
}
}
return builder;
}
/**
* @param builder
*/
private static void endSpooledTable(StringBuilder builder) {
builder.append("</TBODY></TABLE></small>");
}
/**
* @param detailed
* @param uri
* @return the associated StringBuilder as temporary result
*/
private static StringBuilder beginSpooledTable(boolean detailed, String uri) {
StringBuilder builder = new StringBuilder();
builder.append("<small><TABLE class='table table-condensed table-bordered' BORDER=1><CAPTION><A HREF=");
builder.append(uri);
if (detailed) {
builder.append(Messages.getString("SpooledInformTask.TitleDetailed")); //$NON-NLS-1$
} else {
builder.append(Messages.getString("SpooledInformTask.TitleNormal")); //$NON-NLS-1$
}
// title first
builder.append("<THEAD><TR><TH>").append(Messages.getString("SpooledInformTask.0")) //$NON-NLS-1$
.append("</TH><TH>").append(Messages.getString("SpooledInformTask.1")) //$NON-NLS-1$
.append("</TH><TH>").append(Messages.getString("SpooledInformTask.2")) //$NON-NLS-1$
.append("</TH><TH>").append(Messages.getString("SpooledInformTask.3")) //$NON-NLS-1$
.append("</TH><TH>").append(Messages.getString("SpooledInformTask.4")) //$NON-NLS-1$
.append("</TH><TH>").append(Messages.getString("SpooledInformTask.5")) //$NON-NLS-1$
.append("</TH><TH>").append(Messages.getString("SpooledInformTask.6")) //$NON-NLS-1$
.append("</TH><TH>").append(Messages.getString("SpooledInformTask.7")) //$NON-NLS-1$
.append("</TH><TH>").append(Messages.getString("SpooledInformTask.8")) //$NON-NLS-1$
.append("</TH><TH>").append(Messages.getString("SpooledInformTask.9")) //$NON-NLS-1$
.append("</TH></TR></THEAD><TBODY>");
return builder;
}
/**
* @param detailed
* @param status
* @param builder
* @param name
*/
private static SpooledInformation buildSpooledTableElement(boolean detailed, int status, StringBuilder builder,
String name) {
SpooledInformation inform = spooledInformationMap.get(name);
if (inform == null) {
return null;
}
long time = inform.lastUpdate.getTime() + Configuration.configuration.getTIMEOUTCON();
long curtime = System.currentTimeMillis();
if (time + Configuration.configuration.getTIMEOUTCON() < curtime) {
if (status > 0) {
return inform;
}
} else {
if (status < 0) {
return inform;
}
}
builder.append("<TR><TH>").append(name.replace(',', ' ')).append("</TH><TD>").append(inform.host)
.append("</TD>");
if (time + Configuration.configuration.getTIMEOUTCON() < curtime) {
builder.append("<TD bgcolor=Red>");
} else if (time < curtime) {
builder.append("<TD bgcolor=Orange>");
} else {
builder.append("<TD bgcolor=LightGreen>");
}
builder.append(dateFormat.format(inform.lastUpdate)).append("</TD>");
if (inform.fileMonitorInformation != null) {
builder.append(Messages.getString("SpooledInformTask.AllOk")) //$NON-NLS-1$
.append(inform.fileMonitorInformation.globalok)
.append(Messages.getString("SpooledInformTask.AllError")) //$NON-NLS-1$
.append(inform.fileMonitorInformation.globalerror)
.append(Messages.getString("SpooledInformTask.TodayOk")) //$NON-NLS-1$
.append(inform.fileMonitorInformation.todayok)
.append(Messages.getString("SpooledInformTask.TodayError")) //$NON-NLS-1$
.append(inform.fileMonitorInformation.todayerror)
.append("</TD><TD>")
.append(inform.fileMonitorInformation.elapseTime)
.append("</TD><TD>")
.append(inform.fileMonitorInformation.stopFile)
.append("</TD><TD>")
.append(inform.fileMonitorInformation.statusFile)
.append("</TD><TD>")
.append(inform.fileMonitorInformation.scanSubDir)
.append("</TD>");
String dirs = "<ul class='list-unstyled'>";
for (File dir : inform.fileMonitorInformation.directories) {
dirs += "<li>" + dir + "</li>";
}
dirs += "</ul>";
builder.append("<TD>").append(dirs).append("</TD><TD>");
if (detailed && inform.fileMonitorInformation.fileItems != null) {
buildSpooledTableFiles(builder, inform);
} else {
// simply print number of files
if (inform.fileMonitorInformation.fileItems != null) {
builder.append(inform.fileMonitorInformation.fileItems.size());
} else {
builder.append(0);
}
// Form GET to ensure encoding
builder.append(
"<FORM class='form-inline' name='DETAIL' method='GET' action='/SpooledDetailed.html'><input type=hidden name='name' value='")
.append(name).append("'/><INPUT type='submit' class='btn btn-info btn-sm' value='DETAIL'/></FORM>");
}
}
builder.append("</TD></TR>");
return inform;
}
private static DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.LONG);
/**
* @param builder
* @param inform
*/
private static void buildSpooledTableFiles(StringBuilder builder, SpooledInformation inform) {
builder.append("<small><TABLE class='table table-condensed table-bordered' BORDER=1><THEAD><TR><TH>").append(Messages.getString("SpooledInformTask.10")) //$NON-NLS-1$
.append("</TH><TH>").append(Messages.getString("SpooledInformTask.11")) //$NON-NLS-1$
.append("</TH><TH>").append(Messages.getString("SpooledInformTask.12")) //$NON-NLS-1$
.append("</TH><TH>").append(Messages.getString("SpooledInformTask.13")) //$NON-NLS-1$
.append("</TH><TH>").append(Messages.getString("SpooledInformTask.14")) //$NON-NLS-1$
.append("</TH><TH>").append(Messages.getString("SpooledInformTask.15")) //$NON-NLS-1$
.append("</TH></TR></THEAD><TBODY>");
for (FileItem fileItem : inform.fileMonitorInformation.fileItems.values()) {
builder.append("<TR><TD>").append(fileItem.file).append("</TD><TD>");
if (fileItem.hash != null) {
builder.append(FilesystemBasedDigest.getHex(fileItem.hash));
}
builder.append("</TD><TD>");
if (fileItem.lastTime > 0) {
builder.append(dateFormat.format(new Date(fileItem.lastTime)));
}
builder.append("</TD><TD>");
if (fileItem.timeUsed > 0) {
builder.append(dateFormat.format(new Date(fileItem.timeUsed)));
}
builder.append("</TD><TD>").append(fileItem.used).append("</TD><TD>")
.append(fileItem.specialId).append("</TD></TR>");
}
builder.append("</TBODY></TABLE></small>");
}
/**
* @param detailed
* @param status
* 1 for ok, -1 for ko, 0 for all
* @param uri
* @return the String containing the JSON format of the current Spooled information
*/
public static String buildSpooledJson(boolean detailed, int status, String uri) {
ArrayNode array = JsonHandler.createArrayNode();
// get current information
synchronized (spooledInformationMap) {
Set<String> names = spooledInformationMap.keySet();
for (String name : names) {
// per Name
buildSpooledJsonElement(detailed, status, array, name);
}
}
return WaarpStringUtils.cleanJsonForHtml(array.toString());
}
/**
* @param name
* @param uri
* @return the String containing the JSON format of the current Spooled information
*/
public static String buildSpooledUniqueJson(String uri, String name) {
ArrayNode array = JsonHandler.createArrayNode();
// get current information
synchronized (spooledInformationMap) {
// per Name
buildSpooledJsonElement(true, 0, array, name);
}
logger.warn(array.toString());
return WaarpStringUtils.cleanJsonForHtml(array.toString());
}
/**
* @param detailed
* @param status
* @param builder
* @param name
*/
private static void buildSpooledJsonElement(boolean detailed, int status, ArrayNode array,
String name) {
SpooledInformation inform = spooledInformationMap.get(name);
if (inform == null) {
return;
}
long time = inform.lastUpdate.getTime() + Configuration.configuration.getTIMEOUTCON();
long curtime = System.currentTimeMillis();
if (status != 0) {
if (time + Configuration.configuration.getTIMEOUTCON() < curtime) {
if (status < 0) {
return;
}
} else if (status > 0) {
return;
}
}
ObjectNode elt = JsonHandler.createObjectNode();
elt.put("NAME", name.replace(',', ' '));
elt.put("HOST", inform.host);
String val = null;
if (time + Configuration.configuration.getTIMEOUTCON() < curtime) {
val = "bg-danger";
} else if (time < curtime) {
val = "bg-warning";
} else {
val = "bg-success";
}
elt.put("LAST_UPDATE", val + " " + inform.lastUpdate.getTime());
if (inform.fileMonitorInformation != null) {
elt.put("GLOBALOK", inform.fileMonitorInformation.globalok.get());
elt.put("GLOBALERROR", inform.fileMonitorInformation.globalerror.get());
elt.put("TODAYOK", inform.fileMonitorInformation.todayok.get());
elt.put("TODAYERROR", inform.fileMonitorInformation.todayerror.get());
elt.put("INTERVAL", inform.fileMonitorInformation.elapseTime);
elt.put("STOPFILE", inform.fileMonitorInformation.stopFile.getPath());
elt.put("STATUSFILE", inform.fileMonitorInformation.statusFile.getPath());
elt.put("SUBDIRS", inform.fileMonitorInformation.scanSubDir);
String dirs = "";
String dirs2 = "";
int i = 0;
for (File dir : inform.fileMonitorInformation.directories) {
i++;
dirs += dir + "("+i+") ";
dirs2 += dir + " ";
}
elt.put("DIRECTORIES", dirs);
if (detailed && inform.fileMonitorInformation.fileItems != null) {
buildSpooledJsonFiles(elt, inform, dirs2.split(" "));
} else {
// simply print number of files
if (inform.fileMonitorInformation.fileItems != null) {
elt.putArray("FILES").add(inform.fileMonitorInformation.fileItems.size());
} else {
elt.putArray("FILES").add(0);
}
}
}
array.add(elt);
return;
}
/**
* @param builder
* @param inform
*/
private static void buildSpooledJsonFiles(ObjectNode node, SpooledInformation inform, String []dirs) {
ArrayNode array = node.putArray("FILES");
if (inform.fileMonitorInformation.fileItems.size() == 0) {
array.add(0);
return;
}
ArrayNode header = JsonHandler.createArrayNode();
header.add("FILE");
header.add("HASH");
header.add("LASTTIME");
header.add("USEDTIME");
header.add("USED");
header.add("ID");
array.add(header);
for (FileItem fileItem : inform.fileMonitorInformation.fileItems.values()) {
ObjectNode elt = JsonHandler.createObjectNode();
int i = 0;
String path = fileItem.file.getPath();
String sep = path.lastIndexOf('/') >= 0 ? "/" : "\\";
for (String dir : dirs) {
i++;
if (path.startsWith(dir+sep)) {
path = "("+i+")"+path.substring(dir.length());
break;
}
}
elt.put("FILE", path);
if (fileItem.hash != null) {
elt.put("HASH", FilesystemBasedDigest.getHex(fileItem.hash));
} else {
elt.putNull("HASH");
}
if (fileItem.lastTime > 0) {
elt.put("LASTTIME", fileItem.lastTime);
} else {
elt.putNull("LASTTIME");
}
if (fileItem.timeUsed > 0) {
elt.put("USEDTIME", fileItem.timeUsed);
} else {
elt.putNull("USEDTIME");
}
elt.put("USED", fileItem.used);
if (fileItem.specialId == DbConstant.ILLEGALVALUE) {
elt.put("ID", "");
} else {
elt.put("ID", Long.toString(fileItem.specialId));
}
array.add(elt);
}
}
}