/* * (C) Copyright 2017 Netcentric AG. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ package biz.netcentric.cq.tools.actool.history; import java.sql.Timestamp; import java.text.DateFormat; import java.text.NumberFormat; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashSet; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.TreeSet; import org.slf4j.Logger; import biz.netcentric.cq.tools.actool.api.InstallationLog; import biz.netcentric.cq.tools.actool.comparators.HistoryEntryComparator; import biz.netcentric.cq.tools.actool.configmodel.AcConfiguration; import biz.netcentric.cq.tools.actool.installationhistory.AcInstallationHistoryPojo; public class AcInstallationLog implements InstallationLog, AcInstallationHistoryPojo { private static final String MSG_IDENTIFIER_EXCEPTION = "EXCEPTION:"; private static final String MSG_IDENTIFIER_WARNING = "WARNING:"; private Set<HistoryEntry> warnings = new HashSet<HistoryEntry>(); private Set<HistoryEntry> messages = new HashSet<HistoryEntry>(); private Set<HistoryEntry> errors = new HashSet<HistoryEntry>(); private Set<HistoryEntry> verboseMessages = new HashSet<HistoryEntry>(); private boolean success = true; private Date installationDate; private long executionTime; private long msgIndex = 0; Rendition rendition; private String mergedAndProcessedConfig; private AcConfiguration acConfiguration; private Map<String, String> configFileContentsByName; // only for install hook case private String crxPackageName; private int countAclsNoChange = 0; private int countAclsChanged = 0; private int countAclsPathDoesNotExist = 0; private int countActionCacheHit = 0; private int countActionCacheMiss = 0; private DateFormat timestampFormat = new SimpleDateFormat("HH:mm:ss.SSS"); public enum Rendition { HTML, TXT; } public AcInstallationLog() { rendition = Rendition.TXT; setInstallationDate(new Date()); } public AcInstallationLog(Rendition rendition) { this.rendition = rendition; setInstallationDate(new Date()); } public Date getInstallationDate() { return installationDate; } public void setInstallationDate(final Date installationDate) { this.installationDate = installationDate; } public long getExecutionTime() { return executionTime; } public void setExecutionTime(final long time) { executionTime = time; } public Set<HistoryEntry> getWarnings() { return warnings; } public String getMergedAndProcessedConfig() { return mergedAndProcessedConfig; } public void setMergedAndProcessedConfig(String mergedAndProcessedConfig) { this.mergedAndProcessedConfig = mergedAndProcessedConfig; } public AcConfiguration getAcConfiguration() { return acConfiguration; } public void setAcConfiguration(AcConfiguration acConfiguration) { this.acConfiguration = acConfiguration; } public Map<String, String> getConfigFileContentsByName() { return configFileContentsByName; } public void setConfigFileContentsByName(Map<String, String> configFileContentsByName) { this.configFileContentsByName = configFileContentsByName; } /* (non-Javadoc) * @see biz.netcentric.cq.tools.actool.history.AcInstallationLo#getCrxPackageName() */ @Override public String getCrxPackageName() { return crxPackageName; } public void setCrxPackageName(String crxPackageName) { this.crxPackageName = crxPackageName; } public void addWarning(Logger log, String warning) { log.warn(warning); addWarning(warning); } private void addWarning(String warning) { if (rendition.equals(Rendition.HTML)) { warnings.add(new HistoryEntry(msgIndex, new Timestamp( new Date().getTime()), "<font color='orange'><b>" + MSG_IDENTIFIER_WARNING + " " + warning + "</b></font>")); } else if (rendition.equals(Rendition.TXT)) { warnings.add(new HistoryEntry(msgIndex, new Timestamp( new Date().getTime()), MSG_IDENTIFIER_WARNING + " " + warning)); } msgIndex++; } public void addMessage(Logger log, String message) { log.info(message); addMessage(message); } private void addMessage(String message) { messages.add(new HistoryEntry(msgIndex, new Timestamp(new Date() .getTime()), " " + message)); msgIndex++; } public void addError(Logger log, String error, Throwable e) { log.error(error, e); addError(error + " / e=" + e); } public void addError(Logger log, String error) { log.error(error); addError(error); } public void addError(final String error) { if (rendition.equals(Rendition.HTML)) { errors.add(new HistoryEntry(msgIndex, new Timestamp( new Date().getTime()), "<font color='red'><b>" + MSG_IDENTIFIER_EXCEPTION + "</b>" + " " + error + "</b></font>")); } else if (rendition.equals(Rendition.TXT)) { errors.add(new HistoryEntry(msgIndex, new Timestamp( new Date().getTime()), MSG_IDENTIFIER_EXCEPTION + " " + error)); } success = false; msgIndex++; } public void addVerboseMessage(Logger log, String message) { log.debug(message); addVerboseMessage(message); } private void addVerboseMessage(String message) { verboseMessages.add(new HistoryEntry(msgIndex, new Timestamp( new Date().getTime()), " " + message)); msgIndex++; } public Set<HistoryEntry> getMessages() { return messages; } public Set<HistoryEntry> getErrors() { return errors; } public boolean isSuccess() { return success; } public void setSuccess(final boolean success) { this.success = success; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("\n" + "Installation triggered: " + installationDate.toString() + "\n"); sb.append("\n" + getMessageHistory() + "\n"); sb.append("\n" + "Execution time: " + msHumanReadable(executionTime) + "\n"); if (rendition.equals(Rendition.HTML)) { if (success) { sb.append(HtmlConstants.FONT_COLOR_SUCCESS_HTML_OPEN); } else { sb.append(HtmlConstants.FONT_COLOR_NO_SUCCESS_HTML_OPEN); } } sb.append("\n" + "Success: " + success); if (rendition.equals(Rendition.HTML)) { sb.append(HtmlConstants.FONT_COLOR_SUCCESS_HTML_CLOSE); } return sb.toString(); } /* (non-Javadoc) * @see biz.netcentric.cq.tools.actool.history.AcInstallationLo#getMessageHistory() */ @Override @SuppressWarnings("unchecked") public String getMessageHistory() { return getMessageString(getMessageSet(warnings, messages, errors)); } /* (non-Javadoc) * @see biz.netcentric.cq.tools.actool.history.AcInstallationLo#getVerboseMessageHistory() */ @Override @SuppressWarnings("unchecked") public String getVerboseMessageHistory() { return getMessageString(getMessageSet(warnings, messages, verboseMessages, errors)); } private Set<HistoryEntry> getMessageSet(Set<HistoryEntry>... sets) { Set<HistoryEntry> resultSet = new TreeSet<HistoryEntry>( new HistoryEntryComparator()); for (Set<HistoryEntry> set : sets) { for (HistoryEntry entry : set) { resultSet.add(entry); } } return resultSet; } private String getMessageString(Set<HistoryEntry> messageHistorySet) { StringBuilder sb = new StringBuilder(); if (!messageHistorySet.isEmpty()) { for (HistoryEntry entry : messageHistorySet) { sb.append("\n" + timestampFormat.format(entry.getTimestamp()) + ": " + entry.getMessage()); } } return sb.toString(); } /** Utility method to return any magnitude of milliseconds in a human readable format using the appropriate time unit (ms, sec, min) * depending on the magnitude of the input. * * @param millis milliseconds * @return a string with a number and a unit */ public static String msHumanReadable(final long millis) { double number = millis; final String[] units = new String[] { "ms", "sec", "min", "h", "days" }; final double[] divisors = new double[] { 1000, 60, 60, 24 }; int magnitude = 0; do { double currentDivisor = divisors[Math.min(magnitude, divisors.length - 1)]; if (number < currentDivisor) { break; } number /= currentDivisor; magnitude++; } while (magnitude < units.length - 1); NumberFormat format = NumberFormat.getNumberInstance(Locale.UK); format.setMinimumFractionDigits(0); format.setMaximumFractionDigits(1); String result = format.format(number) + units[magnitude]; return result; } public void incCountAclsNoChange() { countAclsNoChange++; } /* (non-Javadoc) * @see biz.netcentric.cq.tools.actool.history.AcInstallationLo#getCountAclsUnchanged() */ @Override public int getCountAclsUnchanged() { return countAclsNoChange; } public void incCountAclsChanged() { countAclsChanged++; } /* (non-Javadoc) * @see biz.netcentric.cq.tools.actool.history.AcInstallationLo#getCountAclsChanged() */ @Override public int getCountAclsChanged() { return countAclsChanged; } public void incCountAclsPathDoesNotExist() { countAclsPathDoesNotExist++; } /* (non-Javadoc) * @see biz.netcentric.cq.tools.actool.history.AcInstallationLo#getCountAclsPathDoesNotExist() */ @Override public int getCountAclsPathDoesNotExist() { return countAclsPathDoesNotExist; } public void incCountActionCacheMiss() { countActionCacheMiss++; } /* (non-Javadoc) * @see biz.netcentric.cq.tools.actool.history.AcInstallationLo#getCountActionCacheMiss() */ @Override public int getCountActionCacheMiss() { return countActionCacheMiss; } public void incCountActionCacheHit() { countActionCacheHit++; } /* (non-Javadoc) * @see biz.netcentric.cq.tools.actool.history.AcInstallationLo#getCountActionCacheHit() */ @Override public int getCountActionCacheHit() { return countActionCacheHit; } }