package de.ugoe.cs.eventbench.windows; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import java.security.InvalidParameterException; import java.util.Collection; import java.util.LinkedList; import java.util.List; import java.util.SortedMap; import java.util.TreeMap; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import org.xml.sax.helpers.DefaultHandler; import de.ugoe.cs.eventbench.windows.data.WindowTree; import de.ugoe.cs.eventbench.windows.data.WindowsEvent; import de.ugoe.cs.eventbench.windows.data.WindowsMessage; import de.ugoe.cs.util.StringTools; import de.ugoe.cs.util.console.Console; /** *

* This class provides functionality to parse XML log files generated by the * MFCUsageMonitor of EventBench. The result of parsing a file is a collection * of event sequences. It uses the {@link SequenceSplitter} and the * {@link EventGenerator} as well as custom defined {@link MessageHandler} for * the parsing. *

* * @author Steffen Herbold * @version 1.0 */ public class MFCLogParser extends DefaultHandler { /** *

* If a custom message handler is used, this field contains its handle. * Otherwise this field is {@code null}. *

*/ private MessageHandler currentHandler; /** *

* Handle to the message that is currently parsed. *

*/ private WindowsMessage currentMessage; /** *

* {@link SequenceSplitter} instance used by the {@link MFCLogParser}. *

*/ private SequenceSplitter sequenceSplitter; /** *

* Collection of event sequences that is contained in the log file, which is * parsed. *

*/ private Collection> sequences; /** *

* Debugging variable that allows the analysis which message type occurs how * often in the log file. Can be used to enhance the message filter. *

*/ private SortedMap typeCounter; /** *

* Debugging variable that enables the counting of the occurrences of each * message. Used in combination with {@link #typeCounter}. *

*/ private boolean countMessageOccurences; /** *

* Constructor. Creates a new LogParser that does not count message * occurrences. *

*/ public MFCLogParser() { this(false); } /** *

* Constructor. Creates a new LogParser. *

* * @param countMessageOccurences * if true, the occurrences of each message type in the log is * counted. */ public MFCLogParser(boolean countMessageOccurences) { sequenceSplitter = new SequenceSplitter(); sequences = new LinkedList>(); currentHandler = null; this.countMessageOccurences = countMessageOccurences; if (countMessageOccurences) { typeCounter = new TreeMap(); } } /** *

* Returns the collection of event sequences that is obtained from parsing * log files. *

* * @return collection of event sequences */ public Collection> getSequences() { return sequences; } /* * (non-Javadoc) * * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, * java.lang.String, java.lang.String, org.xml.sax.Attributes) */ @Override public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException { if (qName.equals("session")) { Console.traceln("start of session"); sequenceSplitter = new SequenceSplitter(); } else if (qName.equals("msg")) { String msgType = atts.getValue("type"); int msgInt = -1; try { msgInt = Integer.parseInt(msgType); if (countMessageOccurences) { Integer currentCount = typeCounter.get(msgInt); if (currentCount == null) { typeCounter.put(msgInt, 1); } else { typeCounter.put(msgInt, currentCount + 1); } } if (msgInt == MessageDefs.WM_CREATE) { currentHandler = new HandlerCreate(); currentHandler.onStartElement(); } else if (msgInt == MessageDefs.WM_DESTROY) { currentHandler = new HandlerDestroy(); currentHandler.onStartElement(); } else if (msgInt == MessageDefs.WM_SETTEXT) { currentHandler = new HandlerSetText(); currentHandler.onStartElement(); } else { currentMessage = new WindowsMessage(msgInt); } } catch (NumberFormatException e) { Console.printerrln("Invalid message type: type not a number"); e.printStackTrace(); } } else if (qName.equals("param")) { if (currentHandler != null) { currentHandler.onParameter(atts.getValue("name"), atts.getValue("value")); } else { currentMessage.addParameter(atts.getValue("name"), atts.getValue("value")); } } } /* * (non-Javadoc) * * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, * java.lang.String, java.lang.String) */ @Override public void endElement(String uri, String localName, String qName) throws SAXException { if (qName.equals("msg")) { if (currentHandler != null) { currentHandler.onEndElement(); currentHandler = null; } else { try { currentMessage.setTarget(WindowTree.getInstance()); sequenceSplitter.addMessage(currentMessage); } catch (InvalidParameterException e) { Console.traceln(e.getMessage() + " WindowsMessage " + currentMessage + " ignored."); } } } else if (qName.equals("session")) { sequenceSplitter.endSession(); sequences.add(sequenceSplitter.getSequence()); Console.traceln("end of session"); } } /** *

* Parses a given log file created by the MFCMonitor and adds its contents * to the collection of event sequences. *

* * @param filename * name and path of the log file */ public void parseFile(String filename) { if (filename == null) { throw new InvalidParameterException("filename must not be null"); } SAXParserFactory spf = SAXParserFactory.newInstance(); spf.setValidating(true); SAXParser saxParser = null; InputSource inputSource = null; try { saxParser = spf.newSAXParser(); inputSource = new InputSource(new InputStreamReader( new FileInputStream(filename), "UTF-16")); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (ParserConfigurationException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } catch (FileNotFoundException e) { e.printStackTrace(); } if (inputSource != null) { inputSource.setSystemId("file://" + new File(filename).getAbsolutePath()); try { if (saxParser == null) { throw new RuntimeException("SAXParser creation failed"); } saxParser.parse(inputSource, this); } catch (SAXParseException e) { Console.printerrln("Failure parsing file in line " + e.getLineNumber() + ", column " + e.getColumnNumber() + "."); e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } if (countMessageOccurences) { Console.println("Message statistics:"); Console.println(typeCounter.toString() .replace(" ", StringTools.ENDLINE) .replaceAll("[\\{\\}]", "")); } } }