// 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.html; 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 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.util.console.Console; /** *
* This class provides the functionality to parse XML log files generated monitors of * AutoQUEST. The result of parsing a file is a collection of event sequences and a GUI model. * This class must be extended by implementing a subclass and the abstract method to complete * the implementation. *
* * @author Patrick Harms * @version 1.0 * */ public abstract class AbstractDefaultLogParser extends DefaultHandler { /** ** Collection of event sequences that is contained in the parsed log file. *
*/ private Collection* Internal handle to the parsed GUI structure, stored in a GUIElementTree *
*/ private GUIElementTree* Id of the GUI element currently being parsed. *
*/ private String currentGUIElementId; /** ** the buffer for GUI elements already parsed but not processed yet (because e.g. the parent * GUI element has not been parsed yet) *
*/ private List* Internal handle to type of the event currently being parsed. *
*/ private String currentEventType; /** ** the buffer for events already parsed but not processed yet (because e.g. the target * GUI element has not been parsed yet) *
*/ private List* Internal handle to the parameters of the event currently being entity. *
*/ private Map* Internal handle to the sequence currently being parsed. *
*/ private List* Constructor. Creates a new logParser. *
*/ public AbstractDefaultLogParser() { sequences = new LinkedList* Parses a log file written by the HTMLMonitor 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 HTMLMonitor and creates a collection of event sequences. *
* * @param file * file to be parsed */ 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.printerrln("Error parsing file " + file.getName()); Console.logException(e); return; } catch (ParserConfigurationException e) { Console.printerrln("Error parsing file " + file.getName()); Console.logException(e); return; } catch (SAXException e) { Console.printerrln("Error parsing file " + file.getName()); Console.logException(e); } catch (FileNotFoundException e) { Console.printerrln("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.printerrln("Error parsing file " + file.getName()); Console.logException(e); return; } catch (IOException e) { Console.printerrln("Error parsing file " + file.getName()); Console.logException(e); return; } } } /** ** Returns a collection of event sequences that was obtained from parsing log files. *
* * @return */ public Collection* Returns the GUI model that is obtained from parsing log files. *
* * @return GUIModel */ public GUIModel getGuiModel() { return guiElementTree.getGUIModel(); } /* * (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")) { // do nothing } else if (qName.equals("component")) { currentGUIElementId = atts.getValue("id"); currentParameters = new HashMap* TODO: comment *
* * @param id * @param parameters * @return */ protected abstract boolean handleGUIElement(String id, Map* TODO: comment *
* * @param id * @param parameters * @return */ protected abstract boolean handleEvent(String type, Map* TODO: comment *
* * @return */ protected GUIElementTree* TODO: comment *
* * @param event */ protected void addToSequence(Event event) { currentSequence.add(event); } /** ** TODO: comment *
* */ private void processGUIElements() throws SAXException { int processedElements = 0; boolean processedElement; do { processedElement = false; // search for the next GUI element that can be processed for (int i = 0; i < guiElementBuffer.size(); i++) { BufferEntry entry = guiElementBuffer.get(i); processedElement = handleGUIElement(entry.id, entry.parameters); if (processedElement) { guiElementBuffer.remove(i); processedElements++; break; } } } while (processedElement); if (processedElements > 0) { processEvents(); } } /** ** TODO: comment *
* */ private void processEvents() throws SAXException { boolean processedEvent; do { processedEvent = false; // check, if the next event can be processed if (eventBuffer.size() > 0) { BufferEntry entry = eventBuffer.get(0); if ((entry != null) && (entry.id != null) && (entry.parameters != null)) { processedEvent = handleEvent(entry.id, entry.parameters); if (processedEvent) { eventBuffer.remove(0); } } else { // the entry signals a session switch. Close the current session and start the // next one if (currentSequence.size() > 0) { sequences.add(currentSequence); currentSequence = new LinkedList* TODO document *
*/ private static class BufferEntry { /** */ private String id; /** */ private Map