package de.ugoe.cs.autoquest.plugin.jfc; import java.awt.event.MouseEvent; 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.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.logging.Level; import java.util.regex.Matcher; import java.util.regex.Pattern; 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.gui.IInteraction; import de.ugoe.cs.autoquest.eventcore.gui.KeyPressed; import de.ugoe.cs.autoquest.eventcore.gui.KeyReleased; import de.ugoe.cs.autoquest.eventcore.gui.KeyboardFocusChange; import de.ugoe.cs.autoquest.eventcore.gui.MouseButtonDown; import de.ugoe.cs.autoquest.eventcore.gui.MouseButtonInteraction; import de.ugoe.cs.autoquest.eventcore.gui.MouseButtonUp; import de.ugoe.cs.autoquest.eventcore.gui.MouseClick; import de.ugoe.cs.autoquest.eventcore.guimodel.GUIModel; import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement; import de.ugoe.cs.autoquest.keyboardmaps.VirtualKey; import de.ugoe.cs.autoquest.plugin.jfc.eventcore.JFCEventId; import de.ugoe.cs.autoquest.plugin.jfc.guimodel.JFCComponentTree; import de.ugoe.cs.autoquest.plugin.jfc.guimodel.JFCGUIElement; import de.ugoe.cs.autoquest.plugin.jfc.guimodel.JFCGUIElementSpec; import de.ugoe.cs.util.console.Console; /** *
* This class provides functionality to parse XML log files generated by the JFCMonitor of * autoquest. The result of parsing a file is a collection of event sequences. *
* * @author Fabian Glaser * @author Steffen Herbold * @version 1.0 */ public class JFCSimplifiedLogParser extends DefaultHandler { /** ** Collection of event sequences that is contained in the log file, which is parsed. *
*/ private Collection* Internal handle to the id of the event that is currently being parsed. *
*/ private JFCEventId currentEventId; /** * ** Internal handle to the hashcode of the component, that is currently parsed. *
*/ private Integer currentComponentHash; /** * ** Internal handle to the hashcode of the parent of the component, that is currently parsed. *
*/ private Integer currentParentHash; /** ** Internal handle to the parameters of the event that is currently being parsed. *
*/ private Integer currentEventSource; /** ** Internal handle to the parameters of the event currently being parsed. *
*/ private Map* Internal handle to the event sequence that is currently being parsed. *
*/ private List* internal handle to the parameters currently parsed for a component *
*/ private JFCGUIElementSpec currentGuiElementSpec; /** ** internal handle to the parsed gui structure, stored in a JFCComponentTree *
*/ private JFCComponentTree currentComponentTree; /** ** internal handle to the component of the previous event to be potentially reused for the * current *
*/ private IGUIElement lastGUIElement; /** ** internal handle to the class ancestors *
*/ private List* this is used to check, if for every pressed key, there is a release of it *
*/ private List* a specification for event ids to be omitted by the parser *
*/ private Collection* Constructor. Creates a new JFCLogParser with a default event filter. This ignores focus * events, mouse pressed, and mouse released events. *
*/ public JFCSimplifiedLogParser() { sequences = new LinkedList
* Constructor. Creates a new JFCLogParser with a specific event filter. The events in the
* provided collection are ignored by the parser. As events, the constants of the different
* event classes must be used. E.g. creating a collection and putting
* MouseEvent.MOUSE_PRESSED
will cause the parser to ignore all mouse pressed
* events. If the provided collection is null, no event is ignored.
*
* Parses a log file written by the JFCMonitor 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 JFCMonitor 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); 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); return; } catch (FileNotFoundException e) { Console.printerr("Error parsing file + " + file.getName()); Console.logException(e); return; } 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); return; } 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; } } } /** ** 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 GUIModel */ public GUIModel getGuiModel() { return currentComponentTree.getGUIModel(); } /* * (non-Javadoc) * * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String, * java.lang.String, org.xml.sax.Attributes) */ public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException{ if (qName.equals("sessions")) { currentSequence = new LinkedList* depending on the event id and the event parameters, this method instantiates the concrete * interaction, that took place, i.e. the event type *
* * @param eventId * the id of the event * @param eventParameters * the parameters provided for the event * * @return as described * * @throws SAXException thrown if the provided event id is unknown */ private IInteraction instantiateInteraction(JFCEventId eventId, Map* handles a mouse interaction. The method determines based on the event id and the parameters * which mouse button is pressed, released or clicked. *
* * @param eventId * the id of the event * @param eventParameters * the parameters provided for the event * * @return as described * * @throws SAXException thrown if the provided event id or button index is unknown */ private IInteraction handleMouseAction(JFCEventId eventId, Map* handles a keyboard interaction. The method determines based on the event id and the * parameters which key on the keyboard is pressed or released. It further checks, if for * every released key there is also a pressed event *
* * @param eventId * the id of the event * @param eventParameters * the parameters provided for the event * * @return as described * * @throws SAXException thrown if the provided event id is unknown or if there is a key * release without a preceding press of the same key */ private IInteraction handleKeyAction(JFCEventId eventId, Map* handles explicit keyboard focus changes. *
* * @param eventId * the id of the event * @param eventParameters * the parameters provided for the event * * @return as described * * @throws SAXException thrown if the provided event id is unknown */ private IInteraction handleNewFocus(JFCEventId eventId, Map
* for some events in the log file, no component specification is provided. In this case the
* GUI element on which the event is executed must be determined based on the
* toString
parameter of the event. This is achieved through this method. The
* toString
parameter does not always carry sufficient information for the GUI
* elements. For example the title is not necessarily provided. Therefore some of this
* information is generated.
*
toString
parameter of the event to be parsed for the GUI element
*
* @return the appropriate GUI Element
*
* @throws SAXException thrown if the provided value of the toString
parameter
* can not be parsed
*/
private void getGUIElementSpecFromToString(String toStringValue)
throws SAXException
{
try
{
// match the following: * creates a default event filter that ignores focus changes, mouse pressed and mouse released * events. *
*/ /*private void setupDefaultEventFilter() { eventFilter = new HashSet