/*********************************************************************************** * * Copyright (c) 2014 Kamil Baczkowicz * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * and Eclipse Distribution License v1.0 which accompany this distribution. * * The Eclipse Public License is available at * http://www.eclipse.org/legal/epl-v10.html * * The Eclipse Distribution License is available at * http://www.eclipse.org/org/documents/edl-v10.php. * * Contributors: * * Kamil Baczkowicz - initial API and implementation and/or initial documentation * */ package pl.baczkowicz.mqttspy.logger; import java.io.File; import java.util.ArrayList; import java.util.Date; import java.util.List; import org.apache.commons.codec.binary.Base64; import org.eclipse.paho.client.mqttv3.MqttMessage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import pl.baczkowicz.mqttspy.common.generated.LoggedMqttMessage; import pl.baczkowicz.mqttspy.messages.BaseMqttMessage; import pl.baczkowicz.spy.exceptions.SpyException; import pl.baczkowicz.spy.exceptions.XMLException; import pl.baczkowicz.spy.files.FileUtils; import pl.baczkowicz.spy.utils.ConversionUtils; import pl.baczkowicz.spy.utils.TimeUtils; import pl.baczkowicz.spy.utils.tasks.ProgressUpdater; /** * Message log utilities. */ public class MqttMessageLogParserUtils { /** Diagnostic logger. */ private final static Logger logger = LoggerFactory.getLogger(MqttMessageLogParserUtils.class); /** * This all-in-one method reads a message log from the given file and turns that into a list of MQTT message objects. * * @param selectedFile The file to read from * * @return List of MQTT messages (ReceivedMqttMessage objects) * * @throws SpyException Thrown when cannot process the given file */ public static List<BaseMqttMessage> readAndConvertMessageLog(final File selectedFile) throws SpyException { final List<String> lines = FileUtils.readFileAsLines(selectedFile); logger.info("Message audit log - read {} messages from {}", lines.size(), selectedFile.getAbsoluteFile()); return processMessageLog(parseMessageLog(lines, null, 0, 0), null, 0, 0); } // /** // * Reads a message log from the given file and turns that into a list of lines. // * // * @param selectedFile The file to read from // * // * @return List of lines // * // * @throws SpyException Thrown when cannot process the given file // */ // public static List<String> readMessageLog(final File selectedFile) throws SpyException // { // try // { // BufferedReader in = new BufferedReader(new FileReader(selectedFile)); // String str; // // final List<String> list = new ArrayList<String>(); // while((str = in.readLine()) != null) // { // list.add(str); // } // // in.close(); // logger.info("Message log - read {} messages from {}", list.size(), selectedFile.getAbsoluteFile()); // // return list; // } // catch (IOException e) // { // throw new SpyException("Can't open the message log file at " + selectedFile.getAbsolutePath(), e); // } // } /** * Parses the given list of XML messages into a list of MQTT message objects. * * @param messages The list of XML messages * @param progress The progress updater to call with updated progress * @param current Current progress * @param max Maximum progress value * * @return List of MQTT message objects (LoggedMqttMessage) * * @throws SpyException Thrown when cannot process the given list */ public static List<LoggedMqttMessage> parseMessageLog(final List<String> messages, final ProgressUpdater progress, final long current, final long max) throws SpyException { try { final long startTime = TimeUtils.getMonotonicTime(); final int items = messages.size(); final long chunkSize = items / 10; final MqttMessageLogParser parser = new MqttMessageLogParser(); final List<LoggedMqttMessage> list = new ArrayList<LoggedMqttMessage>(); long item = 0; long reportAt = 1; for (int i = 0; i < items; i++) //for (final String message : messages) { final String message = messages.get(i); if (progress != null) { if (progress.isCancelled()) { logger.info("Task cancelled!"); return null; } item++; // Update every 1000 if (item % 1000 == 0) { progress.update(current + item, max); } } // If we have 10%, 20%, 30%... if ((i > 0 ) && (i == (chunkSize * reportAt))) { final long currentTime = TimeUtils.getMonotonicTime(); final long timeTaken = currentTime - startTime; final long totalTimeExpected = timeTaken * items / i; // If the 10% took more than 1 second if (timeTaken > 1000) { logger.info("Processed {}%, estimated time left = {}s", reportAt * 10, (totalTimeExpected - timeTaken) / 1000); } reportAt++; } try { list.add(parser.parse(message)); } catch (XMLException e) { logger.error("Can't process message " + message, e); } } logger.info("Message audit log - parsed {} XML messages", list.size()); return list; } catch (XMLException e) { throw new SpyException("Can't parse the message audit log file", e); } } /** * Turns the given list of LoggedMqttMessages into ReceivedMqttMessages. * * @param list List of logged messages to progress * @param progress The progress updater to call with updated progress * @param current Current progress * @param max Maximum progress value * * @return List of MQTT message objects (ReceivedMqttMessage) */ public static List<BaseMqttMessage> processMessageLog( final List<LoggedMqttMessage> list, final ProgressUpdater progress, final long current, final long max) { final List<BaseMqttMessage> mqttMessageList = new ArrayList<BaseMqttMessage>(); long item = 0; // Process the messages for (final LoggedMqttMessage loggedMessage : list) { if (progress != null) { if (progress.isCancelled()) { logger.info("Task cancelled!"); return null; } item++; if (item % 1000 == 0) { progress.update(current + item, max); } } mqttMessageList.add(convertToBaseMqttMessage(loggedMessage)); } logger.info("Message audit log - processed {} MQTT messages", list.size()); return mqttMessageList; } public static BaseMqttMessage convertToBaseMqttMessage(final LoggedMqttMessage loggedMessage) { final MqttMessage mqttMessage = new MqttMessage(); if (logger.isTraceEnabled()) { logger.trace("Processing message with payload {}", loggedMessage.getValue()); } if (Boolean.TRUE.equals(loggedMessage.isEncoded())) { mqttMessage.setPayload(Base64.decodeBase64(loggedMessage.getValue())); } else { mqttMessage.setPayload(ConversionUtils.stringToArray(loggedMessage.getValue())); } mqttMessage.setQos(loggedMessage.getQos() == null ? 0 : loggedMessage.getQos()); mqttMessage.setRetained(loggedMessage.isRetained() == null ? false : loggedMessage.isRetained()); return new BaseMqttMessage(loggedMessage.getId(), loggedMessage.getTopic(), mqttMessage, new Date(loggedMessage.getTimestamp())); } }