// Copyright 2012 Georg-August-Universität Göttingen, Germany // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package de.ugoe.cs.autoquest.plugin.mfc; 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.util.Collection; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; import java.util.logging.Level; 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.autoquest.eventcore.Event; import de.ugoe.cs.autoquest.eventcore.guimodel.GUIElementTree; import de.ugoe.cs.autoquest.eventcore.guimodel.GUIModel; import de.ugoe.cs.autoquest.plugin.mfc.eventcore.WindowsMessage; import de.ugoe.cs.autoquest.plugin.mfc.eventcore.WindowsMessageType; import de.ugoe.cs.autoquest.plugin.mfc.guimodel.MFCGUIElement; 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 * @author Fabian Glaser * @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; /** ** internal handle to the GUI element tree *
*/ private GUIElementTree* the type of the currently parsed message *
*/ private WindowsMessageType currentMessageType; /** ** the parameters of the currently parsed message *
*/ private Map* {@link SequenceSplitter} instance used by the {@link MFCLogParser}. *
*/ private SequenceSplitter sequenceSplitter; /** ** Collection of message sequences that is contained in the log file, which is parsed. *
*/ private Collection* 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* 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) { sequences = new LinkedList* Parses a log file written by the MFCMonitor and creates a collection of event sequences. *
* * @param filename * name and path of the log file */ public void parseFile(String filename) { if (filename == null) { throw new IllegalArgumentException("filename must not be null"); } parseFile(new File(filename)); } /** ** Parses a log file written by the MFCMonitor and creates a collection of event sequences. *
* * @param file * name and path of the log file */ public void parseFile(File file) { if (file == null) { throw new IllegalArgumentException("file 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(file), "UTF-8")); } catch (UnsupportedEncodingException e) { Console.printerr("Error parsing file " + file.getName()); Console.logException(e); } catch (ParserConfigurationException e) { Console.printerr("Error parsing file " + file.getName()); Console.logException(e); } catch (SAXException e) { Console.printerr("Error parsing file " + file.getName()); Console.logException(e); } catch (FileNotFoundException e) { Console.printerr("Error parsing file " + file.getName()); Console.logException(e); } if (inputSource != null) { inputSource.setSystemId("file://" + file.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() + "."); Console.logException(e); } catch (SAXException e) { Console.printerr("Error parsing file " + file.getName()); Console.logException(e); } catch (IOException e) { Console.printerr("Error parsing file " + file.getName()); Console.logException(e); } } if (countMessageOccurences) { Console.println("Message statistics:"); Console.println (typeCounter.toString().replace(" ", StringTools.ENDLINE).replaceAll("[\\{\\}]", "")); } } /** ** Returns the collection of event sequences that is obtained from parsing log files. *
* * @return collection of event sequences */ public Collection* Returns the GUI model that is obtained from parsing log files. *
* * @return collection of event sequences */ public GUIModel getGuiModel() { if( guiElementTree!=null ) { return guiElementTree.getGUIModel(); } else { return null; } } /* * (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(Level.FINE, "start of session"); // in some logs, the session end may be marked in between the log. This is because // of thread problems. So instead of creating a new GUI model, preserve it. if (guiElementTree == null) { guiElementTree = new GUIElementTree