source: trunk/autoquest-plugin-jfc/src/main/java/de/ugoe/cs/autoquest/plugin/android/AndroidLogParser.java @ 1758

Last change on this file since 1758 was 1758, checked in by funger, 10 years ago

add AndroidElements? and CMDparse stubs

  • Property svn:mime-type set to text/plain
File size: 10.0 KB
Line 
1//   Copyright 2014 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.
14package de.ugoe.cs.autoquest.plugin.android;
15
16import java.io.File;
17import java.io.FileInputStream;
18import java.io.FileNotFoundException;
19import java.io.IOException;
20import java.io.InputStreamReader;
21import java.io.UnsupportedEncodingException;
22import java.util.Collection;
23import java.util.LinkedList;
24import java.util.List;
25import java.util.Map;
26
27import javax.xml.parsers.ParserConfigurationException;
28import javax.xml.parsers.SAXParser;
29import javax.xml.parsers.SAXParserFactory;
30
31import org.xml.sax.Attributes;
32import org.xml.sax.InputSource;
33import org.xml.sax.SAXException;
34import org.xml.sax.SAXParseException;
35import org.xml.sax.helpers.DefaultHandler;
36
37import de.ugoe.cs.autoquest.eventcore.Event;
38import de.ugoe.cs.autoquest.eventcore.guimodel.GUIElementTree;
39import de.ugoe.cs.autoquest.eventcore.guimodel.GUIModel;
40import de.ugoe.cs.autoquest.eventcore.guimodel.GUIModelException;
41import de.ugoe.cs.autoquest.plugin.android.guimodel.AndroidGUIElementSpec;
42import de.ugoe.cs.util.console.Console;
43
44/**
45 * <p>
46 * This class provides functionality to parse XML log files generated by the AndroidMonitor of
47 * autoquest. The result of parsing a file is a collection of event sequences.
48 * </p>
49 *
50 * @author Florian Unger
51 * @version 1.0
52 */
53public class AndroidLogParser extends DefaultHandler{
54       
55        /*
56         * (non-Javadoc)
57         *
58         * int java.lang.Object.hashCode() is used in the Androidmonitor
59         * Long is used to internally handle and compare the number. e.g.
60         * currentGUIElementHash != null
61         * */
62        /**
63     *
64     * <p>
65     * Internal handle to the hashcode of the GUI element, that is currently parsed.
66     * </p>
67     */
68    private Long currentGUIElementHash;
69   
70        /**
71     * <p>
72     * internal handle to the parsed GUI structure, stored in a GUIElementTree
73     * </p>
74     */
75    private GUIElementTree<Long> currentGUIElementTree;
76   
77    /**
78     * <p>
79     * internal handle to the specification currently parsed for a GUI element
80     * </p>
81     */
82    private AndroidGUIElementSpec currentGUIElementSpec;
83   
84    /**
85     *
86     * <p>
87     * Internal handle to the hashcode of the parent of the GUI element, that is currently parsed.
88     * </p>
89     */
90    private Long currentParentHash;
91   
92    /**
93     * <p>
94     * Internal handle to the event sequence that is currently being parsed.
95     * </p>
96     */
97  //  private List<Event> currentSequence;
98   
99        /**
100     * <p>
101     * Map that holds events that had no registered target GUI element during parsing. Keys are the
102     * IDs of the unregistered targets.
103     * </p>
104     */
105    private Map<Long, List<Event>> eventsWithoutTargets;
106   
107        /**
108     * <p>
109     * Collection of event sequences that is contained in the log file, which is parsed.
110     * </p>
111     */
112    private Collection<List<Event>> sequences;
113   
114        /**
115     * <p>
116     * Constructor. Creates a new AndroidLogParser.
117     * </p>
118     */
119        public AndroidLogParser(){
120                sequences = new LinkedList<List<Event>>();
121                //currentSequence = null;               
122        }
123       
124        // TODO create a constructor which creates a new AndroidLogParser with a specific event filter.
125       
126        /**
127     * <p>
128     * Parses a log file written by the JFCMonitor and creates a collection of event sequences.
129     * </p>
130     *
131     * @param filename
132     *            name and path of the log file
133     */
134    public void parseFile(String filename) {
135        if (filename == null) {
136            throw new IllegalArgumentException("filename must not be null");
137        }
138
139        parseFile(new File(filename));
140    }
141   
142    /**
143     * <p>
144     * Parses a log file written by the JFCMonitor and creates a collection of event sequences.
145     * </p>
146     *
147     * @param file
148     *            name and path of the log file
149     */
150    public void parseFile(File file) {
151        if (file == null) {
152            throw new IllegalArgumentException("file must not be null");
153        }
154       
155        SAXParserFactory spf = SAXParserFactory.newInstance();
156        //TODO Why? Ask Steffen on next meeting.
157        spf.setValidating(true);
158       
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.printerr("Error parsing file + " + file.getName());
168            Console.logException(e);
169            return;
170        }
171        catch (ParserConfigurationException e) {
172            Console.printerr("Error parsing file + " + file.getName());
173            Console.logException(e);
174            return;
175        }
176        catch (SAXException e) {
177            Console.printerr("Error parsing file + " + file.getName());
178            Console.logException(e);
179            return;
180        }
181        catch (FileNotFoundException e) {
182            Console.printerr("Error parsing file + " + file.getName());
183            Console.logException(e);
184            return;
185        }
186        if (inputSource != null) {
187                inputSource.setSystemId("file://" + file.getAbsolutePath());
188                try {
189                        // TODO Why is saxParser checked for a second time? It is checked in one of the catch blocks right above. http://docs.oracle.com/javase/7/docs/api/javax/xml/parsers/SAXParserFactory.html#newSAXParser()
190                if (saxParser == null) {
191                    throw new RuntimeException("SAXParser creation failed");
192                }
193                saxParser.parse(inputSource, this);
194            }
195            catch (SAXParseException e) {
196                Console.printerrln("Failure parsing file in line " + e.getLineNumber() +
197                    ", column " + e.getColumnNumber() + ".");
198                Console.logException(e);
199                return;
200            }
201            catch (SAXException e) {
202                Console.printerr("Error parsing file + " + file.getName());
203                Console.logException(e);
204                return;
205            }
206            catch (IOException e) {
207                Console.printerr("Error parsing file + " + file.getName());
208                Console.logException(e);
209                return;
210            }
211        }
212        if (!eventsWithoutTargets.isEmpty()) {
213            Console.printerr("Some events reference GUI elements that are not part of logfile. " +
214                        "These events have been parsed without target.");
215        }
216    }
217   
218    /**
219     * <p>
220     * Returns the collection of event sequences that is obtained from parsing log files.
221     * </p>
222     *
223     * @return collection of event sequences
224     */
225    public Collection<List<Event>> getSequences() {
226        return sequences;
227    }
228   
229    /**
230     * <p>
231     * Returns the GUI model that is obtained from parsing log files.
232     * </p>
233     *
234     * @return GUIModel
235     */
236    public GUIModel getGuiModel() {
237        return currentGUIElementTree.getGUIModel();
238    }
239   
240    /*
241     * (non-Javadoc)
242     *
243     * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String,
244     * java.lang.String, org.xml.sax.Attributes)
245     */
246    public void startElement(String uri, String localName, String qName, Attributes atts)
247        throws SAXException
248    {
249        if (qName.equals("sessions")) {
250          //  currentSequence = new LinkedList<Event>(); Up to know it is necessary to handle different sessions. All components are known before an event occurs.
251            if (currentGUIElementTree == null)
252                currentGUIElementTree = new GUIElementTree<Long>();
253        }
254       
255        if (qName.equals("component")) {
256                currentGUIElementHash = Long.parseLong(atts.getValue("hash"));
257                currentGUIElementSpec = new AndroidGUIElementSpec();
258                currentGUIElementSpec.setHashCode((int) currentGUIElementHash.longValue());
259        }
260        else if (qName.equals("event")) {
261                // TODO
262        }
263        else if (qName.equals("param")) {
264                if (currentGUIElementHash != null) {
265                        if ("class".equals(atts.getValue("name"))) {
266                    currentGUIElementSpec.setType(atts.getValue("value"));
267                }
268                        else if("path".equals(atts.getValue("name"))){
269                                currentGUIElementSpec.setPath(atts.getValue("value"));
270                        }
271                        else if ("parent".equals(atts.getValue("name"))) {
272                    currentParentHash = Long.parseLong(atts.getValue("value"));
273                }
274                }
275                //TODO evaluate event values else if(currentEventId != null)
276        }
277    }
278   
279    /*
280     * (non-Javadoc)
281     *
282     * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String,
283     * java.lang.String)
284     */
285    @Override
286    public void endElement(String uri, String localName, String qName) throws SAXException {
287        if (qName.equals("component") && currentGUIElementHash != null) {
288                try {
289                                currentGUIElementTree.add(currentGUIElementHash, currentParentHash,
290                                        currentGUIElementSpec);
291                        } catch (GUIModelException e) {
292                                throw new SAXException("could not handle GUI element with hash " +
293                        currentGUIElementHash + ": " + e.getMessage(), e);
294                        }
295                currentGUIElementHash = null;
296            currentParentHash = null;           
297        }
298        // TODO else if (currentEventId != null) {
299    }
300       
301}
Note: See TracBrowser for help on using the repository browser.