Changeset 619 for trunk/quest-plugin-mfc/src/main/java/de/ugoe/cs/quest/plugin/mfc/MFCLogParser.java
- Timestamp:
- 08/27/12 11:45:09 (12 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/quest-plugin-mfc/src/main/java/de/ugoe/cs/quest/plugin/mfc/MFCLogParser.java
r581 r619 1 1 2 package de.ugoe.cs.quest.plugin.mfc; 2 3 … … 8 9 import java.security.InvalidParameterException; 9 10 import java.util.Collection; 11 import java.util.HashMap; 10 12 import java.util.LinkedList; 11 13 import java.util.List; 14 import java.util.Map; 12 15 import java.util.SortedMap; 13 16 import java.util.TreeMap; … … 24 27 25 28 import de.ugoe.cs.quest.eventcore.Event; 26 import de.ugoe.cs.quest. plugin.mfc.eventcore.WindowTree;29 import de.ugoe.cs.quest.eventcore.guimodel.GUIModel; 27 30 import de.ugoe.cs.quest.plugin.mfc.eventcore.WindowsMessage; 31 import de.ugoe.cs.quest.plugin.mfc.eventcore.WindowsMessageType; 32 import de.ugoe.cs.quest.plugin.mfc.guimodel.MFCGUIElement; 33 import de.ugoe.cs.quest.plugin.mfc.guimodel.WindowTree; 28 34 import de.ugoe.cs.util.StringTools; 29 35 import de.ugoe.cs.util.console.Console; … … 31 37 /** 32 38 * <p> 33 * This class provides functionality to parse XML log files generated by the 34 * MFCUsageMonitor of EventBench. The result of parsing a file is a collection 35 * of event sequences. It uses the {@link SequenceSplitter} and the 36 * {@link EventGenerator} as well as custom defined {@link MessageHandler} for 37 * the parsing. 39 * This class provides functionality to parse XML log files generated by the MFCUsageMonitor of 40 * EventBench. The result of parsing a file is a collection of event sequences. It uses the 41 * {@link SequenceSplitter} and the {@link EventGenerator} as well as custom defined 42 * {@link MessageHandler} for the parsing. 38 43 * </p> 39 44 * … … 43 48 public class MFCLogParser extends DefaultHandler { 44 49 45 /** 46 * <p> 47 * If a custom message handler is used, this field contains its handle. 48 * Otherwise this field is {@code null}. 49 * </p> 50 */ 51 private MessageHandler currentHandler; 52 53 /** 54 * <p> 55 * Handle to the message that is currently parsed. 56 * </p> 57 */ 58 private WindowsMessage currentMessage; 59 60 /** 61 * <p> 62 * {@link SequenceSplitter} instance used by the {@link MFCLogParser}. 63 * </p> 64 */ 65 private SequenceSplitter sequenceSplitter; 66 67 /** 68 * <p> 69 * Collection of event sequences that is contained in the log file, which is 70 * parsed. 71 * </p> 72 */ 73 private Collection<List<Event>> sequences; 74 75 /** 76 * <p> 77 * Debugging variable that allows the analysis which message type occurs how 78 * often in the log file. Can be used to enhance the message filter. 79 * </p> 80 */ 81 private SortedMap<Integer, Integer> typeCounter; 82 83 /** 84 * <p> 85 * Debugging variable that enables the counting of the occurrences of each 86 * message. Used in combination with {@link #typeCounter}. 87 * </p> 88 */ 89 private boolean countMessageOccurences; 90 91 /** 92 * <p> 93 * Constructor. Creates a new LogParser that does not count message 94 * occurrences. 95 * </p> 96 */ 97 public MFCLogParser() { 98 this(false); 99 } 100 101 /** 102 * <p> 103 * Constructor. Creates a new LogParser. 104 * </p> 105 * 106 * @param countMessageOccurences 107 * if true, the occurrences of each message type in the log is 108 * counted. 109 */ 110 public MFCLogParser(boolean countMessageOccurences) { 111 sequenceSplitter = new SequenceSplitter(); 112 sequences = new LinkedList<List<Event>>(); 113 currentHandler = null; 114 this.countMessageOccurences = countMessageOccurences; 115 if (countMessageOccurences) { 116 typeCounter = new TreeMap<Integer, Integer>(); 117 } 118 119 } 120 121 /** 122 * <p> 123 * Returns the collection of event sequences that is obtained from parsing 124 * log files. 125 * </p> 126 * 127 * @return collection of event sequences 128 */ 129 public Collection<List<Event>> getSequences() { 130 return sequences; 131 } 132 133 /* 134 * (non-Javadoc) 135 * 136 * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, 137 * java.lang.String, java.lang.String, org.xml.sax.Attributes) 138 */ 139 @Override 140 public void startElement(String uri, String localName, String qName, 141 Attributes atts) throws SAXException { 142 if (qName.equals("session")) { 143 Console.traceln("start of session"); 144 sequenceSplitter = new SequenceSplitter(); 145 } else if (qName.equals("msg")) { 146 String msgType = atts.getValue("type"); 147 int msgInt = -1; 148 try { 149 msgInt = Integer.parseInt(msgType); 150 151 if (countMessageOccurences) { 152 Integer currentCount = typeCounter.get(msgInt); 153 if (currentCount == null) { 154 typeCounter.put(msgInt, 1); 155 } else { 156 typeCounter.put(msgInt, currentCount + 1); 157 } 158 } 159 160 if (msgInt == MessageDefs.WM_CREATE) { 161 currentHandler = new HandlerCreate(); 162 currentHandler.onStartElement(); 163 } else if (msgInt == MessageDefs.WM_DESTROY) { 164 currentHandler = new HandlerDestroy(); 165 currentHandler.onStartElement(); 166 } else if (msgInt == MessageDefs.WM_SETTEXT) { 167 currentHandler = new HandlerSetText(); 168 currentHandler.onStartElement(); 169 } else { 170 currentMessage = new WindowsMessage(msgInt); 171 } 172 } catch (NumberFormatException e) { 173 Console.printerrln("Invalid message type: type not a number"); 174 e.printStackTrace(); 175 } 176 } else if (qName.equals("param")) { 177 if (currentHandler != null) { 178 currentHandler.onParameter(atts.getValue("name"), 179 atts.getValue("value")); 180 } else { 181 currentMessage.addParameter(atts.getValue("name"), 182 atts.getValue("value")); 183 } 184 } 185 } 186 187 /* 188 * (non-Javadoc) 189 * 190 * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, 191 * java.lang.String, java.lang.String) 192 */ 193 @Override 194 public void endElement(String uri, String localName, String qName) 195 throws SAXException { 196 if (qName.equals("msg")) { 197 if (currentHandler != null) { 198 currentHandler.onEndElement(); 199 currentHandler = null; 200 } else { 201 try { 202 currentMessage.setTarget(WindowTree.getInstance()); 203 sequenceSplitter.addMessage(currentMessage); 204 } catch (InvalidParameterException e) { 205 Console.traceln(e.getMessage() + " WindowsMessage " 206 + currentMessage + " ignored."); 207 } 208 } 209 } else if (qName.equals("session")) { 210 sequenceSplitter.endSession(); 211 List<Event> seq = sequenceSplitter.getSequence(); 212 if( seq!=null && !seq.isEmpty() ) { 213 sequences.add(seq); 214 } 215 Console.traceln("end of session"); 216 } 217 } 218 219 /** 220 * <p> 221 * Parses a given log file created by the MFCMonitor and adds its contents 222 * to the collection of event sequences. 223 * </p> 224 * 225 * @param filename 226 * name and path of the log file 227 */ 228 public void parseFile(String filename) { 229 if (filename == null) { 230 throw new InvalidParameterException("filename must not be null"); 231 } 232 233 SAXParserFactory spf = SAXParserFactory.newInstance(); 234 spf.setValidating(true); 235 236 SAXParser saxParser = null; 237 InputSource inputSource = null; 238 try { 239 saxParser = spf.newSAXParser(); 240 inputSource = new InputSource(new InputStreamReader( 241 new FileInputStream(filename)));//, "UTF-8")); 242 //} catch (UnsupportedEncodingException e) { 243 // e.printStackTrace(); 244 } catch (ParserConfigurationException e) { 245 e.printStackTrace(); 246 } catch (SAXException e) { 247 e.printStackTrace(); 248 } catch (FileNotFoundException e) { 249 e.printStackTrace(); 250 } 251 if (inputSource != null) { 252 inputSource.setSystemId("file://" 253 + new File(filename).getAbsolutePath()); 254 try { 255 if (saxParser == null) { 256 throw new RuntimeException("SAXParser creation failed"); 257 } 258 saxParser.parse(inputSource, this); 259 } catch (SAXParseException e) { 260 Console.printerrln("Failure parsing file in line " 261 + e.getLineNumber() + ", column " + e.getColumnNumber() 262 + "."); 263 e.printStackTrace(); 264 } catch (SAXException e) { 265 e.printStackTrace(); 266 } catch (IOException e) { 267 e.printStackTrace(); 268 } 269 } 270 if (countMessageOccurences) { 271 Console.println("Message statistics:"); 272 Console.println(typeCounter.toString() 273 .replace(" ", StringTools.ENDLINE) 274 .replaceAll("[\\{\\}]", "")); 275 } 276 } 50 /** 51 * <p> 52 * If a custom message handler is used, this field contains its handle. Otherwise this field is 53 * {@code null}. 54 * </p> 55 */ 56 private MessageHandler currentHandler; 57 58 /** 59 * <p> 60 * internal handle to the current window tree 61 * </p> 62 */ 63 private WindowTree currentWindowTree; 64 65 /** 66 * <p> 67 * the type of the currently parsed message 68 * </p> 69 */ 70 private WindowsMessageType currentMessageType; 71 72 /** 73 * <p> 74 * the parameters of the currently parsed message 75 * </p> 76 */ 77 private Map<String, Object> currentMessageParameters = new HashMap<String, Object>(); 78 79 /** 80 * <p> 81 * {@link SequenceSplitter} instance used by the {@link MFCLogParser}. 82 * </p> 83 */ 84 private SequenceSplitter sequenceSplitter; 85 86 /** 87 * <p> 88 * Collection of message sequences that is contained in the log file, which is parsed. 89 * </p> 90 */ 91 private Collection<List<Event>> sequences; 92 93 /** 94 * <p> 95 * Debugging variable that allows the analysis which message type occurs how often in the log 96 * file. Can be used to enhance the message filter. 97 * </p> 98 */ 99 private SortedMap<WindowsMessageType, Integer> typeCounter; 100 101 /** 102 * <p> 103 * Debugging variable that enables the counting of the occurrences of each message. Used in 104 * combination with {@link #typeCounter}. 105 * </p> 106 */ 107 private boolean countMessageOccurences; 108 109 /** 110 * <p> 111 * Constructor. Creates a new LogParser that does not count message occurrences. 112 * </p> 113 */ 114 public MFCLogParser() { 115 this(false); 116 } 117 118 /** 119 * <p> 120 * Constructor. Creates a new LogParser. 121 * </p> 122 * 123 * @param countMessageOccurences 124 * if true, the occurrences of each message type in the log is counted. 125 */ 126 public MFCLogParser(boolean countMessageOccurences) { 127 sequences = new LinkedList<List<Event>>(); 128 currentHandler = null; 129 this.countMessageOccurences = countMessageOccurences; 130 if (countMessageOccurences) { 131 typeCounter = new TreeMap<WindowsMessageType, Integer>(); 132 } 133 } 134 135 /** 136 * <p> 137 * Parses a log file written by the MFCMonitor and creates a collection of event sequences. 138 * </p> 139 * 140 * @param filename 141 * name and path of the log file 142 */ 143 public void parseFile(String filename) { 144 if (filename == null) { 145 throw new InvalidParameterException("filename must not be null"); 146 } 147 148 parseFile(new File(filename)); 149 } 150 151 /** 152 * <p> 153 * Parses a log file written by the MFCMonitor and creates a collection of event sequences. 154 * </p> 155 * 156 * @param file 157 * name and path of the log file 158 */ 159 public void parseFile(File file) { 160 if (file == null) { 161 throw new InvalidParameterException("file must not be null"); 162 } 163 164 SAXParserFactory spf = SAXParserFactory.newInstance(); 165 spf.setValidating(true); 166 167 SAXParser saxParser = null; 168 InputSource inputSource = null; 169 try { 170 saxParser = spf.newSAXParser(); 171 inputSource = new InputSource(new InputStreamReader(new FileInputStream(file)));// , 172 // "UTF-8")); 173 // } catch (UnsupportedEncodingException e) { 174 // e.printStackTrace(); 175 } 176 catch (ParserConfigurationException e) { 177 // TODO handle Exception 178 e.printStackTrace(); 179 } 180 catch (SAXException e) { 181 // TODO handle Exception 182 e.printStackTrace(); 183 } 184 catch (FileNotFoundException e) { 185 // TODO handle Exception 186 e.printStackTrace(); 187 } 188 189 if (inputSource != null) { 190 inputSource.setSystemId("file://" + file.getAbsolutePath()); 191 try { 192 if (saxParser == null) { 193 throw new RuntimeException("SAXParser creation failed"); 194 } 195 saxParser.parse(inputSource, this); 196 } 197 catch (SAXParseException e) { 198 Console.printerrln("Failure parsing file in line " + e.getLineNumber() + 199 ", column " + e.getColumnNumber() + "."); 200 e.printStackTrace(); 201 } 202 catch (SAXException e) { 203 // TODO handle Exception 204 e.printStackTrace(); 205 } 206 catch (IOException e) { 207 // TODO handle Exception 208 e.printStackTrace(); 209 } 210 } 211 212 if (countMessageOccurences) { 213 Console.println("Message statistics:"); 214 Console.println 215 (typeCounter.toString().replace(" ", StringTools.ENDLINE).replaceAll("[\\{\\}]", "")); 216 } 217 } 218 219 /** 220 * <p> 221 * Returns the collection of event sequences that is obtained from parsing log files. 222 * </p> 223 * 224 * @return collection of event sequences 225 */ 226 public Collection<List<Event>> getSequences() { 227 return sequences; 228 } 229 230 /** 231 * <p> 232 * Returns the gui model that is obtained from parsing log files. 233 * </p> 234 * 235 * @return collection of event sequences 236 */ 237 public GUIModel getGuiModel() { 238 return currentWindowTree.getGUIModel(); 239 } 240 241 /* 242 * (non-Javadoc) 243 * 244 * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String, 245 * java.lang.String, org.xml.sax.Attributes) 246 */ 247 @Override 248 public void startElement(String uri, String localName, String qName, Attributes atts) 249 throws SAXException 250 { 251 if (qName.equals("session")) { 252 Console.traceln("start of session"); 253 // in some logs, the session end may be marked in between the log. This is because 254 // of thread problems. So instead of creating a new GUI model, preserve it. 255 if (currentWindowTree == null) { 256 currentWindowTree = new WindowTree(); 257 } 258 sequenceSplitter = new SequenceSplitter(currentWindowTree); 259 } 260 else if (qName.equals("msg")) { 261 currentMessageType = WindowsMessageType.parseMessageType(atts.getValue("type")); 262 263 if (countMessageOccurences) { 264 Integer currentCount = typeCounter.get(currentMessageType); 265 if (currentCount == null) { 266 typeCounter.put(currentMessageType, 1); 267 } 268 else { 269 typeCounter.put(currentMessageType, currentCount + 1); 270 } 271 } 272 273 if (currentMessageType == WindowsMessageType.WM_CREATE) { 274 currentHandler = new HandlerCreate(currentWindowTree); 275 currentHandler.onStartElement(); 276 } 277 else if (currentMessageType == WindowsMessageType.WM_DESTROY) { 278 currentHandler = new HandlerDestroy(currentWindowTree); 279 currentHandler.onStartElement(); 280 } 281 else if (currentMessageType == WindowsMessageType.WM_SETTEXT) { 282 currentHandler = new HandlerSetText(currentWindowTree); 283 currentHandler.onStartElement(); 284 } 285 } 286 else if (qName.equals("param")) { 287 if (currentHandler != null) { 288 currentHandler.onParameter(atts.getValue("name"), atts.getValue("value")); 289 } 290 else { 291 // provide the parameters directly in the correct type 292 String paramName = atts.getValue("name"); 293 if (("window.hwnd".equals(paramName)) || 294 ("source".equals(paramName)) || 295 ("LPARAM".equals(paramName)) || 296 ("WPARAM".equals(paramName)) || 297 ("scrollPos".equals(paramName)) || 298 ("scrollBarHandle".equals(paramName))) 299 { 300 Long paramValue = Long.parseLong(atts.getValue("value")); 301 currentMessageParameters.put(paramName, paramValue); 302 } 303 else { 304 currentMessageParameters.put(paramName, atts.getValue("value")); 305 } 306 } 307 } 308 } 309 310 /* 311 * (non-Javadoc) 312 * 313 * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String, 314 * java.lang.String) 315 */ 316 @Override 317 public void endElement(String uri, String localName, String qName) throws SAXException { 318 if (qName.equals("msg")) { 319 if (currentHandler != null) { 320 currentHandler.onEndElement(); 321 currentHandler = null; 322 } 323 else { 324 try { 325 long hwnd = (Long) currentMessageParameters.get("window.hwnd"); 326 MFCGUIElement target = currentWindowTree.find(hwnd); 327 328 WindowsMessage message = new WindowsMessage 329 (currentMessageType, target, currentMessageParameters); 330 331 sequenceSplitter.addMessage(message); 332 } 333 catch (InvalidParameterException e) { 334 Console.traceln(e.getMessage() + " WindowsMessage " + currentMessageType + 335 " ignored."); 336 } 337 } 338 } 339 else if (qName.equals("session")) { 340 sequenceSplitter.endSession(); 341 List<Event> seq = sequenceSplitter.getSequence(); 342 if (seq != null && !seq.isEmpty()) { 343 sequences.add(seq); 344 } 345 Console.traceln("end of session"); 346 } 347 } 348 277 349 }
Note: See TracChangeset
for help on using the changeset viewer.