package se.sitic.megatron.report; import java.io.File; import java.io.IOException; import java.util.Map; import org.apache.log4j.Logger; import org.joda.time.DateTime; import org.joda.time.DateTimeConstants; import se.sitic.megatron.core.AppProperties; import se.sitic.megatron.core.MegatronException; import se.sitic.megatron.core.TimePeriod; import se.sitic.megatron.core.TypedProperties; import se.sitic.megatron.db.DbManager; import se.sitic.megatron.util.Constants; import se.sitic.megatron.util.FileUtil; import se.sitic.megatron.util.StringUtil; // Swedish characters: aao AAO: \u00e5\u00e4\u00f6 \u00c5\u00c4\u00d6 /** * Creates XML files with overview statistics. Can be used in JavaScript or * Flash graphs. */ public class StatisticsXmlReportGenerator implements IReportGenerator { private final Logger log = Logger.getLogger(StatisticsXmlReportGenerator.class); /** Entry types to include in graph. */ private static final String[] ENTRY_TYPES = { "Botn\u00e4t", "Skr\u00e4ppost (RBL)", "\u00d6vrigt" }; private static final int PROCESSED_LINES_FILE = 1; private static final int PROCESSED_LINES_SUM_FILE = 2; private static final int ALL_LOG_ENTRIES_FILE = 3; private static final int MATCHED_LOG_ENTRIES_FILE = 4; private static final String PROCESSED_LINES_FILENAME = "megatron-processed-lines.xml"; private static final String PROCESSED_LINES_SUM_FILENAME = "megatron-processed-lines-sum.xml"; private static final String ALL_LOG_ENTRIES_FILENAME = "megatron-all-entries.xml"; private static final String MATCHED_LOG_ENTRIES_FILENAME = "megatron-matched-entries.xml"; private static final String TOTAL_ENTRY_TYPE_NAME = "Totalt"; private static final String DOC_TEMPLATE = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + Constants.LINE_BREAK + "<data>" + Constants.LINE_BREAK + "@[email protected]" + Constants.LINE_BREAK + "@[email protected]" + "</data>"; private static final String SERIES_NAMES_TEMPLATE = " <seriesNames>" + Constants.LINE_BREAK + "@[email protected]" + " </seriesNames>" + Constants.LINE_BREAK; private static final String NAME_SERIE_TEMPLATE = " <[email protected]@>@[email protected]</[email protected]@>" + Constants.LINE_BREAK; private static final String SERIES_VALUES_TEMPLATE = " <seriesValues time=\"@[email protected]\">" + Constants.LINE_BREAK + "@[email protected]" + " </seriesValues>" + Constants.LINE_BREAK; private static final String VALUE_SERIE_TEMPLATE = " <[email protected]@>@[email protected]</[email protected]@>" + Constants.LINE_BREAK; private TypedProperties props; public StatisticsXmlReportGenerator() { // empty } @Override public void init() { this.props = AppProperties.getInstance().getGlobalProperties(); } @Override public void createFiles() throws MegatronException { log.info("Creating XML files with overview statistics."); DbManager dbManager = null; try { dbManager = DbManager.createDbManager(props); createFile(dbManager, PROCESSED_LINES_FILE); createFile(dbManager, PROCESSED_LINES_SUM_FILE); createFile(dbManager, ALL_LOG_ENTRIES_FILE); createFile(dbManager, MATCHED_LOG_ENTRIES_FILE); } finally { if (dbManager != null) { dbManager.close(); } } } private void createFile(DbManager dbManager, int fileType) throws MegatronException { // -- init int noOfWeeks = props.getInt(AppProperties.REPORT_STATISTICS_NO_OF_WEEKS_KEY, 0); if (noOfWeeks == 0) { // read deprecated property noOfWeeks = props.getInt(AppProperties.FLASH_NO_OF_WEEKS_KEY, 5); } DateTime dateTime = startDateTime(noOfWeeks); String outputDir = props.getString(AppProperties.REPORT_OUTPUT_DIR_KEY, null); if (outputDir == null) { // read deprecated property outputDir = props.getString(AppProperties.FLASH_OUTPUT_DIR_KEY, "/var/megatron/flash-xml"); } try { FileUtil.ensureDir(outputDir); } catch (IOException e) { throw new MegatronException("Cannot create directory: " + outputDir, e); } String[] entryTypes = { TOTAL_ENTRY_TYPE_NAME }; if (fileType != PROCESSED_LINES_SUM_FILE) { entryTypes = ENTRY_TYPES; } // -- seriesNames StringBuilder nameSeries = new StringBuilder(1*1024); for (int i = 0; i < entryTypes.length; i++) { String entryType = entryTypes[i]; String nameSerie = NAME_SERIE_TEMPLATE; nameSerie = StringUtil.replace(nameSerie, "@[email protected]", i + ""); nameSerie = StringUtil.replace(nameSerie, "@[email protected]", entryType); nameSeries.append(nameSerie); } String seriesNames = SERIES_NAMES_TEMPLATE; seriesNames = StringUtil.replace(seriesNames, "@[email protected]", nameSeries.toString()); // -- seriesValues StringBuilder seriesValues = new StringBuilder(2*1024); for (int i = 0; i < noOfWeeks; i++) { Map<String, Long> valuesMap = null; if ((fileType == PROCESSED_LINES_FILE) || (fileType == PROCESSED_LINES_SUM_FILE)) { valuesMap = fetchNoOfProcessedLinesPerEntryType(dbManager, dateTime); } else if (fileType == ALL_LOG_ENTRIES_FILE) { valuesMap = fetchNoOfLogEntriesPerEntryType(dbManager, dateTime, false); } else { // MATCHED_LOG_ENTRIES_FILE valuesMap = fetchNoOfLogEntriesPerEntryType(dbManager, dateTime, true); } StringBuilder valueSeries = new StringBuilder(1*1024); for (int j = 0; j < entryTypes.length; j++) { String entryType = entryTypes[j]; Long val = valuesMap.get(entryType); if (val == null) { log.warn("Cannot find value for entry type: " + entryType); val = new Long(0); } String valueSerie = VALUE_SERIE_TEMPLATE; valueSerie = StringUtil.replace(valueSerie, "@[email protected]", j + ""); valueSerie = StringUtil.replace(valueSerie, "@[email protected]", val.toString()); valueSeries.append(valueSerie); } String seriesValuesItem = SERIES_VALUES_TEMPLATE; int week = dateTime.getWeekOfWeekyear(); seriesValuesItem = StringUtil.replace(seriesValuesItem, "@[email protected]", "v." + week); seriesValuesItem = StringUtil.replace(seriesValuesItem, "@[email protected]", valueSeries.toString()); seriesValues.append(seriesValuesItem); dateTime = dateTime.plusDays(7); } // -- XML doc String doc = DOC_TEMPLATE; doc = StringUtil.replace(doc, "@[email protected]", seriesNames); doc = StringUtil.replace(doc, "@[email protected]", seriesValues.toString()); // -- write to file String filename = null; if (fileType == PROCESSED_LINES_FILE) { filename = PROCESSED_LINES_FILENAME; } else if (fileType == PROCESSED_LINES_SUM_FILE) { filename = PROCESSED_LINES_SUM_FILENAME; } else if (fileType == ALL_LOG_ENTRIES_FILE) { filename = ALL_LOG_ENTRIES_FILENAME; } else { // MATCHED_LOG_ENTRIES_FILE filename = MATCHED_LOG_ENTRIES_FILENAME; } File file = new File(outputDir, filename); try { FileUtil.writeFile(file, doc, Constants.UTF8); } catch (IOException e) { throw new MegatronException("Cannot create Flash XML file: " + file.getAbsoluteFile(), e); } log.info("Flash XML file created: " + file.getAbsoluteFile() + " (" + file.length() + " bytes)."); } private DateTime startDateTime(int noOfWeeks) { // find first monday DateTime result = new DateTime(); while (true) { if (result.getDayOfWeek() == DateTimeConstants.MONDAY) { break; } result = result.minusDays(1); } return result.minusDays(7*noOfWeeks); } private Map<String, Long> fetchNoOfProcessedLinesPerEntryType(DbManager dbManager, DateTime startDate) throws MegatronException { TimePeriod timePeriod = createWeekTimePeriod(startDate); log.debug("Fetching no. of processed lines for period: " + timePeriod.getFormattedPeriodString(TimePeriod.LONG_FORMAT)); // // create dummy // Map<String, Long> result = new HashMap<String, Long>(); // int intervalStart = 20000; // int intervalEnd = 40000; // result.put("Foo", randomLong(intervalStart, intervalEnd)); // result.put("Skr\u00e4ppost (RBL)", randomLong(intervalStart, intervalEnd)); // result.put("\u00d6vrigt", randomLong(intervalStart, intervalEnd)); // result.put("Botn\u00e4t", randomLong(intervalStart, intervalEnd)); // result.put("Bar", randomLong(intervalStart, intervalEnd)); // return result; Map<String, Long> result = dbManager.fetchNoOfProcessedLinesPerEntryType(timePeriod.getStartDate(), timePeriod.getEndDate()); // Add "Total" entry type long total = 0L; for (int i = 0; i < ENTRY_TYPES.length; i++) { String entryType = ENTRY_TYPES[i]; Long val = result.get(entryType); if (val == null) { log.warn("Cannot find value for entry type: " + entryType); val = new Long(0); } total += val; } result.put(TOTAL_ENTRY_TYPE_NAME, total); return result; } private Map<String, Long> fetchNoOfLogEntriesPerEntryType(DbManager dbManager, DateTime startDate, boolean onlyMatchedEntries) throws MegatronException { TimePeriod timePeriod = createWeekTimePeriod(startDate); log.debug("Fetching no. of log entries for period: " + timePeriod.getFormattedPeriodString(TimePeriod.LONG_FORMAT)); // // create dummy // Map<String, Long> result = new HashMap<String, Long>(); // int intervalStart = onlyMatchedEntries ? 5000 : 8000; // int intervalEnd = onlyMatchedEntries ? 12000 : 15000; // result.put("\u00d6vrigt", randomLong(intervalStart, intervalEnd)); // result.put("Skr\u00e4ppost (RBL)", randomLong(intervalStart, intervalEnd)); // result.put("Foo", randomLong(intervalStart, intervalEnd)); // result.put("Botn\u00e4t", randomLong(intervalStart, intervalEnd)); // result.put("Bar", randomLong(intervalStart, intervalEnd)); // return result; return dbManager.fetchNoOfLogEntriesPerEntryType(timePeriod.getStartDate(), timePeriod.getEndDate(), onlyMatchedEntries); } private TimePeriod createWeekTimePeriod(DateTime dateTime) throws MegatronException { int week = dateTime.getWeekOfWeekyear(); String periodStr = "w" + dateTime.getYear() + "-" + week; return new TimePeriod(periodStr); } // UNUSED // private Long randomLong(int intervalStart, int intervalEnd) { // Random rand = new Random(); // long result = Math.abs(rand.nextLong()); // result = intervalStart + (result % (intervalEnd - intervalStart)); // return new Long(result); // } }