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

Last change on this file since 1266 was 1266, checked in by pharms, 11 years ago
  • improved check for ignored GUI elements
  • Property svn:mime-type set to text/plain
File size: 11.0 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            }
130            else if (parentId == null) {
131                throw new SAXException("invalid log: a page element has no parent id");
132            }
133        }
134        else {
135            throw new SAXException("invalid log: unknown GUI element");
136        }
137
138        if (specification != null) {
139            try {
140                super.getGUIElementTree().add(id, parentId, specification);
141            }
142            catch (GUIModelException e) {
143                throw new SAXException("could not handle GUI element with id " +
144                                       id + ": " + e.getMessage(), e);
145            }
146            return true;
147        }
148        else {
149            return false;
150        }
151    }
152
153    /* (non-Javadoc)
154     * @see de.ugoe.cs.autoquest.plugin.html.AbstractDefaultLogParser#handleEvent(String, Map)
155     */
156    @Override
157    protected boolean handleEvent(String type, Map<String, String> parameters) throws SAXException {
158        String targetId = parameters.get("target");
159       
160        if (targetId == null) {
161            String targetDocument = parameters.get("targetDocument");
162            String targetDOMPath = parameters.get("targetDOMPath");
163           
164            if ((targetDocument == null) || (targetDOMPath == null)) {
165                throw new SAXException("event has no target defined");
166            }
167           
168            targetId = determineTargetId(targetDocument, targetDOMPath);
169           
170            if (targetId == null) {
171                // the target id can not be determined yet
172                return false;
173            }
174        }
175       
176        IGUIElement target = super.getGUIElementTree().find(targetId);
177       
178        if (target == null) {
179            // event not processible yet
180            return false;
181        }
182
183        IEventType eventType =
184            HTMLEventTypeFactory.getInstance().getEventType(type, parameters, target);
185       
186        if (eventType != null) {
187            Event event = new Event(eventType, target);
188
189            String timestampStr = parameters.get("timestamp");
190       
191            if (timestampStr != null) {
192                event.setTimestamp(Long.parseLong(timestampStr));
193            }
194
195            ((HTMLGUIElement) event.getTarget()).markUsed();
196       
197            super.addToSequence(event);
198        }
199        // else ignore unknown event type
200
201        return true;
202    }
203
204    /**
205     * <p>
206     * used to determine the id of a target denoted by an event. This is only required for older
207     * document formats. The new formats use concrete ids.
208     * </p>
209     */
210    private String determineTargetId(String targetDocument, String targetDOMPath)
211        throws SAXException
212    {
213        IGUIElement document = super.getGUIElementTree().find(targetDocument);
214       
215        if (document == null) {
216            return null;
217        }
218       
219        if (!(document.getSpecification() instanceof HTMLDocumentSpec)) {
220            throw new SAXException("an id that should refer to an HTML document refers to" +
221                                   "something else");
222        }
223       
224        GUIModel model = super.getGUIElementTree().getGUIModel();
225        IGUIElement child = document;
226        String[] pathElements = targetDOMPath.split("/");
227        int pathIndex = 0;
228       
229        HTMLPageElementSpec compareSpec;
230        String tagName;
231        int index;
232        String htmlId;
233       
234        while ((pathIndex < pathElements.length) && (child != null)) {
235            if ((pathElements[pathIndex] != null) && (!"".equals(pathElements[pathIndex]))) {           
236                Matcher matcher = htmlElementPattern.matcher(pathElements[pathIndex]);
237                if (!matcher.matches()) {
238                    throw new SAXException
239                        ("could not parse target DOM path element " + pathElements[pathIndex]);
240                }
241
242                tagName = matcher.group(1);
243                String indexStr = matcher.group(3);
244                htmlId = matcher.group(4);
245
246                index = -1;
247                if ((indexStr != null) && (!"".equals(indexStr))) {
248                    index = Integer.parseInt(indexStr);
249                }
250
251                compareSpec = new HTMLPageElementSpec
252                    ((HTMLDocumentSpec) document.getSpecification(), tagName, htmlId, index);
253
254                List<IGUIElement> children = model.getChildren(child);
255                child = null;
256
257                for (IGUIElement candidate : children) {
258                    if (compareSpec.getSimilarity(candidate.getSpecification())) {
259                        child = candidate;
260                        break;
261                    }
262                }
263            }
264           
265            pathIndex++;
266        }
267       
268        if (child != null) {
269            return super.getGUIElementTree().find(child);
270        }
271        else {
272            return null;
273        }
274    }
275
276    /**
277     * <p>
278     * checks if tags with the provided name must be handled in the GUI model. As an example,
279     * it is not necessary to handle "head" tags and anything included in them.
280     * </p>
281     *
282     * @param tagName the tag name to check
283     *
284     * @return true, if the tag must be considered, false else
285     */
286    private boolean tagNameMustBeConsidered(String tagName) {
287        if (!tagName.startsWith("input_")) {
288            for (int i = 0; i < tagName.length(); i++) {
289                // all known HTML tags are either letters or digits, but nothing else. Any GUI model
290                // containing something different is proprietary and, therefore, ignored.
291                if (!Character.isLetterOrDigit(tagName.charAt(i))) {
292                    return false;
293                }
294            }
295        }
296       
297        return
298            !"head".equals(tagName) && !"title".equals(tagName) && !"script".equals(tagName) &&
299            !"style".equals(tagName) && !"link".equals(tagName) && !"meta".equals(tagName) &&
300            !"iframe".equals(tagName) && !"input_hidden".equals(tagName) &&
301            !"option".equals(tagName) && !"tt".equals(tagName) && !"br".equals(tagName) &&
302            !"colgroup".equals(tagName) && !"col".equals(tagName) && !"hr".equals(tagName) &&
303            !"param".equals(tagName) && !"sfmsg".equals(tagName);
304
305    }
306
307}
Note: See TracBrowser for help on using the repository browser.