source: trunk/autoquest-htmlmonitor/src/main/java/de/ugoe/cs/autoquest/htmlmonitor/HtmlMonitorServlet.java @ 1174

Last change on this file since 1174 was 1174, checked in by ftrautsch, 11 years ago

Modified Method "checkEventParameterCombinations" - onchange Event because of the input_password bug

File size: 31.4 KB
RevLine 
[927]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
[857]15package de.ugoe.cs.autoquest.htmlmonitor;
16
[879]17import java.io.BufferedReader;
[1019]18import java.io.FileNotFoundException;
[857]19import java.io.IOException;
[879]20import java.io.InputStream;
[857]21import java.io.InputStreamReader;
[879]22import java.io.PrintWriter;
[857]23import java.net.MalformedURLException;
24import java.net.URL;
25import java.util.ArrayList;
26import java.util.List;
27import java.util.Map;
28import java.util.Set;
29
30import javax.servlet.ServletException;
31import javax.servlet.http.HttpServletRequest;
32import javax.servlet.http.HttpServletResponse;
33
34import org.json.simple.JSONArray;
35import org.json.simple.JSONObject;
36import org.json.simple.JSONValue;
37import org.json.simple.parser.ParseException;
38import org.mortbay.jetty.servlet.DefaultServlet;
39
[1019]40import de.ugoe.cs.util.FileTools;
[857]41import de.ugoe.cs.util.console.Console;
42
43/**
44 * <p>
[879]45 * the servlet deployed in the web server that receives all client messages and returns the client
46 * java script. The messages are parsed, validated, and forwarded to the provided message listener.
47 * If a message is not valid, it is discarded. If an event in a message is not valid, it is
48 * discarded. Messages are only received via the POST HTTP method. The GET HTTP method is only
49 * implemented for returning the client java script.
[857]50 * </p>
51 *
52 * @author Patrick Harms
53 */
[871]54class HtmlMonitorServlet extends DefaultServlet {
[857]55
56    /**  */
57    private static final long serialVersionUID = 1L;
58   
[879]59    /**  */
60    private static final boolean DO_TRACE = false;
61   
[857]62    /**
[1019]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    /**
[871]78     * the message listener to forward received messages to.
[857]79     */
[1075]80    private transient HtmlGUIElementManager guiElementManager = new HtmlGUIElementManager();
[1069]81
82    /**
83     * the message listener to forward received messages to.
84     */
[873]85    private transient HtmlMonitorMessageListener messageListener;
[857]86
87    /**
88     * <p>
[871]89     * initializes the servlet with the message listener to which all events shall be forwarded
[857]90     * </p>
91     *
[871]92     * @param messageListener the message listener that shall receive all client events
[857]93     */
94    HtmlMonitorServlet(HtmlMonitorMessageListener messageListener) {
95        this.messageListener = messageListener;
[1019]96        try {
97            loadRobotRegex();
98        }
99        catch (Exception e) {
100            Console.println
101                ("robot filtering disabled: could not parse robot filter file " + ROBOTFILTERFILE);
102        }
[857]103    }
104
105    /* (non-Javadoc)
[879]106     * @see org.mortbay.jetty.servlet.DefaultServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
107     */
108    @Override
109    protected void doGet(HttpServletRequest request, HttpServletResponse response)
110        throws ServletException, IOException
111    {
112        if ((request.getPathInfo() != null) &&
113            (request.getPathInfo().endsWith("/script/autoquest-htmlmonitor.js")))
114        {
[884]115            BufferedReader reader = null;
[879]116           
117            try {
[884]118                InputStream script = this.getClass().getClassLoader().getResourceAsStream
[879]119                     ("autoquest-htmlmonitor.js");
[1019]120               
[879]121                if (script == null) {
122                    Console.printerrln("could not read autoquest-htmlmonitor.js from classpath");
123                }
124                else {
[884]125                    reader = new BufferedReader(new InputStreamReader(script, "UTF-8"));
[879]126                    PrintWriter output = response.getWriter();
127                    String line;
128                   
129                    while ((line = reader.readLine()) != null) {
130                        output.println(line);
131                    }
132                   
133                    output.close();
134                }
135            }
136            catch (Exception e) {
137                Console.printerrln("could not read autoquest-htmlmonitor.js from classpath: " + e);
138                Console.logException(e);
139            }
140            finally {
[884]141                if (reader != null) {
142                    reader.close();
[879]143                }
144            }
145        }
146    }
147
148    /* (non-Javadoc)
[857]149     * @see org.mortbay.jetty.servlet.DefaultServlet#doPost(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
150     */
151    @Override
152    protected void doPost(HttpServletRequest request, HttpServletResponse response)
153        throws ServletException, IOException
154    {
155        Object value = null;
156        try {
[1019]157            //InputStream requestInputStream = dumpStreamContent(request.getInputStream());
[998]158            InputStream requestInputStream = request.getInputStream();
[1019]159
[872]160            value = JSONValue.parseWithException
[998]161                (new InputStreamReader(requestInputStream, "UTF-8"));
[857]162           
163            if (!(value instanceof JSONObject)) {
164                Console.printerrln("incoming data is not of the expected type --> discarding it");
165            }
166            else {
167                handleJSONObject((JSONObject) value);
168            }
169        }
170        catch (ParseException e) {
171            Console.printerrln
172                ("could not parse incoming data --> discarding it (" + e.toString() + ")");
173        }
174    }
175
176    /**
177     * <p>
[871]178     * processes a received JSON object and validates it. If the message is ok, it is forwarded
179     * to the message listener
[857]180     * </p>
181     *
[871]182     * @param object the JSON object that contains a client message
[857]183     */
184    private void handleJSONObject(JSONObject object) {
[879]185        if (DO_TRACE) {
186            dumpJSONObject(object, "");
187        }
[857]188       
189        JSONObject message = assertValue(object, "message", JSONObject.class);
190       
191        if (message == null) {
192            Console.printerrln("incoming data is no valid message --> discarding it");
193        }
194        else {
195            HtmlClientInfos clientInfos = extractClientInfos(message);
196
197            if (clientInfos == null) {
198                Console.printerrln
199                    ("incoming message does not contain valid client infos --> discarding it");
200            }
[1019]201            else if (isRobot(clientInfos.getUserAgent())) {
202                Console.printerrln
203                    ("ignoring robot " + clientInfos.getUserAgent());
204            }
[857]205            else {
[1069]206                HtmlGUIElement guiStructure = extractHtmlPageElements(message, clientInfos);
[857]207                HtmlEvent[] events = extractHtmlEvents(message, clientInfos);
[1019]208               
[857]209                if (events == null) {
210                    Console.printerrln
[998]211                        ("incoming message does not contain valid events --> discarding it");
[857]212                }
213                else {
[1019]214                    messageListener.handleMessage(clientInfos, guiStructure, events);
[857]215                }
216            }
217        }
218    }
219
220    /**
221     * <p>
[871]222     * tries to extract the client infos out of the received JSON object. If this is not fully
223     * possible, an appropriate message is dumped and the whole message is discarded (the method
224     * return null).
[857]225     * </p>
226     *
[871]227     * @param message the message to parse the client infos from
228     *
229     * @return the client infos, if the message is valid in this respect, or null if not
[857]230     */
231    private HtmlClientInfos extractClientInfos(JSONObject message) {
232        HtmlClientInfos clientInfos = null;
233       
234        JSONObject infos = assertValue(message, "clientInfos", JSONObject.class);
235       
236        if (infos != null) {
237            String clientId = assertValue((JSONObject) infos, "clientId", String.class);
238            String userAgent = assertValue((JSONObject) infos, "userAgent", String.class);
239            URL url = assertValue((JSONObject) infos, "url", URL.class);
240            String title = assertValue((JSONObject) infos, "title", String.class);
241           
242            if (clientId == null) {
243                Console.printerrln("client infos do not contain a valid client id");
244            }
245            else if (userAgent == null) {
246                Console.printerrln("client infos do not contain a valid user agent");
247            }
248            else if (url == null) {
249                Console.printerrln("client infos do not contain a valid URL");
250            }
251            else if (title == null) {
252                Console.printerrln("client infos do not contain a valid title");
253            }
254            else {
255                clientInfos = new HtmlClientInfos(clientId, userAgent, url, title);
256            }
257        }
258       
259        return clientInfos;
260    }
261
262    /**
263     * <p>
[871]264     * tries to extract the events out of the received JSON object. If this is not fully
265     * possible, an appropriate message is dumped and the errorprone event is discarded. If no
266     * valid event is found, the whole message is discarded.
[857]267     * </p>
268     *
[871]269     * @param object      the message to parse the events from
270     * @param clientInfos the infos about the client that send the events
271     * 
272     * @return the valid events stored in the message, or null if there are none
[857]273     */
274    private HtmlEvent[] extractHtmlEvents(JSONObject object, HtmlClientInfos clientInfos) {
275        List<HtmlEvent> events = null;
276       
277        JSONArray eventArray = assertValue(object, "events", JSONArray.class);
278       
279        if (eventArray != null) {
280            events = new ArrayList<HtmlEvent>();
281           
[1069]282            HtmlServer server = getServerElement(clientInfos);
283            HtmlDocument document = getPageElementRepresentingWebPage(clientInfos, server);
[1019]284
[857]285            for (int i = 0; i < eventArray.size(); i++) {
286                Object eventObj = eventArray.get(i);
287                if (!(eventObj instanceof JSONObject)) {
288                    Console.printerrln("event number " + (i + 1) + " is not a valid event object");
289                }
290                else {
291                    Long time = assertValue(((JSONObject) eventObj), "time", Long.class);
[1069]292                    String domPath = assertValue(((JSONObject) eventObj), "path", String.class);
[857]293                    String eventType =
294                        assertValue(((JSONObject) eventObj), "eventType", String.class);
295                    Integer[] coordinates =
296                        assertValue(((JSONObject) eventObj), "coordinates", Integer[].class);
297                    Integer key = assertValue(((JSONObject) eventObj), "key", Integer.class);
[942]298                    Integer[] scrollPosition =
299                        assertValue(((JSONObject) eventObj), "scrollPosition", Integer[].class);
300                    String selectedValue =
301                            assertValue(((JSONObject) eventObj), "selectedValue", String.class);
[857]302                   
[998]303                    if (eventType == null) {
304                        Console.printerrln("event number " + (i + 1) + " has no valid event type");
[857]305                    }
[998]306                    else if (time == null) {
307                        Console.printerrln(eventType + " event has no valid timestamp");
308                    }
[1069]309                    else if (domPath == null) {
310                        Console.printerrln(eventType + " event has no valid DOM path");
[857]311                    }
312                    else if ((coordinates != null) && (coordinates.length != 2)) {
[998]313                        Console.printerrln(eventType + " event has no valid coordinates");
[857]314                    }
315                    else if (checkEventParameterCombinations
[1174]316                                (eventType, coordinates, key, scrollPosition, selectedValue, domPath))
[857]317                    {
[1069]318                        HtmlPageElement target =
319                            guiElementManager.getPageElement(document, domPath);
320                       
321                        if (target != null) {
322                            events.add(new HtmlEvent(clientInfos, time, target, eventType,
323                                                     coordinates, key, scrollPosition,
324                                                     selectedValue));
325                        }
326                        else {
327                            events.add(new HtmlEvent(clientInfos, time, document, domPath,
328                                                     eventType, coordinates, key, scrollPosition,
329                                                     selectedValue));
330                        }
[857]331                    }
332                    else {
[998]333                        Console.printerrln(eventType + " event has no valid parameter combination");
[857]334                    }
335                }
336            }
337           
338        }
339       
340        if ((events != null) && (events.size() > 0)) {
341            return events.toArray(new HtmlEvent[events.size()]);
342        }
343        else {
344            return null;
345        }
346    }
347
348    /**
349     * <p>
[1022]350     * extracts the GUI structure from the provided JSON object.
[1019]351     * </p>
352     *
[1022]353     * @param object      the JSON object to extract the GUI structure from
354     * @param clientInfos infos about the client who send the data
355     *
356     * @return the GUI structure extracted from the JSON object of which the root node is a
357     *         representation of the server of the HTML page that was observed
[1019]358     */
[1069]359    private HtmlServer extractHtmlPageElements(JSONObject      object,
360                                               HtmlClientInfos clientInfos)
[1019]361    {
[1069]362        HtmlServer server = getServerElement(clientInfos);
363        HtmlDocument document = getPageElementRepresentingWebPage(clientInfos, server);
[1019]364
365        JSONObject jsonPageElement = assertValue(object, "guiModel", JSONObject.class);
[1069]366        document.addChild(convert(jsonPageElement, document, null));
[1019]367       
368        return server;
369    }
370
371    /**
372     * <p>
[1022]373     * instantiates an element of the GUI structure representing the server of the observed
374     * web page
[1019]375     * </p>
376     *
[1022]377     * @param clientInfos infos about the client who send the data
378     *
379     * @return as described
[1019]380     */
[1069]381    private HtmlServer getServerElement(HtmlClientInfos clientInfos) {
382        String host = clientInfos.getUrl().getHost();
383        int port = 80;
384       
[1019]385        if (clientInfos.getUrl().getPort() > -1) {
[1069]386            port = clientInfos.getUrl().getPort();
[1019]387        }
388       
[1069]389        return guiElementManager.createHtmlServer(host, port);
[1019]390    }
391
392    /**
393     * <p>
[1022]394     * instantiates an element of the GUI structure representing the observed web page. Adds
395     * this element to the provided server as child.
[1019]396     * </p>
397     *
[1022]398     * @param clientInfos infos about the client who send the data
399     * @param server      the server on which the page represented by the return value resists
400     *
401     * @return as described
[1019]402     */
[1069]403    private HtmlDocument getPageElementRepresentingWebPage(HtmlClientInfos clientInfos,
404                                                           HtmlServer      server)
[1019]405    {
[1069]406        String path = clientInfos.getUrl().getPath();
407        String query = null;
[1019]408       
409        if (clientInfos.getUrl().getQuery() != null) {
[1069]410            query = "?" + clientInfos.getUrl().getQuery();
[1019]411        }
412       
[1069]413        HtmlDocument document = guiElementManager.createHtmlDocument
414            (server, path, query, clientInfos.getTitle());
[1019]415       
[1069]416        server.addChild(document);
[1019]417       
[1069]418        return document;
[1019]419    }
420
421    /**
422     * <p>
[1022]423     * converts a JSON object representing an HTML page element to an HTML page element. Calls
424     * itself recursively to also convert the children of the element, if any.
[1019]425     * </p>
426     *
[1022]427     * @param jsonPageElement the JSON object to be converted
[1069]428     * @param document        the document to which the page element belongs
429     * @param parent          the parent page element of the converted element, of null, if none
430     *                        is present. In this case the document is considered the parent
431     *                        element.
[1022]432     *                       
433     * @return as described.
[1019]434     */
[1069]435    private HtmlPageElement convert(JSONObject      jsonPageElement,
436                                    HtmlDocument    document,
437                                    HtmlPageElement parent)
438    {
[1019]439        HtmlPageElement result = null;
440
441        if (jsonPageElement != null) {
442            String tagName = assertValue(jsonPageElement, "tagName", String.class);
[1069]443            String htmlid = assertValue(jsonPageElement, "htmlId", String.class);
[1019]444            Integer index = assertValue(jsonPageElement, "index", Integer.class);
445
[1069]446            result = guiElementManager.createHtmlPageElement
447                (document, parent, tagName, htmlid, index);
[1019]448
449            JSONArray childElements = assertValue(jsonPageElement, "children", JSONArray.class);
450           
451            if (childElements != null) {
452                Object jsonChild;
453
454                for (int i = 0; i < childElements.size(); i++) {
455                    jsonChild = childElements.get(i);
456                    if (!(jsonChild instanceof JSONObject)) {
457                        Console.printerrln("child " + (i + 1) + " of HTML page element " + tagName +
458                                           " is no valid HTML page element");
459                    }
460                    else {
[1069]461                        result.addChild(convert((JSONObject) jsonChild, document, result));
[1019]462                    }
463                }
464            }
465           
466        }
467       
468        return result;   
469    }
470
471    /**
472     * <p>
[942]473     * validates if for the given event type the parameter combination of coordinates, key,
474     * scroll position, and selected value is valid. As an example, an onclick event should
475     * usually not have an associated scroll position.
[857]476     * </p>
477     *
[871]478     * @param eventType      the type of the event
479     * @param coordinates    the coordinates of the event
480     * @param key            the key of the event
481     * @param scrollPosition the scroll position of the event
[942]482     * @param selectedValue  the value selected through a specific event
[1174]483     * @param domPath            the path through the DOM of the document of the HTML element on which
484     *                       the event was executed
[871]485     *
486     * @return true, if the combination of the parameters is valid, false else
[857]487     */
488    private boolean checkEventParameterCombinations(String    eventType,
489                                                    Integer[] coordinates,
490                                                    Integer   key,
[942]491                                                    Integer[] scrollPosition,
[1174]492                                                    String    selectedValue,
493                                                    String    domPath)
[857]494    {
495        boolean result = false;
496       
497        if ("onscroll".equals(eventType)) {
[942]498            if ((coordinates == null) && (key == null) &&
499                (scrollPosition != null) && (selectedValue == null))
500            {
[857]501                result = true;
502            }
503            else {
504                Console.printerrln(eventType + " event has invalid parameters");
505            }
506        }
507        else if ("onclick".equals(eventType) || "ondblclick".equals(eventType)) {
[942]508            if ((coordinates != null) && (key == null) &&
509                (scrollPosition == null) && (selectedValue == null))
510            {
[857]511                result = true;
512            }
513            else {
514                Console.printerrln(eventType + " event has invalid parameters");
515            }
516        }
[942]517        else if ("onchange".equals(eventType)) {
[1174]518            // "input_password" dont have a selectedValue
519            if (domPath.contains("input_password")) {
520                if ((coordinates == null) && (key == null) && (scrollPosition == null)) {
521                    result = true;
522                }
523                else {
524                    Console.printerrln(eventType + " event has invalid parameters");
525                }
[942]526            }
527            else {
[1174]528                if ((coordinates == null) && (key == null) && (scrollPosition == null) &&
529                    (selectedValue != null))
530                {
531                    result = true;
532                }
533                else {
534                    Console.printerrln(eventType + " event has invalid parameters");
535                }
[942]536            }
[1174]537
[942]538        }
[857]539        else if ("onkeypress".equals(eventType) || "onkeydown".equals(eventType) ||
540                 "onkeyup".equals(eventType))
541        {
[942]542            if ((coordinates == null) && (key != null) &&
543                (scrollPosition == null) && (selectedValue == null))
544            {
[857]545                result = true;
546            }
547            else {
548                Console.printerrln(eventType + " event has invalid parameters");
549            }
550        }
551        else if ("onfocus".equals(eventType) || "onmouseout".equals(eventType) ||
[998]552                 "onmousemove".equals(eventType) || "onload".equals(eventType) ||
553                 "onunload".equals(eventType) || "onbeforeunload".equals(eventType) ||
554                 "onpagehide".equals(eventType) || "onpageshow".equals(eventType) ||
555                 "onabort".equals(eventType) || "onsubmit".equals(eventType) ||
556                 "onplaying".equals(eventType) || "onpause".equals(eventType) ||
557                 "ontimeupdate".equals(eventType) || "onerror".equals(eventType) ||
558                 "onundo".equals(eventType) || "onreset".equals(eventType) ||
559                 "onselect".equals(eventType))
[857]560        {
[942]561            if ((coordinates == null) && (key == null) &&
562                (scrollPosition == null) && (selectedValue == null))
563            {
[857]564                result = true;
565            }
566            else {
567                Console.printerrln(eventType + " event has invalid parameters");
568            }
569        }
570        else {
571            Console.printerrln("'" + eventType + "' is not a valid event type");
572        }
573       
574        return result;
575    }
576
577    /**
578     * <p>
[871]579     * converts a value in the provided object matching the provided key to the provided type. If
580     * there is no value with the key or if the value can not be transformed to the provided type,
581     * the method returns null.
[857]582     * </p>
583     *
[871]584     * @param object the object to read the value from
585     * @param key    the key of the value
586     * @param clazz  the type to which the value should be transformed
587     *
588     * @return the value or null if either the value does not exist or if it can not be transformed
589     *         to the expected type
[857]590     */
591    @SuppressWarnings("unchecked")
592    private <T> T assertValue(JSONObject object, String key, Class<T> clazz) {
593        Object value = object.get(key);
594        T result = null;
595       
596        if (clazz.isInstance(value)) {
597            result = (T) value;
598        }
599        else if (value instanceof String) {
600            if (URL.class.equals(clazz)) {
601                try {
602                    result = (T) new URL((String) value);
603                }
604                catch (MalformedURLException e) {
605                    e.printStackTrace();
606                    Console.printerrln("retrieved malformed URL for key '" + key + "': " + value +
607                                       " (" + e.toString() + ")");
608                }
609            }
610            else if ((int.class.equals(clazz)) || (Integer.class.equals(clazz))) {
611                try {
[872]612                    result = (T) Integer.valueOf(Integer.parseInt((String) value));
[857]613                }
614                catch (NumberFormatException e) {
615                    Console.printerrln
616                        ("retrieved malformed integer for key '" + key + "': " + value);
617                }
618            }
619            else if ((long.class.equals(clazz)) || (Long.class.equals(clazz))) {
620                try {
[872]621                    result = (T) Long.valueOf(Long.parseLong((String) value));
[857]622                }
623                catch (NumberFormatException e) {
624                    Console.printerrln
625                        ("retrieved malformed long for key '" + key + "': " + value);
626                }
627            }
628        }
629        else if (value instanceof Long) {
630            if ((int.class.equals(clazz)) || (Integer.class.equals(clazz))) {
631                result = (T) (Integer) ((Long) value).intValue();
632            }
633        }
634        else if (value instanceof JSONArray) {
635            if ((int[].class.equals(clazz)) || (Integer[].class.equals(clazz))) {
636                Integer[] resultArray = new Integer[((JSONArray) value).size()];
637                boolean allCouldBeParsed = true;
638               
639                for (int i = 0; i < ((JSONArray) value).size(); i++) {
640                    try {
641                        if (((JSONArray) value).get(i) instanceof Long) {
642                            resultArray[i] = (int) (long) (Long) ((JSONArray) value).get(i);
643                        }
644                        else if (((JSONArray) value).get(i) instanceof String) {
645                            try {
646                                resultArray[i] =
647                                    (int) Long.parseLong((String) ((JSONArray) value).get(i));
648                            }
649                            catch (NumberFormatException e) {
650                                Console.printerrln
651                                    ("retrieved malformed integer array for key '" + key + "': " +
652                                     value);
653                       
654                                allCouldBeParsed = false;
655                                break;
656                            }
657                        }
658                        else {
659                            Console.printerrln
660                                ("can not handle type of value in expected integer array '" + key +
661                                 "': " + value);
662                        }
663                    }
664                    catch (ClassCastException e) {
665                        e.printStackTrace();
666                        Console.printerrln("expected integer array for key '" + key +
667                                           "' but it was something else: " + value);
668                       
669                        allCouldBeParsed = false;
670                        break;
671                    }
672                }
673               
674                if (allCouldBeParsed) {
675                    result = (T) resultArray;
676                }
677            }
678        }
679       
680        return result;
681    }
682
683    /**
684     * <p>
[1019]685     * Checks whether an agent is a robot.
686     * </p>
687     *
688     * @param agent
689     *            agent that is checked
690     * @return true, if the agent is a robot; false otherwise
691     */
692    private boolean isRobot(String agent) {
693        return agent.matches(robotRegex);
694    }
695
696    /**
697     * <p>
698     * Reads {@link #ROBOTFILTERFILE} and creates a regular expression that
699     * matches all the robots defined in the file. The regular expression is
700     * stored in the field {@link #robotRegex}.
701     * </p>
702     *
703     * @throws IOException
704     *             thrown if there is a problem reading the robot filter
705     * @throws FileNotFoundException
706     *             thrown if the robot filter is not found
707     */
708    private void loadRobotRegex() throws IOException, FileNotFoundException {
709        String[] lines = FileTools.getLinesFromFile(ROBOTFILTERFILE);
710        StringBuilder regex = new StringBuilder();
711        for (int i = 0; i < lines.length; i++) {
712            regex.append("(.*" + lines[i] + ".*)");
713            if (i != lines.length - 1) {
714                regex.append('|');
715            }
716        }
717        robotRegex = regex.toString();
718    }
719
720    /**
721     * <p>
[998]722     * convenience method for dumping the content of a stream and returning a new stream
723     * containing the same data.
724     * </p>
725     *
726     * @param inputStream the stream to be dumped and copied
727     * @return the copy of the stream
728     *
729     * @throws IOException if the stream can not be read
730     */
[1019]731/*    private InputStream dumpStreamContent(ServletInputStream inputStream) throws IOException {
[998]732        List<Byte> bytes = new ArrayList<Byte>();
733        int buf;
734       
735        while ((buf = inputStream.read()) >= 0) {
736            bytes.add((byte) buf);
737        }
738       
739        byte[] byteArray = new byte[bytes.size()];
740        for (int i = 0; i < bytes.size(); i++) {
741            byteArray[i] = bytes.get(i);
742        }
743       
744        System.out.println(new String(byteArray, "UTF-8"));
745       
746        return new ByteArrayInputStream(byteArray);
747    }*/
748
749    /**
750     * <p>
[871]751     * convenience method for dumping an object to std out. If the object is a JSON object, it is
752     * deeply analyzed and its internal structure is dumped as well.
[857]753     * </p>
754     *
[871]755     * @param object the object to dump
756     * @param indent the indentation to be used.
[857]757     */
758    private void dumpJSONObject(Object object, String indent) {
759        if (object instanceof JSONArray) {
760            boolean arrayContainsJSONObjects = false;
761            for (Object arrayElem : (JSONArray) object) {
762                if (arrayElem instanceof JSONObject) {
763                    arrayContainsJSONObjects = true;
764                    break;
765                }               
766            }
767           
768            if (arrayContainsJSONObjects) {
769                System.out.println();
770                System.out.print(indent);
771                System.out.println('[');
772                System.out.print(indent);
773                System.out.print(' ');
774            }
775            else {
776                System.out.print(' ');
777                System.out.print('[');
778            }
779           
780            int index = 0;
781            for (Object arrayElem : (JSONArray) object) {
782                if (index++ > 0) {
783                    System.out.print(",");
784                    if (arrayContainsJSONObjects) {
785                        System.out.println();
786                        System.out.print(indent);
787                    }
788
789                    System.out.print(' ');
790                }
791
792                dumpJSONObject(arrayElem, indent + "  ");
793            }
794           
795            if (arrayContainsJSONObjects) {
796                System.out.println();
797                System.out.print(indent);
798            }
799           
800            System.out.print(']');
801        }
802        else if (object instanceof JSONObject) {
803            System.out.println(" {");
804           
805            @SuppressWarnings("unchecked")
806            Set<Map.Entry<?,?>> entrySet = ((JSONObject) object).entrySet();
807           
808            int index = 0;
809            for (Map.Entry<?,?> entry : entrySet) {
810                if (index++ > 0) {
811                    System.out.println(",");
812                }
813                System.out.print(indent);
814                System.out.print("  \"");
815                System.out.print(entry.getKey());
816                System.out.print("\":");
817                dumpJSONObject(entry.getValue(), indent + "  ");
818            }
819           
820            System.out.println();
821            System.out.print(indent);
822            System.out.print('}');
823        }
824        else {
825            System.out.print('"');
826            System.out.print(object);
827            System.out.print('"');
828        }
829    }
830
831}
Note: See TracBrowser for help on using the repository browser.