Ignore:
Timestamp:
08/27/12 11:45:09 (12 years ago)
Author:
pharms
Message:
  • adapted implementation to now generate a full GUI model as well as concrete GUI interaction events
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 
    12package de.ugoe.cs.quest.plugin.mfc; 
    23 
     
    89import java.security.InvalidParameterException; 
    910import java.util.Collection; 
     11import java.util.HashMap; 
    1012import java.util.LinkedList; 
    1113import java.util.List; 
     14import java.util.Map; 
    1215import java.util.SortedMap; 
    1316import java.util.TreeMap; 
     
    2427 
    2528import de.ugoe.cs.quest.eventcore.Event; 
    26 import de.ugoe.cs.quest.plugin.mfc.eventcore.WindowTree; 
     29import de.ugoe.cs.quest.eventcore.guimodel.GUIModel; 
    2730import de.ugoe.cs.quest.plugin.mfc.eventcore.WindowsMessage; 
     31import de.ugoe.cs.quest.plugin.mfc.eventcore.WindowsMessageType; 
     32import de.ugoe.cs.quest.plugin.mfc.guimodel.MFCGUIElement; 
     33import de.ugoe.cs.quest.plugin.mfc.guimodel.WindowTree; 
    2834import de.ugoe.cs.util.StringTools; 
    2935import de.ugoe.cs.util.console.Console; 
     
    3137/** 
    3238 * <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. 
    3843 * </p> 
    3944 *  
     
    4348public class MFCLogParser extends DefaultHandler { 
    4449 
    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 
    277349} 
Note: See TracChangeset for help on using the changeset viewer.