View Javadoc
1   /*
2    * The MIT License
3    * Copyright © 2004-2014 Fabrizio Giustina
4    * Copyright © 2022-2022 Web-Legacy
5    *
6    * Permission is hereby granted, free of charge, to any person obtaining a copy
7    * of this software and associated documentation files (the "Software"), to deal
8    * in the Software without restriction, including without limitation the rights
9    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10   * copies of the Software, and to permit persons to whom the Software is
11   * furnished to do so, subject to the following conditions:
12   *
13   * The above copyright notice and this permission notice shall be included in
14   * all copies or substantial portions of the Software.
15   *
16   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22   * THE SOFTWARE.
23   */
24  package net.sf.maventaglib;
25  
26  import java.io.StringReader;
27  import java.text.MessageFormat;
28  import java.util.Locale;
29  
30  import org.apache.commons.lang3.StringUtils;
31  import org.apache.maven.doxia.module.xhtml5.Xhtml5Parser;
32  import org.apache.maven.doxia.parser.ParseException;
33  import org.apache.maven.doxia.sink.Sink;
34  import org.apache.maven.doxia.util.HtmlTools;
35  import org.apache.maven.plugin.logging.Log;
36  import org.apache.maven.reporting.AbstractMavenReportRenderer;
37  
38  import net.sf.maventaglib.checker.ELFunction;
39  import net.sf.maventaglib.checker.Tag;
40  import net.sf.maventaglib.checker.TagAttribute;
41  import net.sf.maventaglib.checker.TagFile;
42  import net.sf.maventaglib.checker.TagVariable;
43  import net.sf.maventaglib.checker.Tld;
44  import net.sf.maventaglib.checker.TldItem;
45  
46  
47  /**
48   * Generates a tag reference xdoc that can be integrated in a maven generated site.
49   *
50   * @author Fabrizio Giustina
51   * @version $Revision $ ($Author $)
52   */
53  public class TagreferenceRenderer extends AbstractMavenTaglibReportRenderer
54  {
55  
56      private static final String OPEN_DIV = "<div>";
57  
58      private static final String CLOSE_DIV = "</div>";
59  
60      /**
61       * list of Tld to check.
62       */
63      private Tld[] tlds;
64  
65      /**
66       * {@code true} to parse html in the description of tld info, tags and attributes.
67       */
68      private boolean parseHtml = true;
69  
70      /**
71       * the logger that has been injected into this mojo.
72       */
73      private Log log;
74  
75      /**
76       * Class-Constructor
77       *
78       * @param sink the sink to use.
79       * @param locale the wanted locale to return the report's description, could be <code>null</code>.
80       * @param tlds list of TLDs to check.
81       * @param parseHtml {@code true} to parse html in the description of tld info, tags and attributes.
82       * @param log the logger that has been injected into this mojo.
83       */
84      public TagreferenceRenderer(Sink sink, Locale locale, Tld[] tlds, boolean parseHtml, Log log)
85      {
86          super(sink, locale);
87  
88          this.tlds = tlds;
89          this.parseHtml = parseHtml;
90          this.log = log;
91  
92      }
93  
94      /**
95       * @see AbstractMavenReportRenderer#getTitle()
96       */
97      @Override
98      public String getTitle()
99      {
100         return getMessageString("Tagreference.title"); //$NON-NLS-1$
101     }
102 
103     /**
104      * @see AbstractMavenReportRenderer#renderBody()
105      */
106     @Override
107     protected void renderBody()
108     {
109         sink.body();
110 
111         startSection(getMessageString("Tagreference.h1")); //$NON-NLS-1$
112         paragraph(getMessageString("Tagreference.intro")); //$NON-NLS-1$
113 
114         sink.list();
115         for (Tld tld : tlds)
116         {
117             log.debug("Rendering " + tld.getFilename());
118             sink.listItem();
119             sink.link("#" + tld.getFilename()); //$NON-NLS-1$
120             sink.text(MessageFormat.format(getMessageString("Tagreference.listitem.tld"), //$NON-NLS-1$
121                 StringUtils.defaultIfEmpty(tld.getName(), tld.getShortname()), tld.getFilename()));
122             sink.link_();
123             sink.text(getMessageString("Tagreference.listitem.uri") + tld.getUri()); //$NON-NLS-1$
124             sink.listItem_();
125         }
126         sink.list_();
127 
128         endSection();
129 
130         for (Tld tld : tlds)
131         {
132             doTld(tld);
133             sink.pageBreak();
134         }
135 
136         sink.body_();
137     }
138 
139     private String stripTags(String html)
140     {
141         if (html == null)
142         {
143             return StringUtils.EMPTY;
144         }
145         return html.replaceAll("\\<.*?\\>", StringUtils.EMPTY); //$NON-NLS-1$
146     }
147 
148     /**
149      * @param tld Tld
150      */
151     private void doTld(Tld tld)
152     {
153         // new section for each tld
154         sink.anchor(tld.getFilename());
155         sink.anchor_();
156 
157         startSection(StringUtils.defaultIfEmpty(tld.getName(), tld.getShortname())
158             + " - "
159             + MessageFormat.format(getMessageString("Tagreference.tldversion"), tld.getTlibversion()));
160 
161         sink.paragraph();
162         if (parseHtml)
163         {
164             parseHtml(tld.getInfo());
165         }
166         else
167         {
168             sink.text(tld.getInfo());
169         }
170         sink.paragraph_();
171 
172         sink.paragraph();
173         sink.bold();
174         sink.text("Namespace definition:");
175         sink.bold_();
176         sink.text(" xmlns:");
177         sink.text(tld.getShortname());
178         sink.text("=\"");
179         sink.text(tld.getUri());
180         sink.text("\"");
181         sink.paragraph_();
182 
183         TldItem[] tags = tld.getTags();
184         ELFunction[] functions = tld.getFunctions();
185         TagFile[] tagfiles = tld.getTagfiles();
186 
187         printList(tld, tags, "Tags");
188         printList(tld, functions, "EL Functions");
189         printList(tld, tagfiles, "Tagfiles");
190 
191         sink.paragraph();
192         sink.text(getMessageString("Tagreference.intro.required") + ' '); //$NON-NLS-1$
193         sink.bold();
194         sink.text(getMessageString("Tagreference.required.marker")); //$NON-NLS-1$
195         sink.bold_();
196         sink.paragraph_();
197 
198         if (tags != null)
199         {
200             for (TldItem tag : tags)
201             {
202                 doTag(tld.getShortname(), (Tag) tag);
203             }
204         }
205 
206         if (functions != null)
207         {
208             for (ELFunction function : functions)
209             {
210                 doFunction(tld.getShortname(), function);
211             }
212         }
213         if (tagfiles != null)
214         {
215             for (TagFile tagfile : tagfiles)
216             {
217                 doTagFile(tld.getShortname(), tagfile);
218             }
219         }
220 
221         endSection();
222     }
223 
224     /**
225      * @param shortname
226      * @param elFunction
227      */
228     private void doFunction(String prefix, ELFunction tag)
229     {
230 
231         sink.anchor(prefix + ":" + tag.getName());
232         sink.anchor_();
233 
234         // new subsection for each tag
235         startSection(prefix + ":" + tag.getName() + "(" + tag.getParameters() + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
236 
237         sink.paragraph();
238         sink.bold();
239         sink.text("Function class: ");
240         sink.bold_();
241         sink.text(tag.getFunctionClass());
242         sink.paragraph_();
243         sink.paragraph();
244         sink.bold();
245         sink.text("Function signature: ");
246         sink.bold_();
247         sink.text(tag.getFunctionSignature());
248         sink.paragraph_();
249 
250         if (parseHtml)
251         {
252             parseHtml(tag.getDescription());
253         }
254         else
255         {
256             sink.paragraph();
257             sink.text(tag.getDescription());
258             sink.paragraph_();
259         }
260 
261         if (StringUtils.isNotEmpty(tag.getExample()))
262         {
263             startSection(getMessageString("Tagreference.example")); //$NON-NLS-1$
264             verbatimText(tag.getExample());
265             endSection();
266         }
267 
268         endSection();
269     }
270 
271     /**
272      * @param tld
273      * @param tags
274      */
275     private void printList(Tld tld, TldItem[] tags, String intro)
276     {
277         if (tags != null && tags.length > 0)
278         {
279 
280             sink.paragraph();
281             sink.bold();
282             sink.text(intro);
283             sink.bold_();
284             sink.paragraph_();
285 
286             sink.list();
287 
288             for (TldItem tag : tags)
289             {
290                 sink.listItem();
291 
292                 sink.link("#" + tld.getShortname() + ":" + tag.getName()); //$NON-NLS-1$
293                 if (tag.isDeprecated())
294                 {
295                     sink.italic();
296                 }
297                 sink.text(tag.getName());
298                 if (tag instanceof ELFunction)
299                 {
300                     sink.text("()");
301                 }
302 
303                 if (tag.isDeprecated())
304                 {
305                     sink.italic_();
306                 }
307                 sink.link_();
308 
309                 sink.text(" "); //$NON-NLS-1$
310 
311                 String cleanedDescription = stripTags(StringUtils.substringBefore(tag.getDescription(), ".")) + '.'; //$NON-NLS-1$
312                 if (parseHtml)
313                 {
314                     cleanedDescription = HtmlTools.unescapeHTML(cleanedDescription);
315                 }
316                 sink.text(cleanedDescription);
317 
318                 sink.listItem_();
319             }
320 
321             sink.list_();
322         }
323     }
324 
325     /**
326      * Checks a single tag and returns validation results.
327      * @param tag Tag
328      */
329     private void doTag(String prefix, Tag tag)
330     {
331         sink.anchor(prefix + ":" + tag.getName());
332         sink.anchor_();
333 
334         // new subsection for each tag
335         startSection("<" + prefix + ":" + tag.getName() + ">"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
336         if (parseHtml)
337         {
338             parseHtml(tag.getDescription());
339         }
340         else
341         {
342             sink.paragraph();
343             sink.text(tag.getDescription());
344             sink.paragraph_();
345         }
346 
347         sink.paragraph();
348         sink.text(getMessageString("Tagreference.cancontain") + ' '); //$NON-NLS-1$
349         sink.text(tag.getBodycontent());
350         sink.paragraph_();
351 
352         if (StringUtils.isNotEmpty(tag.getExample()))
353         {
354             startSection(getMessageString("Tagreference.example")); //$NON-NLS-1$
355             verbatimText(tag.getExample());
356             endSection();
357         }
358 
359         // variables
360 
361         // attributes
362         TagAttribute[] attributes = tag.getAttributes();
363 
364         if (attributes != null && attributes.length > 0)
365         {
366             startSection(getMessageString("Tagreference.attributes")); //$NON-NLS-1$
367 
368             startTable();
369             tableHeader(new String[]{
370                   getMessageString("Tagreference.attribute.name"), getMessageString("Tagreference.attribute.description"), getMessageString("Tagreference.attribute.type")}); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
371 
372             for (TagAttribute attribute : attributes)
373             {
374                 sink.tableRow();
375 
376                 sink.tableCell();
377                 if (attribute.isDeprecated())
378                 {
379                     sink.italic();
380                 }
381                 if (attribute.isRequired())
382                 {
383                     sink.bold();
384                 }
385                 sink.text(attribute.getName());
386                 if (attribute.isRequired())
387                 {
388                     sink.text(getMessageString("Tagreference.required.marker")); //$NON-NLS-1$
389                     sink.bold_();
390                 }
391                 if (attribute.isDeprecated())
392                 {
393                     sink.italic_();
394                 }
395                 sink.tableCell_();
396 
397                 sink.tableCell();
398                 if (attribute.isDeprecated() || StringUtils.isBlank(attribute.getDescription()))
399                 {
400                     sink.italic();
401                 }
402 
403                 if (StringUtils.isBlank(attribute.getDescription()))
404                 {
405                     sink.text(getMessageString("Tagreference.required.marker"));
406                 }
407                 else if (parseHtml)
408                 {
409                     parseHtml(attribute.getDescription());
410                 }
411                 else
412                 {
413                     sink.text(attribute.getDescription());
414                 }
415                 if (attribute.isDeprecated() || StringUtils.isBlank(attribute.getDescription()))
416                 {
417                     sink.italic_();
418                 }
419                 sink.tableCell_();
420 
421                 tableCell(StringUtils.defaultIfEmpty(
422                     StringUtils.substringBefore(attribute.getType(), "java.lang."), "String")); //$NON-NLS-1$ //$NON-NLS-2$
423 
424                 sink.tableRow_();
425 
426             }
427 
428             endTable();
429 
430             endSection();
431         }
432         else
433         {
434             paragraph(getMessageString("Tagreference.noattributes")); //$NON-NLS-1$
435         }
436 
437         // attributes
438         TagVariable[] variables = tag.getVariables();
439 
440         if (variables != null && variables.length > 0)
441         {
442             startSection(getMessageString("Tagreference.variables")); //$NON-NLS-1$
443 
444             startTable();
445             tableHeader(new String[]{
446                 getMessageString("Tagreference.variable.name"), getMessageString("Tagreference.variable.type"), getMessageString("Tagreference.variable.scope"), getMessageString("Tagreference.variable.description")}); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
447 
448             for (TagVariable variable : variables)
449             {
450                 sink.tableRow();
451 
452                 sink.tableCell();
453                 if (variable.isDeprecated())
454                 {
455                     sink.italic();
456                 }
457 
458                 if (variable.getNameGiven() != null)
459                 {
460                     sink.text(variable.getNameGiven());
461                     sink.text(getMessageString("Tagreference.variable.constant")); //$NON-NLS-1$
462                 }
463                 else
464                 {
465                     sink.text(getMessageString("Tagreference.variable.specifiedvia") + ' '); //$NON-NLS-1$
466                     sink.text(variable.getNameFromAttribute());
467                 }
468 
469                 if (variable.isDeprecated())
470                 {
471                     sink.italic_();
472                 }
473                 sink.tableCell_();
474 
475                 tableCell(StringUtils.defaultIfEmpty(StringUtils.substringBefore(variable.getType(), "java.lang."), //$NON-NLS-1$
476                     "String")); //$NON-NLS-1$
477 
478                 tableCell(variable.getScope());
479 
480                 sink.tableCell();
481                 if (variable.isDeprecated())
482                 {
483                     sink.italic();
484                 }
485                 if (parseHtml)
486                 {
487                     parseHtml(variable.getDescription());
488                 }
489                 else
490                 {
491                     sink.text(variable.getDescription());
492                 }
493                 if (variable.isDeprecated())
494                 {
495                     sink.italic_();
496                 }
497                 sink.tableCell_();
498 
499                 sink.tableRow_();
500 
501             }
502 
503             endTable();
504 
505             endSection();
506         }
507 
508         endSection();
509 
510     }
511 
512     /**
513      * Checks a single tag and returns validation results.
514      * @param tag Tag
515      */
516     private void doTagFile(String prefix, TagFile tag)
517     {
518         sink.anchor(prefix + ":" + tag.getName());
519         sink.anchor_();
520 
521         // new subsection for each tag
522         startSection("<" + prefix + ":" + tag.getName() + ">"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
523         if (parseHtml)
524         {
525             parseHtml(tag.getDescription());
526         }
527         else
528         {
529             sink.paragraph();
530             sink.text(tag.getDescription());
531             sink.paragraph_();
532         }
533 
534         if (StringUtils.isNotEmpty(tag.getExample()))
535         {
536             startSection(getMessageString("Tagreference.example")); //$NON-NLS-1$
537             verbatimText(tag.getExample());
538             endSection();
539         }
540 
541         endSection();
542 
543     }
544 
545     private void parseHtml(String description)
546     {
547         try
548         {
549             new Xhtml5Parser().parse(new StringReader(OPEN_DIV + description + CLOSE_DIV), sink);
550         }
551         catch (ParseException e)
552         {
553             log.error(description, e);
554         }
555     }
556 
557 }