package jdrivesync.report;
import jdrivesync.exception.JDriveSyncException;
import jdrivesync.logging.LoggerFactory;
import java.io.*;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;
public class HtmlReport implements Report {
private static final Logger LOGGER = LoggerFactory.getLogger();
private Date reportDate = new Date();
private File file = null;
private RandomAccessFile randomAccessFile = null;
private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH-mm-ss");
@Override
public void log(ReportEntry reportEntry) {
if (file == null) {
createFile();
writeHeader();
}
logReportEntry(reportEntry);
}
private void writeHeader() {
String headerPath = "/report/header.tpl";
InputStream resourceAsStream = HtmlReport.class.getResourceAsStream(headerPath);
if(resourceAsStream == null) {
throw new JDriveSyncException(JDriveSyncException.Reason.IOException, "Could not load HTML header '" + headerPath + "' from classpath.");
}
String header = streamToString(resourceAsStream);
try {
String headPlusFooter = header + createFooter();
randomAccessFile.write(headPlusFooter.getBytes("UTF-8"));
} catch (IOException e) {
throw new JDriveSyncException(JDriveSyncException.Reason.IOException, "Failed to write header to file '" + file.getAbsolutePath() + "'.", e);
}
}
private String streamToString(InputStream is) {
try {
StringBuilder out = new StringBuilder();
char[] buffer = new char[1024];
InputStreamReader isr = new InputStreamReader(is, "UTF-8");
int read = isr.read(buffer, 0, buffer.length);
while(read >= 0) {
out.append(buffer, 0, read);
read = isr.read(buffer, 0, buffer.length);
}
return out.toString();
} catch (UnsupportedEncodingException e) {
throw new JDriveSyncException(JDriveSyncException.Reason.IOException, "Unsupported encoding: " + e.getMessage(), e);
} catch (IOException e) {
throw new JDriveSyncException(JDriveSyncException.Reason.IOException, "Failed to convert input stream to String: " + e.getMessage(), e);
}
}
private void logReportEntry(ReportEntry reportEntry) {
String footer = createFooter();
int footerLength = footer.getBytes(Charset.forName("UTF-8")).length;
try {
randomAccessFile.seek(randomAccessFile.length() - footerLength);
LOGGER.log(Level.INFO, statusEntry(reportEntry) + " " + reportEntry.getAction() + " " + reportEntry.getRelativePath());
String entryPlusFooter = reportEntryToString(reportEntry) + "\n" + footer;
randomAccessFile.write(entryPlusFooter.getBytes("UTF-8"));
} catch (IOException e) {
throw new JDriveSyncException(JDriveSyncException.Reason.IOException, "Failed to write entry to file '" + file.getAbsolutePath() + "'.", e);
}
}
private String reportEntryToString(ReportEntry reportEntry) {
StringBuilder sb = new StringBuilder();
sb.append("<tr>\n");
sb.append("<td>").append(encodeHTML(reportEntry.getRelativePath())).append("</td>\n");
sb.append("<td>").append(encodeHTML(statusEntry(reportEntry))).append("</td>\n");
sb.append("<td>").append(reportEntry.getAction()).append("</td>\n");
sb.append("</tr>\n");
return sb.toString();
}
public static String statusEntry(ReportEntry reportEntry) {
StringBuilder sb = new StringBuilder();
if(reportEntry.getStatus() == ReportEntry.Status.Error) {
sb.append(reportEntry.getStatus());
sb.append("(");
if(reportEntry.getErrorMessage().isPresent()) {
sb.append(reportEntry.getErrorMessage().get());
} else {
sb.append("n.a.");
}
sb.append(")");
} else {
sb.append(reportEntry.getStatus());
}
return sb.toString();
}
private String createFooter() {
StringBuilder sb = new StringBuilder();
sb.append("</tbody>\n");
sb.append("</table>\n");
sb.append("</body>\n");
sb.append("</html>\n");
return sb.toString();
}
private void createFile() {
String filename = "jdrivesyncReport_" + sdf.format(reportDate) + ".html";
this.file = new File(filename);
if (file.exists()) {
boolean deleted = file.delete();
if (!deleted) {
throw new JDriveSyncException(JDriveSyncException.Reason.IllegalStateException, "Unable to delete file '" + file.getAbsolutePath() + "'.");
}
}
try {
this.randomAccessFile = new RandomAccessFile(file, "rws");
} catch (FileNotFoundException e) {
throw new JDriveSyncException(JDriveSyncException.Reason.IOException, "Failed to create file '" + file.getAbsolutePath() + "'.", e);
}
}
private String encodeHTML(String s) {
StringBuilder out = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c > 127 || c == '"' || c == '<' || c == '>') {
out.append("" + (int) c + ";");
} else {
out.append(c);
}
}
return out.toString();
}
}