TagreferenceRenderer.java
/*
* The MIT License
* Copyright © 2004-2014 Fabrizio Giustina
* Copyright © 2022-2026 Web-Legacy
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package io.github.weblegacy.maven.plugin.taglib;
import io.github.weblegacy.maven.plugin.taglib.checker.ElFunction;
import io.github.weblegacy.maven.plugin.taglib.checker.Tag;
import io.github.weblegacy.maven.plugin.taglib.checker.TagAttribute;
import io.github.weblegacy.maven.plugin.taglib.checker.TagFile;
import io.github.weblegacy.maven.plugin.taglib.checker.TagVariable;
import io.github.weblegacy.maven.plugin.taglib.checker.Tld;
import io.github.weblegacy.maven.plugin.taglib.checker.TldItem;
import java.io.StringReader;
import java.text.MessageFormat;
import java.util.Locale;
import org.apache.commons.lang3.StringUtils;
import org.apache.maven.doxia.module.xhtml5.Xhtml5Parser;
import org.apache.maven.doxia.parser.ParseException;
import org.apache.maven.doxia.sink.Sink;
import org.apache.maven.doxia.util.HtmlTools;
import org.apache.maven.plugin.logging.Log;
/**
* Generates a tag reference xdoc that can be integrated in a maven generated site.
*
* @author Fabrizio Giustina
*/
public class TagreferenceRenderer extends AbstractMavenTaglibReportRenderer {
/**
* Constant for opening HTML-DIV-Tag.
*/
private static final String OPEN_DIV = "<div>";
/**
* Constant for closing HTML-DIV-Tag.
*/
private static final String CLOSE_DIV = "</div>";
/**
* The list of Tld to check.
*/
private final Tld[] tlds;
/**
* {@code True} to parse html in the description of tld info, tags and attributes.
*/
private final boolean parseHtml;
/**
* The logger that has been injected into this mojo.
*/
private final Log log;
/**
* The class-constructor.
*
* @param sink the sink to use.
* @param locale the wanted locale to return the report's description, could be {@code null}.
* @param tlds list of TLDs to check.
* @param parseHtml {@code true} to parse html in the description of tld info, tags and
* attributes.
* @param log the logger that has been injected into this mojo.
*/
public TagreferenceRenderer(Sink sink, Locale locale, Tld[] tlds, boolean parseHtml, Log log) {
super(sink, locale);
this.tlds = tlds;
this.parseHtml = parseHtml;
this.log = log;
}
@Override
public String getTitle() {
return getMessageString("Tagreference.title");
}
@Override
protected void renderBody() {
sink.body();
startSection(getMessageString("Tagreference.h1"));
paragraph(getMessageString("Tagreference.intro"));
sink.list();
for (Tld tld : tlds) {
log.debug("Rendering " + tld.getFilename());
sink.listItem();
sink.link('#' + tld.getFilename());
sink.text(MessageFormat.format(getMessageString("Tagreference.listitem.tld"),
StringUtils.defaultIfEmpty(tld.getName(), tld.getShortname()),
tld.getFilename()));
sink.link_();
sink.text(getMessageString("Tagreference.listitem.uri") + tld.getUri());
sink.listItem_();
}
sink.list_();
endSection();
for (Tld tld : tlds) {
doTld(tld);
sink.pageBreak();
}
sink.body_();
}
/**
* Remove any html-tags.
*
* @param html the html-text
*
* @return text without html-tags
*/
private String stripTags(String html) {
if (html == null) {
return StringUtils.EMPTY;
}
return html.replaceAll("\\<.*?\\>", StringUtils.EMPTY);
}
/**
* Generate report for one tld.
*
* @param tld Tld
*/
private void doTld(Tld tld) {
// new section for each tld
sink.anchor(tld.getFilename());
sink.anchor_();
startSection(StringUtils.defaultIfEmpty(tld.getName(),
tld.getShortname()) + " - "
+ MessageFormat.format(getMessageString("Tagreference.tldversion"),
tld.getTlibversion()));
sink.paragraph();
if (parseHtml) {
parseHtml(tld.getInfo());
} else {
sink.text(tld.getInfo());
}
sink.paragraph_();
sink.paragraph();
sink.bold();
sink.text("Namespace definition:");
sink.bold_();
sink.text(" xmlns:");
sink.text(tld.getShortname());
sink.text("=\"");
sink.text(tld.getUri());
sink.text("\"");
sink.paragraph_();
TldItem[] tags = tld.getTags();
ElFunction[] functions = tld.getFunctions();
TagFile[] tagfiles = tld.getTagfiles();
printList(tld, tags, "Tags");
printList(tld, functions, "EL Functions");
printList(tld, tagfiles, "Tagfiles");
sink.paragraph();
sink.text(getMessageString("Tagreference.intro.required") + ' ');
sink.bold();
sink.text(getMessageString("Tagreference.required.marker"));
sink.bold_();
sink.paragraph_();
if (tags != null) {
for (TldItem tag : tags) {
doTag(tld.getShortname(), (Tag) tag);
}
}
if (functions != null) {
for (ElFunction function : functions) {
doFunction(tld.getShortname(), function);
}
}
if (tagfiles != null) {
for (TagFile tagfile : tagfiles) {
doTagFile(tld.getShortname(), tagfile);
}
}
endSection();
}
/**
* Generate report-part for a function.
*
* @param prefix the prefix of the function
* @param tag the function itself
*/
private void doFunction(String prefix, ElFunction tag) {
sink.anchor(prefix + ":" + tag.getName());
sink.anchor_();
// new subsection for each tag
startSection(prefix + ":" + tag.getName() + "(" + tag.getParameters() + ")");
sink.paragraph();
sink.bold();
sink.text("Function class: ");
sink.bold_();
sink.text(tag.getFunctionClass());
sink.paragraph_();
sink.paragraph();
sink.bold();
sink.text("Function signature: ");
sink.bold_();
sink.text(tag.getFunctionSignature());
sink.paragraph_();
if (parseHtml) {
parseHtml(tag.getDescription());
} else {
sink.paragraph();
sink.text(tag.getDescription());
sink.paragraph_();
}
if (StringUtils.isNotEmpty(tag.getExample())) {
startSection(getMessageString("Tagreference.example"));
verbatimText(tag.getExample());
endSection();
}
endSection();
}
/**
* Generate a list-report of all tags of a tld.
*
* @param tld the tld
* @param tags the items of the tld
* @param intro intro-text for the report
*/
private void printList(Tld tld, TldItem[] tags, String intro) {
if (tags != null && tags.length > 0) {
sink.paragraph();
sink.bold();
sink.text(intro);
sink.bold_();
sink.paragraph_();
sink.list();
for (TldItem tag : tags) {
sink.listItem();
sink.link("#" + tld.getShortname() + ":" + tag.getName());
if (tag.isDeprecated()) {
sink.italic();
}
sink.text(tag.getName());
if (tag instanceof ElFunction) {
sink.text("()");
}
if (tag.isDeprecated()) {
sink.italic_();
}
sink.link_();
sink.text(" ");
String cleanedDescription = stripTags(
StringUtils.substringBefore(tag.getDescription(), ".")) + '.';
if (parseHtml) {
cleanedDescription = HtmlTools.unescapeHTML(cleanedDescription);
}
sink.text(cleanedDescription);
sink.listItem_();
}
sink.list_();
}
}
/**
* Checks a single tag and returns validation results.
*
* @param prefix the prefix of the tag
* @param tag Tag
*/
private void doTag(String prefix, Tag tag) {
sink.anchor(prefix + ":" + tag.getName());
sink.anchor_();
// new subsection for each tag
startSection("<" + prefix + ":" + tag.getName() + ">");
if (parseHtml) {
parseHtml(tag.getDescription());
} else {
sink.paragraph();
sink.text(tag.getDescription());
sink.paragraph_();
}
sink.paragraph();
sink.text(getMessageString("Tagreference.cancontain") + ' ');
sink.text(tag.getBodycontent());
sink.paragraph_();
if (StringUtils.isNotEmpty(tag.getExample())) {
startSection(getMessageString("Tagreference.example"));
verbatimText(tag.getExample());
endSection();
}
// variables
// attributes
TagAttribute[] attributes = tag.getAttributes();
if (attributes != null && attributes.length > 0) {
startSection(getMessageString("Tagreference.attributes"));
startTable();
tableHeader(new String[]{
getMessageString("Tagreference.attribute.name"),
getMessageString("Tagreference.attribute.description"),
getMessageString("Tagreference.attribute.type")
});
for (TagAttribute attribute : attributes) {
sink.tableRow();
sink.tableCell();
if (attribute.isDeprecated()) {
sink.italic();
}
if (attribute.isRequired()) {
sink.bold();
}
sink.text(attribute.getName());
if (attribute.isRequired()) {
sink.text(getMessageString("Tagreference.required.marker"));
sink.bold_();
}
if (attribute.isDeprecated()) {
sink.italic_();
}
sink.tableCell_();
sink.tableCell();
if (attribute.isDeprecated() || StringUtils.isBlank(attribute.getDescription())) {
sink.italic();
}
if (StringUtils.isBlank(attribute.getDescription())) {
sink.text(getMessageString("Tagreference.required.marker"));
} else if (parseHtml) {
parseHtml(attribute.getDescription());
} else {
sink.text(attribute.getDescription());
}
if (attribute.isDeprecated() || StringUtils.isBlank(attribute.getDescription())) {
sink.italic_();
}
sink.tableCell_();
tableCell(StringUtils.defaultIfEmpty(
StringUtils.substringBefore(attribute.getType(), "java.lang."), "String"));
sink.tableRow_();
}
endTable();
endSection();
} else {
paragraph(getMessageString("Tagreference.noattributes"));
}
// attributes
TagVariable[] variables = tag.getVariables();
if (variables != null && variables.length > 0) {
startSection(getMessageString("Tagreference.variables"));
startTable();
tableHeader(new String[]{
getMessageString("Tagreference.variable.name"),
getMessageString("Tagreference.variable.type"),
getMessageString("Tagreference.variable.scope"),
getMessageString("Tagreference.variable.description")
});
for (TagVariable variable : variables) {
sink.tableRow();
sink.tableCell();
if (variable.isDeprecated()) {
sink.italic();
}
if (variable.getNameGiven() != null) {
sink.text(variable.getNameGiven());
sink.text(getMessageString("Tagreference.variable.constant"));
} else {
sink.text(getMessageString("Tagreference.variable.specifiedvia") + ' ');
sink.text(variable.getNameFromAttribute());
}
if (variable.isDeprecated()) {
sink.italic_();
}
sink.tableCell_();
tableCell(StringUtils.defaultIfEmpty(
StringUtils.substringBefore(variable.getType(), "java.lang."), "String"));
tableCell(variable.getScope());
sink.tableCell();
if (variable.isDeprecated()) {
sink.italic();
}
if (parseHtml) {
parseHtml(variable.getDescription());
} else {
sink.text(variable.getDescription());
}
if (variable.isDeprecated()) {
sink.italic_();
}
sink.tableCell_();
sink.tableRow_();
}
endTable();
endSection();
}
endSection();
}
/**
* Checks a single tag and returns validation results.
*
* @param prefix the prefix of the function
* @param tag Tag
*/
private void doTagFile(String prefix, TagFile tag) {
sink.anchor(prefix + ":" + tag.getName());
sink.anchor_();
// new subsection for each tag
startSection("<" + prefix + ":" + tag.getName() + ">");
if (parseHtml) {
parseHtml(tag.getDescription());
} else {
sink.paragraph();
sink.text(tag.getDescription());
sink.paragraph_();
}
if (StringUtils.isNotEmpty(tag.getExample())) {
startSection(getMessageString("Tagreference.example"));
verbatimText(tag.getExample());
endSection();
}
endSection();
}
/**
* Writes the description to the report and checks for valid html-code.
*
* @param description the description
*/
private void parseHtml(String description) {
try {
new Xhtml5Parser().parse(new StringReader(OPEN_DIV + description + CLOSE_DIV), sink);
} catch (ParseException e) {
log.error(description, e);
}
}
}