Ignore:
Timestamp:
12/14/12 15:10:12 (12 years ago)
Author:
pharms
Message:
  • changed logfile format to XML
  • included logging of GUI structure
  • moved robot detection into monitor
Location:
trunk/autoquest-htmlmonitor/src/main/java/de/ugoe/cs/autoquest/htmlmonitor
Files:
1 added
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/autoquest-htmlmonitor/src/main/java/de/ugoe/cs/autoquest/htmlmonitor/HtmlClientInfos.java

    r927 r1019  
    5757     * @param title     title of the web site shown by the browser of the client 
    5858     */ 
    59     public HtmlClientInfos(String clientId, String userAgent, URL url, String title) { 
     59    HtmlClientInfos(String clientId, String userAgent, URL url, String title) { 
    6060        this.clientId = clientId; 
    6161        this.userAgent = userAgent; 
  • trunk/autoquest-htmlmonitor/src/main/java/de/ugoe/cs/autoquest/htmlmonitor/HtmlMonitorLogManager.java

    r927 r1019  
    115115     */ 
    116116    @Override 
    117     public void handleMessage(HtmlClientInfos clientInfos, HtmlEvent[] events) { 
     117    public void handleMessage(HtmlClientInfos clientInfos, 
     118                              HtmlPageElement guiStructure, 
     119                              HtmlEvent[]     events) 
     120    { 
    118121        HtmlMonitorOutputWriter writer = writers.get(clientInfos.getClientId()); 
    119122         
     
    132135            } 
    133136 
    134             writer.handleMessage(clientInfos, events); 
     137            writer.handleMessage(clientInfos, guiStructure, events); 
    135138        } 
    136139        catch (Exception e) { 
     
    144147            if (writer != null) { 
    145148                try { 
    146                     writer.handleMessage(clientInfos, events); 
     149                    writer.handleMessage(clientInfos, guiStructure, events); 
    147150                } 
    148151                catch (Exception e1) { 
  • trunk/autoquest-htmlmonitor/src/main/java/de/ugoe/cs/autoquest/htmlmonitor/HtmlMonitorMessageListener.java

    r927 r1019  
    3232     * 
    3333     * @param clientInfos infos about the client that send the events 
     34     * @param TODO comment 
    3435     * @param events      the received events 
    3536     */ 
    36     void handleMessage(HtmlClientInfos clientInfos, HtmlEvent[] events); 
     37    void handleMessage(HtmlClientInfos clientInfos, 
     38                       HtmlPageElement guiStructure, 
     39                       HtmlEvent[]     events); 
    3740 
    3841} 
  • trunk/autoquest-htmlmonitor/src/main/java/de/ugoe/cs/autoquest/htmlmonitor/HtmlMonitorOutputWriter.java

    r997 r1019  
    2222import java.text.DecimalFormat; 
    2323 
     24import de.ugoe.cs.util.StringTools; 
    2425import de.ugoe.cs.util.console.Console; 
    2526 
     
    177178     */ 
    178179    @Override 
    179     public void handleMessage(HtmlClientInfos clientInfos, HtmlEvent[] events) { 
     180    public void handleMessage(HtmlClientInfos clientInfos, 
     181                              HtmlPageElement guiStructure, 
     182                              HtmlEvent[]     events) 
     183    { 
    180184        if (outputWriter == null) { 
    181185            throw new IllegalStateException("not initialized. Call init() first"); 
    182186        } 
    183187         
     188        if (guiStructure != null) { 
     189            dumpGuiStructure(guiStructure); 
     190        } 
     191         
    184192        for (HtmlEvent event : events) { 
    185193            dumpEvent(event); 
     
    200208    /** 
    201209     * <p> 
     210     * TODO: comment 
     211     * </p> 
     212     * 
     213     * @param guiStructure 
     214     */ 
     215    private void dumpGuiStructure(HtmlPageElement guiStructure) { 
     216        outputWriter.print("<component path=\""); 
     217        outputWriter.print(guiStructure.getPath()); 
     218        outputWriter.println("\">"); 
     219         
     220        dumpParam("class", guiStructure.getTagName()); 
     221        dumpParam("htmlId", guiStructure.getId()); 
     222        dumpParam("title", guiStructure.getTitle()); 
     223        dumpParam("index", guiStructure.getIndex()); 
     224        dumpParam("parent", guiStructure.getParentPath()); 
     225         
     226        outputWriter.println("</component>"); 
     227         
     228        if (guiStructure.getChildren() != null) { 
     229            for (HtmlPageElement child : guiStructure.getChildren()) { 
     230                dumpGuiStructure(child); 
     231            } 
     232        } 
     233    } 
     234 
     235    /** 
     236     * <p> 
    202237     * formats a received event and writes it to the log file. One event results in one line 
    203238     * in the log file containing all infos of the event. 
     
    207242     */ 
    208243    private void dumpEvent(HtmlEvent event) { 
    209         dumpString(event.getClientInfos().getClientId()); 
    210         outputWriter.print(' '); 
    211         dumpString(event.getTime().toString()); 
    212         outputWriter.print(' '); 
    213         dumpString(event.getClientInfos().getTitle()); 
    214         outputWriter.print(' '); 
    215         dumpString(event.getClientInfos().getUrl().toString()); 
    216         outputWriter.print(' '); 
    217         dumpString(event.getClientInfos().getUserAgent()); 
    218         outputWriter.print(' '); 
    219         dumpString(event.getEventType()); 
    220         outputWriter.print(' '); 
    221         dumpString(event.getPath()); 
    222  
     244        outputWriter.print("<event type=\""); 
     245        outputWriter.print(event.getEventType()); 
     246        outputWriter.println("\">"); 
     247         
    223248        if (event.getCoordinates() != null) { 
    224             outputWriter.print(' '); 
    225              
    226             StringBuffer value = new StringBuffer(); 
    227             for (int i = 0; i < event.getCoordinates().length; i++) { 
    228                 if (i > 0) { 
    229                     value.append(','); 
    230                 } 
    231                 value.append(event.getCoordinates()[i]); 
    232             } 
    233              
    234             dumpString(value.toString()); 
    235         } 
    236  
    237         if (event.getKey() != null) { 
    238             outputWriter.print(' '); 
    239             dumpString(event.getKey().toString()); 
    240         } 
     249            dumpParam("X", event.getCoordinates()[0]); 
     250            dumpParam("Y", event.getCoordinates()[1]); 
     251        } 
     252 
     253        dumpParam("key", event.getKey()); 
    241254             
    242255        if (event.getScrollPosition() != null) { 
    243             outputWriter.print(' '); 
    244              
    245             StringBuffer value = new StringBuffer(); 
    246             for (int i = 0; i < event.getScrollPosition().length; i++) { 
    247                 if (i > 0) { 
    248                     value.append(','); 
    249                 } 
    250                 value.append(event.getScrollPosition()[i]); 
    251             } 
    252              
    253             dumpString(value.toString()); 
    254         } 
    255  
    256         if (event.getSelectedValue() != null) { 
    257             outputWriter.print(' '); 
    258             dumpString(event.getSelectedValue()); 
    259         } 
    260              
    261         outputWriter.println(); 
    262     } 
    263  
    264     /** 
    265      * <p> 
    266      * convenience method to dump a string with trailing and leading " as well as replaced 
    267      * backslashes, ", and newlines 
    268      * </p> 
    269      * 
    270      * @param clientId2 
    271      */ 
    272     private void dumpString(String str) { 
    273         String value = str; 
    274         value = value.replaceAll("\\\\", "\\\\\\\\"); 
    275         value = value.replaceAll("\\\"", "\\\\\\\""); 
    276         value = value.replaceAll("\n", "\\\\n"); 
    277          
    278         outputWriter.print('"'); 
    279         outputWriter.print(value); 
    280         outputWriter.print('"'); 
     256            dumpParam("scrollX", event.getScrollPosition()[0]); 
     257            dumpParam("scrollY", event.getScrollPosition()[1]); 
     258        } 
     259 
     260        dumpParam("selectedValue", event.getSelectedValue()); 
     261        dumpParam("target", event.getPath()); 
     262        dumpParam("timestamp", event.getTime()); 
     263         
     264        outputWriter.println("</event>"); 
     265    } 
     266 
     267    /** 
     268     * <p> 
     269     * TODO: comment 
     270     * </p> 
     271     * 
     272     * @param string 
     273     * @param integer 
     274     */ 
     275    private void dumpParam(String name, Object value) { 
     276        if (value == null) { 
     277            return; 
     278        } 
     279         
     280        String val; 
     281         
     282        if (value instanceof String) { 
     283            val = (String) value; 
     284        } 
     285        else { 
     286            val = value.toString(); 
     287        } 
     288         
     289        outputWriter.print(" <param name=\""); 
     290        outputWriter.print(name); 
     291        outputWriter.print("\" value=\""); 
     292        outputWriter.print(StringTools.xmlEntityReplacement(val)); 
     293        outputWriter.println("\"/>"); 
    281294    } 
    282295 
     
    332345        FileOutputStream fis = new FileOutputStream(logFile); 
    333346        outputWriter = new PrintWriter(new OutputStreamWriter(fis, "UTF-8")); 
     347        outputWriter.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); 
     348        outputWriter.println("<session>"); 
    334349    } 
    335350 
     
    341356    private void closeLogWriter() { 
    342357        if (outputWriter != null) { 
     358            outputWriter.println("</session>"); 
    343359            outputWriter.flush(); 
    344360            outputWriter.close(); 
  • trunk/autoquest-htmlmonitor/src/main/java/de/ugoe/cs/autoquest/htmlmonitor/HtmlMonitorServlet.java

    r998 r1019  
    1616 
    1717import java.io.BufferedReader; 
     18import java.io.FileNotFoundException; 
    1819import java.io.IOException; 
    1920import java.io.InputStream; 
     
    3738import org.mortbay.jetty.servlet.DefaultServlet; 
    3839 
     40import de.ugoe.cs.util.FileTools; 
    3941import de.ugoe.cs.util.console.Console; 
    4042 
     
    5961     
    6062    /** 
     63     * <p> 
     64     * Name and path of the robot filter. 
     65     * </p> 
     66     */ 
     67    private static final String ROBOTFILTERFILE = "data/robots/robotfilter.txt"; 
     68 
     69    /** 
     70     * <p> 
     71     * Field that contains a regular expression that matches all robots 
     72     * contained in {@link #ROBOTFILTERFILE}. 
     73     * </p> 
     74     */ 
     75    private String robotRegex = null; 
     76 
     77    /** 
    6178     * the message listener to forward received messages to. 
    6279     */ 
     
    7289    HtmlMonitorServlet(HtmlMonitorMessageListener messageListener) { 
    7390        this.messageListener = messageListener; 
     91        try { 
     92            loadRobotRegex(); 
     93        } 
     94        catch (Exception e) { 
     95            Console.println 
     96                ("robot filtering disabled: could not parse robot filter file " + ROBOTFILTERFILE); 
     97        } 
    7498    } 
    7599 
     
    89113                InputStream script = this.getClass().getClassLoader().getResourceAsStream 
    90114                     ("autoquest-htmlmonitor.js"); 
    91              
     115                 
    92116                if (script == null) { 
    93117                    Console.printerrln("could not read autoquest-htmlmonitor.js from classpath"); 
     
    126150        Object value = null; 
    127151        try { 
     152            //InputStream requestInputStream = dumpStreamContent(request.getInputStream()); 
    128153            InputStream requestInputStream = request.getInputStream(); 
    129              
     154 
    130155            value = JSONValue.parseWithException 
    131156                (new InputStreamReader(requestInputStream, "UTF-8")); 
     
    169194                    ("incoming message does not contain valid client infos --> discarding it"); 
    170195            } 
    171             else { 
     196            else if (isRobot(clientInfos.getUserAgent())) { 
     197                Console.printerrln 
     198                    ("ignoring robot " + clientInfos.getUserAgent()); 
     199            } 
     200            else { 
     201                HtmlPageElement guiStructure = extractHtmlPageElements(message, clientInfos); 
    172202                HtmlEvent[] events = extractHtmlEvents(message, clientInfos); 
     203                 
    173204                if (events == null) { 
    174205                    Console.printerrln 
     
    176207                } 
    177208                else { 
    178                     messageListener.handleMessage(clientInfos, events); 
     209                    messageListener.handleMessage(clientInfos, guiStructure, events); 
    179210                } 
    180211            } 
     
    244275            events = new ArrayList<HtmlEvent>(); 
    245276             
     277            HtmlPageElement server = getServerElement(clientInfos); 
     278            HtmlPageElement page = getPageElementRepresentingWebPage(clientInfos, server); 
     279 
    246280            for (int i = 0; i < eventArray.size(); i++) { 
    247281                Object eventObj = eventArray.get(i); 
     
    277311                                (eventType, coordinates, key, scrollPosition, selectedValue)) 
    278312                    { 
    279                         events.add(new HtmlEvent(clientInfos, time, path, eventType, coordinates, 
    280                                                  key, scrollPosition, selectedValue)); 
     313                        path = page.getPath() + path; 
     314                        events.add(new HtmlEvent(clientInfos, time, path, eventType, 
     315                                                 coordinates, key, scrollPosition, selectedValue)); 
    281316                    } 
    282317                    else { 
     
    294329            return null; 
    295330        } 
     331    } 
     332 
     333    /** 
     334     * <p> 
     335     * TODO: comment 
     336     * </p> 
     337     * 
     338     * @param message 
     339     * @param clientInfos 
     340     * @return 
     341     */ 
     342    private HtmlPageElement extractHtmlPageElements(JSONObject      object, 
     343                                                    HtmlClientInfos clientInfos) 
     344    { 
     345        HtmlPageElement server = getServerElement(clientInfos); 
     346        HtmlPageElement page = getPageElementRepresentingWebPage(clientInfos, server); 
     347 
     348        JSONObject jsonPageElement = assertValue(object, "guiModel", JSONObject.class); 
     349        page.addChild(convert(jsonPageElement, page.getPath())); 
     350         
     351        return server; 
     352    } 
     353 
     354    /** 
     355     * <p> 
     356     * TODO: comment 
     357     * </p> 
     358     * 
     359     * @param clientInfos 
     360     * @return 
     361     */ 
     362    private HtmlPageElement getServerElement(HtmlClientInfos clientInfos) { 
     363        String id = clientInfos.getUrl().getHost(); 
     364        if (clientInfos.getUrl().getPort() > -1) { 
     365            id += ":" + clientInfos.getUrl().getPort(); 
     366        } 
     367         
     368        return new HtmlPageElement(null, "server", id, 0); 
     369    } 
     370 
     371    /** 
     372     * <p> 
     373     * TODO: comment 
     374     * </p> 
     375     * 
     376     * @param clientInfos 
     377     */ 
     378    private HtmlPageElement getPageElementRepresentingWebPage(HtmlClientInfos clientInfos, 
     379                                                              HtmlPageElement server) 
     380    { 
     381        String id = clientInfos.getUrl().getPath(); 
     382         
     383        if (clientInfos.getUrl().getQuery() != null) { 
     384            id += "?" + clientInfos.getUrl().getQuery(); 
     385        } 
     386         
     387        HtmlPageElement page = 
     388            new HtmlPageElement(server.getPath(), "document", id, clientInfos.getTitle(), 0); 
     389         
     390        server.addChild(page); 
     391         
     392        return page; 
     393    } 
     394 
     395    /** 
     396     * <p> 
     397     * TODO: comment 
     398     * </p> 
     399     * 
     400     * @param jsonPageElement 
     401     * @return 
     402     */ 
     403    private HtmlPageElement convert(JSONObject jsonPageElement, String parentPath) { 
     404        HtmlPageElement result = null; 
     405 
     406        if (jsonPageElement != null) { 
     407            String tagName = assertValue(jsonPageElement, "tagName", String.class); 
     408            String id = assertValue(jsonPageElement, "id", String.class); 
     409            Integer index = assertValue(jsonPageElement, "index", Integer.class); 
     410 
     411            result = new HtmlPageElement(parentPath, tagName, id, index); 
     412 
     413            JSONArray childElements = assertValue(jsonPageElement, "children", JSONArray.class); 
     414             
     415            if (childElements != null) { 
     416                Object jsonChild; 
     417 
     418                for (int i = 0; i < childElements.size(); i++) { 
     419                    jsonChild = childElements.get(i); 
     420                    if (!(jsonChild instanceof JSONObject)) { 
     421                        Console.printerrln("child " + (i + 1) + " of HTML page element " + tagName + 
     422                                           " is no valid HTML page element"); 
     423                    } 
     424                    else { 
     425                        result.addChild(convert((JSONObject) jsonChild, result.getPath())); 
     426                    } 
     427                } 
     428            } 
     429             
     430        } 
     431         
     432        return result;     
    296433    } 
    297434 
     
    495632    /** 
    496633     * <p> 
     634     * Checks whether an agent is a robot. 
     635     * </p> 
     636     *  
     637     * @param agent 
     638     *            agent that is checked 
     639     * @return true, if the agent is a robot; false otherwise 
     640     */ 
     641    private boolean isRobot(String agent) { 
     642        return agent.matches(robotRegex); 
     643    } 
     644 
     645    /** 
     646     * <p> 
     647     * Reads {@link #ROBOTFILTERFILE} and creates a regular expression that 
     648     * matches all the robots defined in the file. The regular expression is 
     649     * stored in the field {@link #robotRegex}. 
     650     * </p> 
     651     *  
     652     * @throws IOException 
     653     *             thrown if there is a problem reading the robot filter 
     654     * @throws FileNotFoundException 
     655     *             thrown if the robot filter is not found 
     656     */ 
     657    private void loadRobotRegex() throws IOException, FileNotFoundException { 
     658        String[] lines = FileTools.getLinesFromFile(ROBOTFILTERFILE); 
     659        StringBuilder regex = new StringBuilder(); 
     660        for (int i = 0; i < lines.length; i++) { 
     661            regex.append("(.*" + lines[i] + ".*)"); 
     662            if (i != lines.length - 1) { 
     663                regex.append('|'); 
     664            } 
     665        } 
     666        robotRegex = regex.toString(); 
     667    } 
     668 
     669    /** 
     670     * <p> 
    497671     * convenience method for dumping the content of a stream and returning a new stream 
    498672     * containing the same data. 
     
    504678     * @throws IOException if the stream can not be read  
    505679     */ 
    506     /*private InputStream dumpStreamContent(ServletInputStream inputStream) throws IOException { 
     680/*    private InputStream dumpStreamContent(ServletInputStream inputStream) throws IOException { 
    507681        List<Byte> bytes = new ArrayList<Byte>(); 
    508682        int buf; 
Note: See TracChangeset for help on using the changeset viewer.