View Javadoc

1   /*
2    *  Java HTML Tidy - JTidy
3    *  HTML parser and pretty printer
4    *
5    *  Copyright (c) 1998-2000 World Wide Web Consortium (Massachusetts
6    *  Institute of Technology, Institut National de Recherche en
7    *  Informatique et en Automatique, Keio University). All Rights
8    *  Reserved.
9    *
10   *  Contributing Author(s):
11   *
12   *     Dave Raggett <dsr@w3.org>
13   *     Andy Quick <ac.quick@sympatico.ca> (translation to Java)
14   *     Gary L Peskin <garyp@firstech.com> (Java development)
15   *     Sami Lempinen <sami@lempinen.net> (release management)
16   *     Fabrizio Giustina <fgiust at users.sourceforge.net>
17   *     Vlad Skarzhevskyy <vlads at users.sourceforge.net> (JTidy servlet  development)
18   *
19   *  The contributing author(s) would like to thank all those who
20   *  helped with testing, bug fixes, and patience.  This wouldn't
21   *  have been possible without all of you.
22   *
23   *  COPYRIGHT NOTICE:
24   *
25   *  This software and documentation is provided "as is," and
26   *  the copyright holders and contributing author(s) make no
27   *  representations or warranties, express or implied, including
28   *  but not limited to, warranties of merchantability or fitness
29   *  for any particular purpose or that the use of the software or
30   *  documentation will not infringe any third party patents,
31   *  copyrights, trademarks or other rights.
32   *
33   *  The copyright holders and contributing author(s) will not be
34   *  liable for any direct, indirect, special or consequential damages
35   *  arising out of any use of the software or documentation, even if
36   *  advised of the possibility of such damage.
37   *
38   *  Permission is hereby granted to use, copy, modify, and distribute
39   *  this source code, or portions hereof, documentation and executables,
40   *  for any purpose, without fee, subject to the following restrictions:
41   *
42   *  1. The origin of this source code must not be misrepresented.
43   *  2. Altered versions must be plainly marked as such and must
44   *     not be misrepresented as being the original source.
45   *  3. This Copyright notice may not be removed or altered from any
46   *     source or altered source distribution.
47   *
48   *  The copyright holders and contributing author(s) specifically
49   *  permit, without fee, and encourage the use of this source code
50   *  as a component for supporting the Hypertext Markup Language in
51   *  commercial products. If you use this source code in a product,
52   *  acknowledgment is not required but would be appreciated.
53   *
54   */
55  package org.w3c.tidy.servlet.reports;
56  
57  import java.io.IOException;
58  import java.io.InputStream;
59  import java.io.LineNumberReader;
60  import java.io.InputStreamReader;
61  import java.io.Writer;
62  import java.io.StringReader;
63  import java.util.Vector;
64  import java.util.Iterator;
65  import java.util.HashMap;
66  
67  import javax.servlet.http.HttpSession;
68  
69  import org.apache.commons.logging.Log;
70  import org.apache.commons.logging.LogFactory;
71  
72  import org.w3c.tidy.TidyMessage;
73  import org.w3c.tidy.servlet.ResponseRecord;
74  import org.w3c.tidy.servlet.ResponseRecordRepository;
75  import org.w3c.tidy.servlet.properties.JTidyServletProperties;
76  import org.w3c.tidy.servlet.util.HTMLEncode;
77  
78  
79  /***
80   * Report code used by ReportTag and TidyServlet
81   * @author Vlad Skarzhevskyy <a href="mailto:skarzhevskyy@gmail.com">skarzhevskyy@gmail.com </a>
82   * @version $Revision: 1.10 $ ($Author: vlads $)
83   */
84  public class Report
85  {
86  
87      /***
88       * Properties
89       */
90      private boolean completePage = true;
91  
92      private boolean view;
93  
94      private boolean printSource;
95  
96      private boolean wrapSource = true;
97  
98      private boolean printHtmlResult = false;
99  
100     private int wrapLen = 0;
101     
102     /***
103      * output report as xhtml
104      */
105     private boolean xhtml;
106 
107     private static final String RESOURCE_JAVASCRIPT = "JTidyServletReport.js";
108 
109     private static final String RESOURCE_STYLESHEET = "JTidyServletReport.css";
110 
111     /***
112      * Logger.
113      */
114     private Log log = LogFactory.getLog(Report.class);
115 
116     /***
117      * Internal variables for convenience
118      */
119     StringBuffer out;
120 
121     ResponseRecordRepository responseRecordRepository;
122 
123     public Report(ResponseRecordRepository responseRecordRepository)
124     {
125         this.out = new StringBuffer(1024);
126         this.responseRecordRepository = responseRecordRepository;
127         init();
128     }
129 
130     public Report(HttpSession httpSession)
131     {
132         this.out = new StringBuffer(1024);
133         this.responseRecordRepository = JTidyServletProperties.getInstance().getRepositoryInstance(httpSession);
134         init();
135     }
136 
137     private void init() 
138     {
139         JTidyServletProperties properties = JTidyServletProperties.getInstance();
140         this.xhtml = properties.getBooleanProperty(JTidyServletProperties.PROPERTY_BOOLEAN_XHTML, true);
141     }
142     
143     public void print(Writer writer, String key) throws IOException
144     {
145         format(key);
146         writer.write(this.out.toString());
147     }
148 
149     void td(String str1, String str2)
150     {
151         td(str1);
152         td(str2);
153     }
154 
155     void td(String str)
156     {
157         this.out.append("<td>").append(str).append("</td>\n");
158     }
159 
160     void tr()
161     {
162         this.out.append("</tr><tr>\n");
163     }
164 
165     void identSpace(int ln)
166     {
167         if (ln < 10)
168         {
169             this.out.append("   ");
170         }
171         else if (ln < 100)
172         {
173             this.out.append("  ");
174         }
175         else if (ln < 1000)
176         {
177             this.out.append(" ");
178         }
179     }
180 
181     void format(String keyString) throws IOException
182     {
183 
184         ResponseRecord record = null;
185 
186         if (this.responseRecordRepository == null)
187         {
188             log.info("No ResponseRecordRepository");
189         }
190         else
191         {
192             Object key = this.responseRecordRepository.getResponseID(keyString);
193             record = this.responseRecordRepository.getRecord(key);
194         }
195 
196         if (record == null)
197         {
198             this.out.append("No data for ").append(keyString);
199             return;
200         }
201 
202         if (this.view)
203         {
204             formatView(record);
205         }
206         else
207         {
208             formatReport(record);
209         }
210     }
211 
212     void formatView(ResponseRecord record)
213     {
214         if (printHtmlResult)
215         {
216             this.out.append(record.getHtmlOutput());
217         }
218         else
219         {
220             this.out.append(record.getHtmlInput());
221         }
222     }
223 
224     void printScript()
225     {
226         appendResource(RESOURCE_JAVASCRIPT);
227     }
228 
229     void printStylesheet()
230     {
231         this.out.append("<style type=\"text/css\">\n");
232         appendResource(RESOURCE_STYLESHEET);
233         this.out.append("</style>\n");
234     }
235 
236     void appendResource(String resourceName)
237     {
238         InputStream in = this.getClass().getClassLoader().getResourceAsStream(resourceName);
239         if (in == null)
240         {
241             log.warn("resource not found:" + resourceName);
242             return;
243         }
244 
245         LineNumberReader lnr = new LineNumberReader(new InputStreamReader(in));
246         String strSource;
247         try
248         {
249             while ((strSource = lnr.readLine()) != null)
250             {
251                 this.out.append(strSource).append("\n");
252             }
253             lnr.close();
254         }
255         catch (IOException e)
256         {
257             log.error("Error Reading resource " + resourceName, e);
258         }
259     }
260 
261     void formatReport(ResponseRecord record) throws IOException
262     {
263         if (completePage)
264         {
265             if (this.xhtml)
266             {
267                 out.append("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"");
268                 out.append(" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n");
269             }
270             else
271             {
272                 out.append("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"");
273                 out.append(" \"http://www.w3.org/TR/html4/loose.dtd\">\n");
274             }
275             out.append("<html><head><title>JTidy Messages</title>");
276             printStylesheet();
277             out.append("</head><body>\n");
278         }
279 
280         printScript();
281 
282         out.append("<table id=\"JTidyMessagesTable\" summary=\"\"><tr>");
283         out.append("<td colspan=\"4\">JTidy Messages for request:" + record.getRequestID());
284         out.append(" processed in " + record.getParsTime() + " milliseconds</td>");
285         tr();
286         out.append("<td colspan=\"4\">Validation Errors " + record.getParseErrors() + "</td>\n");
287         tr();
288         out.append("<td colspan=\"4\">Validation Warnings " + record.getParseWarnings() + "</td>\n");
289 
290         HashMap map = new HashMap();
291 
292         // Build source list lines
293         Vector source = new Vector();
294         LineNumberReader lnr = new LineNumberReader(new StringReader(record.getHtmlInput()));
295         String strSource;
296         while ((strSource = lnr.readLine()) != null)
297         {
298             // ignore lnr.getLineNumber() for now since lines should be one after another.
299             source.add(strSource);
300         }
301 
302         for (Iterator i = record.getMessages().iterator(); i.hasNext();)
303         {
304             TidyMessage message = (TidyMessage) i.next();
305             tr();
306             Integer ln = new Integer(message.getLine());
307 
308             StringBuffer lineStr = new StringBuffer(300);
309             lineStr.append("Line ");
310             if (printSource)
311             {
312                 lineStr.append("<a href=\"#line").append(ln).append("\" ");
313                 lineStr.append(" onclick=\"jTidyReportHighlight('").append(ln).append("')\" ");
314                 lineStr.append(">").append(ln).append("</a>");
315             }
316             else
317             {
318                 lineStr.append(ln);
319             }
320 
321             if (map.get(ln) == null)
322             {
323                 // Back to Error anchor
324                 lineStr.append("<a name=\"errline").append(ln).append("\"></a>");
325             }
326             lineStr.append(", ");
327 
328             td(lineStr.toString());
329 
330             td("column " + message.getColumn());
331             td(message.getLevel().toString() + ":");
332 
333             StringBuffer messageStr = new StringBuffer(300);
334             // Add popup message
335             messageStr.append("<a title=\"");
336             messageStr.append(HTMLEncode.encode((String) source.get(message.getLine() - 1)));
337             messageStr.append("\">");
338 
339             messageStr.append(HTMLEncode.encode(message.getMessage()));
340 
341             messageStr.append("</a>");
342 
343             td(messageStr.toString());
344 
345             map.put(ln, message);
346         }
347 
348         out.append("</tr>\n");
349         out.append("</table>\n");
350 
351         if (printSource)
352         {
353             out.append("<div>");
354             if (this.xhtml)
355             {
356                 out.append("<br/>");
357             }
358             else
359             {
360                 out.append("<br>");
361             }
362             out.append("Below is the source used for this validation:");
363 
364             out.append("<pre>");
365             out.append("<a name=\"JTidyOriginalSource\"></a>");
366             
367             int ln = 0;
368             for (int lnIdx = 0; lnIdx < source.size(); lnIdx++)
369             {
370                 ln = lnIdx + 1;
371                 String str = (String) source.get(lnIdx);
372                 TidyMessage message = (TidyMessage) map.get(new Integer(ln));
373 
374                 out.append("<span id=\"srcline").append(ln).append("\"");
375 
376                 if (message != null)
377                 {
378                     // out.append(" style=\"padding: 0px; margin: 0; background: #F0DFDF; border: solid 1px #F0DFDF;\"
379                     // ");
380                     out.append("class = \"JTidyReportSrcLineError\" ");
381                 }
382                 out.append(">");
383 
384                 identSpace(ln);
385 
386                 out.append("<a name=\"line");
387                 out.append(ln);
388                 out.append("\"></a><strong>");
389 
390                 if (message == null)
391                 {
392                     out.append(ln);
393                 }
394                 else
395                 {
396                     // to-do onclick=\"history.go(-1)\"
397                     out.append("<a href=\"#errline" + ln + "\">");
398                     out.append(ln);
399                     out.append("</a>");
400                 }
401 
402                 out.append("</strong>");
403 
404                 if ((this.wrapSource) || (this.wrapLen != 0))
405                 {
406                     int useWrapLen = this.wrapLen;
407                     if (useWrapLen == 0)
408                     {
409                         useWrapLen = 100;
410                     }
411                     str = wrap(str, useWrapLen);
412                 }
413 
414                 if (message != null)
415                 {
416                     // Add popup message
417                     out.append("<a title=\"");
418                     out.append(message.getLevel().toString() + " :");
419                     out.append(HTMLEncode.encode(message.getMessage()));
420                     out.append("\">");
421                 }
422                 // Print Source code
423                 if (str.length() > 0)
424                 {
425                     out.append("<code class=\"html\">&nbsp;");
426                     out.append(HTMLEncode.encode(str));
427                     out.append("</code>");
428                 }
429 
430                 if (message != null)
431                 {
432                     out.append("</a>");
433                 }
434                 out.append("</span>");
435                 out.append("\n");
436             }
437 
438             // End of file last line + 1
439             out.append("<a name=\"line");
440             out.append((ln + 1));
441             out.append("\"></a>");
442             out.append("EOF");
443             out.append("</pre>");
444             out.append("</div>");
445         }
446 
447         if (printHtmlResult)
448         {
449             out.append("<div>");
450             if (this.xhtml) {
451                 out.append("<br/>");
452             } else {
453                 out.append("<br>");
454             }
455             out.append("Below is the generated html code:");
456 
457             LineNumberReader lnrr = new LineNumberReader(new StringReader(record.getHtmlOutput()));
458 
459             out.append("<pre>");
460             out.append("<a name=\"JTidyHtmlResult\"></a>");
461             
462             String str;
463             int ln = 0;
464             while ((str = lnrr.readLine()) != null)
465             {
466                 ln = lnrr.getLineNumber();
467 
468                 identSpace(ln);
469                 out.append("<a name=\"resultLine");
470                 out.append(ln);
471                 out.append("\"></a><strong>");
472                 out.append(ln);
473                 out.append("</strong>");
474 
475                 if ((this.wrapSource) || (this.wrapLen != 0))
476                 {
477                     int useWrapLen = this.wrapLen;
478                     if (useWrapLen == 0)
479                     {
480                         useWrapLen = 100;
481                     }
482                     str = wrap(str, useWrapLen);
483                 }
484 
485                 // Print Source code
486                 if (str.length() > 0)
487                 {
488                     out.append("<code>&nbsp;");
489                     out.append(HTMLEncode.encode(str));
490                     out.append("</code>");
491                 }
492 
493                 out.append("\n");
494             }
495             out.append("<a name=\"resultLine");
496             out.append((ln + 1));
497             out.append("\"></a>");
498             out.append("EOF");
499             out.append("</pre>");
500             out.append("</div>");
501         }
502 
503         if (completePage)
504         {
505             out.append("</body></html>");
506         }
507     }
508 
509     /***
510      * Simple line Wrapper by End of Tag.
511      * @param str
512      * @param wrapLen
513      * @return Wraped line
514      */
515     private String wrap(String str, int wrapLen)
516     {
517         final String identLine = "    ";
518         int strLen = str.length();
519         StringBuffer buffer = new StringBuffer(strLen + strLen / wrapLen + 3);
520 
521         char[] charAry = str.toCharArray();
522         int idx = 0;
523         int lineLen = 0;
524         boolean inString = false;
525         while (idx < charAry.length)
526         {
527             char c = charAry[idx];
528             idx++;
529             lineLen++;
530             buffer.append(c);
531             if ((lineLen >= wrapLen) && (c == '>'))
532             {
533                 buffer.append('\n').append(identLine);
534                 lineLen = 0;
535             }
536 
537             if (c == '\"')
538             {
539                 if (inString && (lineLen >= (wrapLen + 10)))
540                 {
541                     buffer.append('\n').append(identLine);
542                     lineLen = 0;
543                 }
544                 inString = !inString;
545             }
546         }
547 
548         return buffer.toString();
549     }
550 
551     /***
552      * @param completePage The completePage to set.
553      */
554     public void setCompletePage(boolean completePage)
555     {
556         this.completePage = completePage;
557     }
558 
559     /***
560      * @param view The view to set.
561      */
562     public void setView(boolean view)
563     {
564         this.view = view;
565     }
566 
567     /***
568      * @param printSource The printSource to set.
569      */
570     public void setPrintSource(boolean printSource)
571     {
572         this.printSource = printSource;
573     }
574 
575     /***
576      * @param wrapSource The wrapSource to set.
577      */
578     public void setWrapSource(boolean wrapSource)
579     {
580         this.wrapSource = wrapSource;
581     }
582 
583     /***
584      * @param printHtmlResult The printHtmlResult to set.
585      */
586     public void setPrintHtmlResult(boolean printHtmlResult)
587     {
588         this.printHtmlResult = printHtmlResult;
589     }
590 
591     /***
592      * @param wrapLen The wrapLen to set.
593      */
594     public void setWrapLen(int wrapLen)
595     {
596         this.wrapLen = wrapLen;
597     }
598 }