source: trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/AbstractDefaultLogParser.java @ 1093

Last change on this file since 1093 was 1093, checked in by pharms, 11 years ago
  • bugfix to correctly handle sessions without an included event
File size: 12.3 KB
Line 
1//   Copyright 2012 Georg-August-Universität Göttingen, Germany
2//
3//   Licensed under the Apache License, Version 2.0 (the "License");
4//   you may not use this file except in compliance with the License.
5//   You may obtain a copy of the License at
6//
7//       http://www.apache.org/licenses/LICENSE-2.0
8//
9//   Unless required by applicable law or agreed to in writing, software
10//   distributed under the License is distributed on an "AS IS" BASIS,
11//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//   See the License for the specific language governing permissions and
13//   limitations under the License.
14
15package de.ugoe.cs.autoquest.plugin.html;
16
17import java.io.File;
18import java.io.FileInputStream;
19import java.io.FileNotFoundException;
20import java.io.IOException;
21import java.io.InputStreamReader;
22import java.io.UnsupportedEncodingException;
23import java.util.Collection;
24import java.util.HashMap;
25import java.util.LinkedList;
26import java.util.List;
27import java.util.Map;
28
29import javax.xml.parsers.ParserConfigurationException;
30import javax.xml.parsers.SAXParser;
31import javax.xml.parsers.SAXParserFactory;
32
33import org.xml.sax.Attributes;
34import org.xml.sax.InputSource;
35import org.xml.sax.SAXException;
36import org.xml.sax.SAXParseException;
37import org.xml.sax.helpers.DefaultHandler;
38
39import de.ugoe.cs.autoquest.eventcore.Event;
40import de.ugoe.cs.autoquest.eventcore.guimodel.GUIElementTree;
41import de.ugoe.cs.autoquest.eventcore.guimodel.GUIModel;
42import de.ugoe.cs.util.console.Console;
43
44/**
45 * <p>
46 * This class provides the functionality to parse XML log files generated monitors of
47 * AutoQUEST. The result of parsing a file is a collection of event sequences and a GUI model.
48 * This class must be extended by implementing a subclass and the abstract method to complete
49 * the implementation.
50 * </p>
51 *
52 * @author Patrick Harms
53 * @version 1.0
54 *
55 */
56public abstract class AbstractDefaultLogParser extends DefaultHandler {
57   
58    /**
59     * <p>
60     * Collection of event sequences that is contained in the parsed log file.
61     * </p>
62     */
63    private Collection<List<Event>> sequences;
64
65    /**
66     * <p>
67     * Internal handle to the parsed GUI structure, stored in a GUIElementTree
68     * </p>
69     */
70    private GUIElementTree<String> guiElementTree;
71
72    /**
73     * <p>
74     * Id of the GUI element currently being parsed.
75     * </p>
76     */
77    private String currentGUIElementId;
78
79    /**
80     * <p>
81     * the buffer for GUI elements already parsed but not processed yet (because e.g. the parent
82     * GUI element has not been parsed yet)
83     * </p>
84     */
85    private List<BufferEntry> guiElementBuffer;
86
87    /**
88     * <p>
89     * Internal handle to type of the event currently being parsed.
90     * </p>
91     */
92    private String currentEventType;
93
94    /**
95     * <p>
96     * the buffer for events already parsed but not processed yet (because e.g. the target
97     * GUI element has not been parsed yet)
98     * </p>
99     */
100    private List<BufferEntry> eventBuffer;
101
102    /**
103     * <p>
104     * Internal handle to the parameters of the event currently being entity.
105     * </p>
106     */
107    private Map<String, String> currentParameters;
108
109    /**
110     * <p>
111     * Internal handle to the sequence currently being parsed.
112     * </p>
113     */
114    private List<Event> currentSequence;
115
116    /**
117     * <p>
118     * Constructor. Creates a new logParser.
119     * </p>
120     */
121    public AbstractDefaultLogParser() {
122        sequences = new LinkedList<List<Event>>();
123        guiElementTree = new GUIElementTree<String>();
124        guiElementBuffer = new LinkedList<BufferEntry>();
125        eventBuffer = new LinkedList<BufferEntry>();
126        currentSequence = new LinkedList<Event>();
127    }
128
129    /**
130     * <p>
131     * Parses a log file written by the HTMLMonitor and creates a collection of event sequences.
132     * </p>
133     *
134     * @param filename
135     *            name and path of the log file
136     */
137    public void parseFile(String filename) {
138        if (filename == null) {
139            throw new IllegalArgumentException("filename must not be null");
140        }
141
142        parseFile(new File(filename));
143    }
144
145    /**
146     * <p>
147     * Parses a log file written by the HTMLMonitor and creates a collection of event sequences.
148     * </p>
149     *
150     * @param file
151     *            file to be parsed
152     */
153    public void parseFile(File file) {
154        if (file == null) {
155            throw new IllegalArgumentException("file must not be null");
156        }
157        SAXParserFactory spf = SAXParserFactory.newInstance();
158        spf.setValidating(true);
159        SAXParser saxParser = null;
160        InputSource inputSource = null;
161        try {
162            saxParser = spf.newSAXParser();
163            inputSource =
164                new InputSource(new InputStreamReader(new FileInputStream(file), "UTF-8"));
165        }
166        catch (UnsupportedEncodingException e) {
167            Console.printerrln("Error parsing file " + file.getName());
168            Console.logException(e);
169            return;
170        }
171        catch (ParserConfigurationException e) {
172            Console.printerrln("Error parsing file " + file.getName());
173            Console.logException(e);
174            return;
175        }
176        catch (SAXException e) {
177            Console.printerrln("Error parsing file " + file.getName());
178            Console.logException(e);
179        }
180        catch (FileNotFoundException e) {
181            Console.printerrln("Error parsing file " + file.getName());
182            Console.logException(e);
183        }
184        if (inputSource != null) {
185            inputSource.setSystemId("file://" + file.getAbsolutePath());
186            try {
187                if (saxParser == null) {
188                    throw new RuntimeException("SaxParser creation failed");
189                }
190                saxParser.parse(inputSource, this);
191            }
192            catch (SAXParseException e) {
193                Console.printerrln("Failure parsing file in line " + e.getLineNumber() +
194                    ", column " + e.getColumnNumber() + ".");
195                Console.logException(e);
196            }
197            catch (SAXException e) {
198                Console.printerrln("Error parsing file " + file.getName());
199                Console.logException(e);
200                return;
201            }
202            catch (IOException e) {
203                Console.printerrln("Error parsing file " + file.getName());
204                Console.logException(e);
205                return;
206            }
207        }
208    }
209
210    /**
211     * <p>
212     * Returns a collection of event sequences that was obtained from parsing log files.
213     * </p>
214     *
215     * @return
216     */
217    public Collection<List<Event>> getSequences() {
218        return sequences;
219    }
220
221    /**
222     * <p>
223     * Returns the GUI model that is obtained from parsing log files.
224     * </p>
225     *
226     * @return GUIModel
227     */
228    public GUIModel getGuiModel() {
229        return guiElementTree.getGUIModel();
230    }
231
232    /*
233     * (non-Javadoc)
234     *
235     * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String,
236     * java.lang.String, org.xml.sax.Attributes)
237     */
238    @Override
239    public void startElement(String uri, String localName, String qName, Attributes atts)
240        throws SAXException
241    {
242        if (qName.equals("session")) {
243            // do nothing
244        }
245        else if (qName.equals("component")) {
246            currentGUIElementId = atts.getValue("id");
247            currentParameters = new HashMap<String, String>();
248        }
249        else if (qName.equals("event")) {
250            currentEventType = atts.getValue("type");
251            currentParameters = new HashMap<String, String>();
252        }
253        else if (qName.equals("param")) {
254            String paramName = atts.getValue("name");
255            if ((currentGUIElementId != null) || (currentEventType != null)) {
256                currentParameters.put(paramName, atts.getValue("value"));
257            }
258            else {
259                throw new SAXException("param tag found where it should not be.");
260            }
261        }
262        else {
263            throw new SAXException("unknown tag found: " + qName);
264        }
265
266    }
267
268    /*
269     * (non-Javadoc)
270     *
271     * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String,
272     * java.lang.String)
273     */
274    @Override
275    public void endElement(String uri, String localName, String qName) throws SAXException {
276        if (qName.equals("session") && (eventBuffer != null)) {
277            eventBuffer.add(new BufferEntry("sessionSwitch", null));
278            processEvents();
279        }
280        else if (qName.equals("component") && (currentGUIElementId != null)) {
281            guiElementBuffer.add(new BufferEntry(currentGUIElementId, currentParameters));
282
283            processGUIElements();
284
285            currentGUIElementId = null;
286            currentParameters = null;
287        }
288        else if (qName.equals("event") && (currentEventType != null)) {
289            eventBuffer.add(new BufferEntry(currentEventType, currentParameters));
290
291            processEvents();
292
293            currentEventType = null;
294            currentParameters = null;
295        }
296    }
297
298    /**
299     * <p>
300     * TODO: comment
301     * </p>
302     *
303     * @param id
304     * @param parameters
305     * @return
306     */
307    protected abstract boolean handleGUIElement(String id, Map<String, String> parameters)
308        throws SAXException;
309   
310    /**
311     * <p>
312     * TODO: comment
313     * </p>
314     *
315     * @param id
316     * @param parameters
317     * @return
318     */
319    protected abstract boolean handleEvent(String type, Map<String, String> parameters)
320        throws SAXException;
321   
322    /**
323     * <p>
324     * TODO: comment
325     * </p>
326     *
327     * @return
328     */
329    protected GUIElementTree<String> getGUIElementTree() {
330        return guiElementTree;
331    }
332
333    /**
334     * <p>
335     * TODO: comment
336     * </p>
337     *
338     * @param event
339     */
340    protected void addToSequence(Event event) {
341        currentSequence.add(event);
342    }
343
344    /**
345     * <p>
346     * TODO: comment
347     * </p>
348     *
349     */
350    private void processGUIElements() throws SAXException {
351        int processedElements = 0;
352        boolean processedElement;
353       
354        do {
355            processedElement = false;
356            // search for the next GUI element that can be processed
357            for (int i = 0; i < guiElementBuffer.size(); i++) {
358                BufferEntry entry = guiElementBuffer.get(i);
359                processedElement = handleGUIElement(entry.id, entry.parameters);
360                if (processedElement) {
361                    guiElementBuffer.remove(i);
362                    processedElements++;
363                    break;
364                }
365            }
366        }
367        while (processedElement);
368       
369        if (processedElements > 0) {
370            processEvents();
371        }
372    }
373
374    /**
375     * <p>
376     * TODO: comment
377     * </p>
378     *
379     */
380    private void processEvents() throws SAXException {
381        boolean processedEvent;
382       
383        do {
384            processedEvent = false;
385            // check, if the next event can be processed
386            if (eventBuffer.size() > 0) {
387                BufferEntry entry = eventBuffer.get(0);
388               
389                if ((entry != null) && (entry.id != null) && (entry.parameters != null)) {
390                    processedEvent = handleEvent(entry.id, entry.parameters);
391                    if (processedEvent) {
392                        eventBuffer.remove(0);
393                    }
394                }
395                else {
396                    // the entry signals a session switch. Close the current session and start the
397                    // next one
398                    if (currentSequence.size() > 0) {
399                        sequences.add(currentSequence);
400                        currentSequence = new LinkedList<Event>();
401                    }
402                    eventBuffer.remove(0);
403                    processedEvent = true;
404                }
405            }
406        }
407        while (processedEvent);
408    }
409
410    /**
411     * <p>
412     * TODO document
413     * </p>
414     */
415    private static class BufferEntry {
416       
417        /** */
418        private String id;
419       
420        /** */
421        private Map<String, String> parameters;
422       
423        /**
424         *
425         */
426        private BufferEntry(String id, Map<String, String> parameters) {
427            this.id = id;
428            this.parameters = parameters;
429        }
430    }
431
432}
Note: See TracBrowser for help on using the repository browser.