// 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.IEventType; import de.ugoe.cs.autoquest.eventcore.guimodel.GUIElementTree; import de.ugoe.cs.autoquest.eventcore.guimodel.GUIModel; import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement; import de.ugoe.cs.autoquest.plugin.html.eventcore.HTMLEventTypeFactory; import de.ugoe.cs.autoquest.plugin.html.guimodel.HTMLGUIElement; import de.ugoe.cs.autoquest.plugin.html.guimodel.HTMLGUIElementSpec; import de.ugoe.cs.autoquest.plugin.html.guimodel.HTMLPageElementSpec; import de.ugoe.cs.autoquest.plugin.html.guimodel.HTMLPageSpec; import de.ugoe.cs.autoquest.plugin.html.guimodel.HTMLServerSpec; import de.ugoe.cs.util.console.Console; /** *

* This class provides the functionality to parse XML log files generated by the HTMLMonitor of * autoquest. The result of parsing a file is a collection of event sequences. *

* * @author Fabian Glaser * @version 1.0 * */ public class HTMLLogParser extends DefaultHandler { /** *

* Constructor. Creates a new HTMLLogParser. *

*/ public HTMLLogParser() { sequences = new LinkedList>(); } /** *

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

*/ private Collection> sequences; /** *

* Internal handle to the parsed GUI structure, stored in a GUIElementTree *

*/ private GUIElementTree currentGUIElementTree; /** *

* Path of the GUI element currently being parsed. *

*/ private String currentGUIElementPath; /** *

* Path of the parent of the GUI element currently being parsed. *

*/ private String currentParentPath; /** *

* Source of the GUI element currently being parsed. *

*/ private String currentEventSource; /** *

* Timestamp of the event currently being parsed. *

*/ private Long currentEventTimestamp; /** *

* Internal handle to the parameters of the event currently being parsed. *

*/ private Map currentEventParameters; /** *

* Internal handle to the parameters of the GUI element currently being parsed. *

*/ private Map currentGUIElementParameters; /** *

* Internal handle to the sequence currently being parsed. *

*/ private List currentSequence; /** *

* Internal handle to type of the event currently being parsed. *

*/ private String currentEventType; /** *

* Class of the GUI element currently being parsed. *

*/ private String currentGUIElementClass; /** *

* Index of the GUI element currently being parsed. *

*/ private String currentGUIElementIndex; /** *

* internal handle to the GUI element of the previous event to be potentially reused for the * current *

*/ private IGUIElement lastGUIElement; /** *

* internal handle to the server specification currently being used. *

*/ private HTMLServerSpec currentServerSpec; /** *

* 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.printerr("Error parsing file " + file.getName()); Console.logException(e); return; } catch (ParserConfigurationException e) { Console.printerr("Error parsing file " + file.getName()); Console.logException(e); return; } 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); return; } catch (IOException e) { Console.printerr("Error parsing file " + file.getName()); Console.logException(e); return; } } } /* * (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")) { currentSequence = new LinkedList(); if (currentGUIElementTree == null) currentGUIElementTree = new GUIElementTree(); } else if (qName.equals("component")) { currentGUIElementPath = atts.getValue("path"); currentGUIElementParameters = new HashMap(); } else if (qName.equals("event")) { currentEventType = atts.getValue("type"); currentEventParameters = new HashMap(); } else if (qName.equals("param")) { String paramName = atts.getValue("name"); if (currentGUIElementPath != null) { if ("parent".equals(paramName)) { currentParentPath = atts.getValue("value"); } if ("class".equals(paramName)) { currentGUIElementClass = atts.getValue("value"); } if ("index".equals(paramName)) { currentGUIElementIndex = atts.getValue("value"); } currentGUIElementParameters.put(paramName, atts.getValue("value")); } else if (currentEventType != null) { if ("target".equals(paramName)) { currentEventSource = atts.getValue("value"); } if ("timestamp".equals(paramName)) { currentEventTimestamp = Long.parseLong(atts.getValue("value")); } currentEventParameters.put(paramName, atts.getValue("value")); } else { throw new SAXException("param tag found where it should not be."); } } else { throw new SAXException("unknown tag found: " + qName); } } /* * (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("session")) { if (currentSequence != null && !currentSequence.isEmpty()) { sequences.add(currentSequence); } currentSequence = null; } else if (qName.equals("component") && currentGUIElementPath != null) { HTMLGUIElementSpec guiElementSpec = getGUIElementSpec(currentGUIElementClass, currentGUIElementParameters); currentGUIElementTree.add(currentGUIElementPath, currentParentPath, guiElementSpec); currentParentPath = null; currentGUIElementPath = null; currentGUIElementParameters = null; } else if (qName.equals("event")) { IGUIElement currentGUIElement; currentGUIElement = currentGUIElementTree.find(currentEventSource); IEventType eventType = HTMLEventTypeFactory.getInstance().getEventType(currentEventType, currentEventParameters, currentGUIElement); Event event = new Event(eventType, (currentGUIElement == null ? lastGUIElement : currentGUIElement)); event.setTimestamp(currentEventTimestamp); HTMLGUIElement currentEventTarget = (HTMLGUIElement) event.getTarget(); currentEventTarget.markUsed(); currentSequence.add(event); currentEventSource = null; currentEventTimestamp = -1l; currentEventParameters = null; currentEventType = null; if (currentGUIElement != null) { lastGUIElement = currentGUIElement; } currentGUIElement = null; } } /** *

* Returns a collection of event sequences that was obtained from parsing log files. *

* * @return */ public Collection> getSequences() { return sequences; } /** *

* Returns the GUI model that is obtained from parsing log files. *

* * @return GUIModel */ public GUIModel getGuiModel() { return currentGUIElementTree.getGUIModel(); } /** * Returns the HTMLGUIElementSpecification for a GUI Element described * by its class name and its parameters. * @param guiElementClass * @param guiElementParameters * @return */ private HTMLGUIElementSpec getGUIElementSpec(String guiElementClass, Map guiElementParameters) { HTMLGUIElementSpec specification = null; if ("server".equals(guiElementClass)) { // TODO: add correct port handling specification = new HTMLServerSpec(guiElementParameters.get("htmlId"), 0); currentServerSpec = (HTMLServerSpec) specification; } else { String id = guiElementParameters.get("htmlId"); if (id == null) { HTMLPageElementSpec parentSpec = (HTMLPageElementSpec) currentGUIElementTree.find(currentParentPath) .getSpecification(); id = parentSpec.getPage().getPagePath(); } int index = -1; String indexStr = guiElementParameters.get("index"); if ((indexStr != null) && (!"".equals(indexStr))) { index = Integer.parseInt(indexStr); } String title = guiElementParameters.get("title"); HTMLPageSpec page = new HTMLPageSpec(currentServerSpec, id, title); specification = new HTMLPageElementSpec(page, guiElementClass, id, index); } return specification; } }