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

Last change on this file since 1232 was 1232, checked in by pharms, 11 years ago
  • added some documentation
  • corrected handling of unparseable file during compression
  • Property svn:mime-type set to text/plain
File size: 10.5 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.util.List;
18import java.util.Map;
19import java.util.regex.Matcher;
20import java.util.regex.Pattern;
21
22import org.xml.sax.SAXException;
23
24import de.ugoe.cs.autoquest.eventcore.Event;
25import de.ugoe.cs.autoquest.eventcore.IEventType;
26import de.ugoe.cs.autoquest.eventcore.guimodel.GUIModel;
27import de.ugoe.cs.autoquest.eventcore.guimodel.GUIModelException;
28import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement;
29import de.ugoe.cs.autoquest.plugin.html.eventcore.HTMLEventTypeFactory;
30import de.ugoe.cs.autoquest.plugin.html.guimodel.HTMLDocumentSpec;
31import de.ugoe.cs.autoquest.plugin.html.guimodel.HTMLGUIElement;
32import de.ugoe.cs.autoquest.plugin.html.guimodel.HTMLGUIElementSpec;
33import de.ugoe.cs.autoquest.plugin.html.guimodel.HTMLPageElementSpec;
34import de.ugoe.cs.autoquest.plugin.html.guimodel.HTMLServerSpec;
35
36/**
37 * <p>
38 * This class provides the functionality to parse XML log files generated by the HTMLMonitor of
39 * AutoQUEST. The result of parsing a file is a collection of event sequences and a GUI model
40 * </p>
41 *
42 * @author Fabian Glaser, Patrick Harms
43 * @version 1.0
44 *
45 */
46public class HTMLLogParser extends AbstractDefaultLogParser {
47   
48    /**
49     * <p>
50     * the pattern used for parsing HTML GUI element paths
51     * </p>
52     */
53    private Pattern htmlElementPattern =
54        Pattern.compile("(\\w+)(\\[(\\d+)\\]|\\(htmlId=([\\w-]+)\\))");
55
56    /* (non-Javadoc)
57     * @see de.ugoe.cs.autoquest.plugin.html.AbstractDefaultLogParser#handleGUIElement(String, Map)
58     */
59    @Override
60    protected boolean handleGUIElement(String id, Map<String, String> parameters)
61        throws SAXException
62    {
63        HTMLGUIElementSpec specification = null;
64       
65        String parentId = parameters.get("parent");
66        IGUIElement parent = super.getGUIElementTree().find(parentId);
67
68        if (parameters.containsKey("host")) {
69            // this is a server specification
70            int port = 80;
71            String portStr = parameters.get(port);
72           
73            if (portStr != null) {
74                port = Integer.parseInt(portStr);
75            }
76           
77            specification = new HTMLServerSpec(parameters.get("host"), port);
78        }
79        else if (parameters.containsKey("path")) {
80            // this is a document specification
81           
82            if (parent != null) {
83                if (!(parent.getSpecification() instanceof HTMLServerSpec)) {
84                    throw new SAXException
85                        ("invalid log: parent GUI element of a document is not of type server");
86                }
87               
88                specification = new HTMLDocumentSpec
89                    ((HTMLServerSpec) parent.getSpecification(), parameters.get("path"),
90                     parameters.get("query"), parameters.get("title"));
91            }
92            else if (parentId == null) {
93                throw new SAXException("invalid log: a document has no parent id");
94            }
95        }
96        else if (parameters.containsKey("tagname")) {
97            String tagName = parameters.get("tagname");
98           
99            if (!tagNameMustBeConsidered(tagName)) {
100                return true;
101            }
102
103            if (parent != null) {
104                IGUIElement document = parent;
105               
106                while ((document != null) &&
107                       (!(document.getSpecification() instanceof HTMLDocumentSpec)))
108                {
109                    document = document.getParent();
110                }
111               
112                if (document == null) {
113                    throw new SAXException
114                        ("invalid log: parent hierarchy of a page element does not contain a " +
115                         "document");
116                }
117               
118                int index = -1;
119                String indexStr = parameters.get("index");
120
121                if ((indexStr != null) && (!"".equals(indexStr))) {
122                    index = Integer.parseInt(indexStr);
123                }
124
125                specification = new HTMLPageElementSpec
126                    ((HTMLDocumentSpec) document.getSpecification(), tagName,
127                     parameters.get("htmlid"), index);
128            }
129            else if (parentId == null) {
130                throw new SAXException("invalid log: a page element has no parent id");
131            }
132        }
133        else {
134            throw new SAXException("invalid log: unknown GUI element");
135        }
136
137        if (specification != null) {
138            try {
139                super.getGUIElementTree().add(id, parentId, specification);
140            }
141            catch (GUIModelException e) {
142                throw new SAXException("could not handle GUI element with id " +
143                                       id + ": " + e.getMessage(), e);
144            }
145            return true;
146        }
147        else {
148            return false;
149        }
150    }
151
152    /* (non-Javadoc)
153     * @see de.ugoe.cs.autoquest.plugin.html.AbstractDefaultLogParser#handleEvent(String, Map)
154     */
155    @Override
156    protected boolean handleEvent(String type, Map<String, String> parameters) throws SAXException {
157        String targetId = parameters.get("target");
158       
159        if (targetId == null) {
160            String targetDocument = parameters.get("targetDocument");
161            String targetDOMPath = parameters.get("targetDOMPath");
162           
163            if ((targetDocument == null) || (targetDOMPath == null)) {
164                throw new SAXException("event has no target defined");
165            }
166           
167            targetId = determineTargetId(targetDocument, targetDOMPath);
168           
169            if (targetId == null) {
170                // the target id can not be determined yet
171                return false;
172            }
173        }
174       
175        IGUIElement target = super.getGUIElementTree().find(targetId);
176       
177        if (target == null) {
178            // event not processible yet
179            return false;
180        }
181
182        IEventType eventType =
183            HTMLEventTypeFactory.getInstance().getEventType(type, parameters, target);
184       
185        if (eventType != null) {
186            Event event = new Event(eventType, target);
187
188            String timestampStr = parameters.get("timestamp");
189       
190            if (timestampStr != null) {
191                event.setTimestamp(Long.parseLong(timestampStr));
192            }
193
194            ((HTMLGUIElement) event.getTarget()).markUsed();
195       
196            super.addToSequence(event);
197        }
198        // else ignore unknown event type
199
200        return true;
201    }
202
203    /**
204     * <p>
205     * used to determine the id of a target denoted by an event. This is only required for older
206     * document formats. The new formats use concrete ids.
207     * </p>
208     */
209    private String determineTargetId(String targetDocument, String targetDOMPath)
210        throws SAXException
211    {
212        IGUIElement document = super.getGUIElementTree().find(targetDocument);
213       
214        if (document == null) {
215            return null;
216        }
217       
218        if (!(document.getSpecification() instanceof HTMLDocumentSpec)) {
219            throw new SAXException("an id that should refer to an HTML document refers to" +
220                                   "something else");
221        }
222       
223        GUIModel model = super.getGUIElementTree().getGUIModel();
224        IGUIElement child = document;
225        String[] pathElements = targetDOMPath.split("/");
226        int pathIndex = 0;
227       
228        HTMLPageElementSpec compareSpec;
229        String tagName;
230        int index;
231        String htmlId;
232       
233        while ((pathIndex < pathElements.length) && (child != null)) {
234            if ((pathElements[pathIndex] != null) && (!"".equals(pathElements[pathIndex]))) {           
235                Matcher matcher = htmlElementPattern.matcher(pathElements[pathIndex]);
236                if (!matcher.matches()) {
237                    throw new SAXException
238                        ("could not parse target DOM path element " + pathElements[pathIndex]);
239                }
240
241                tagName = matcher.group(1);
242                String indexStr = matcher.group(3);
243                htmlId = matcher.group(4);
244
245                index = -1;
246                if ((indexStr != null) && (!"".equals(indexStr))) {
247                    index = Integer.parseInt(indexStr);
248                }
249
250                compareSpec = new HTMLPageElementSpec
251                    ((HTMLDocumentSpec) document.getSpecification(), tagName, htmlId, index);
252
253                List<IGUIElement> children = model.getChildren(child);
254                child = null;
255
256                for (IGUIElement candidate : children) {
257                    if (compareSpec.getSimilarity(candidate.getSpecification())) {
258                        child = candidate;
259                        break;
260                    }
261                }
262            }
263           
264            pathIndex++;
265        }
266       
267        if (child != null) {
268            return super.getGUIElementTree().find(child);
269        }
270        else {
271            return null;
272        }
273    }
274
275    /**
276     * <p>
277     * checks if tags with the provided name must be handled in the GUI model. As an example,
278     * it is not necessary to handle "head" tags and anything included in them.
279     * </p>
280     *
281     * @param tagName the tag name to check
282     *
283     * @return true, if the tag must be considered, false else
284     */
285    private boolean tagNameMustBeConsidered(String tagName) {
286        return
287            !"head".equals(tagName) && !"title".equals(tagName) && !"script".equals(tagName) &&
288            !"style".equals(tagName) && !"link".equals(tagName) && !"meta".equals(tagName) &&
289            !"iframe".equals(tagName) && !"input_hidden".equals(tagName) &&
290            !"option".equals(tagName) && !"tt".equals(tagName) && !"br".equals(tagName) &&
291            !"colgroup".equals(tagName) && !"col".equals(tagName) && !"hr".equals(tagName) &&
292            !"param".equals(tagName);
293
294    }
295
296}
Note: See TracBrowser for help on using the repository browser.