| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.maven.tools.plugin.generator; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.io.OutputStreamWriter; |
| import java.io.PrintWriter; |
| import java.io.Writer; |
| import java.net.URI; |
| import java.net.URISyntaxException; |
| import java.text.MessageFormat; |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Locale; |
| import java.util.ResourceBundle; |
| import java.util.regex.Matcher; |
| import java.util.regex.Pattern; |
| |
| import org.apache.maven.plugin.descriptor.MojoDescriptor; |
| import org.apache.maven.plugin.descriptor.Parameter; |
| import org.apache.maven.project.MavenProject; |
| import org.apache.maven.tools.plugin.EnhancedParameterWrapper; |
| import org.apache.maven.tools.plugin.ExtendedMojoDescriptor; |
| import org.apache.maven.tools.plugin.PluginToolsRequest; |
| import org.apache.maven.tools.plugin.javadoc.JavadocLinkGenerator; |
| import org.codehaus.plexus.util.StringUtils; |
| import org.codehaus.plexus.util.io.CachingOutputStream; |
| import org.codehaus.plexus.util.xml.PrettyPrintXMLWriter; |
| import org.codehaus.plexus.util.xml.XMLWriter; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import static java.nio.charset.StandardCharsets.UTF_8; |
| |
| /** |
| * Generate <a href="https://maven.apache.org/doxia/references/xdoc-format.html">xdoc documentation</a> for each mojo. |
| */ |
| public class PluginXdocGenerator implements Generator { |
| /** |
| * Regular expression matching an XHTML link |
| * group 1 = link target, group 2 = link label |
| */ |
| private static final Pattern HTML_LINK_PATTERN = Pattern.compile("<a href=\\\"([^\\\"]*)\\\">(.*?)</a>"); |
| |
| private static final Logger LOG = LoggerFactory.getLogger(PluginXdocGenerator.class); |
| |
| /** |
| * locale |
| */ |
| private final Locale locale; |
| |
| /** |
| * project |
| */ |
| private final MavenProject project; |
| |
| /** |
| * The directory where the generated site is written. |
| * Used for resolving relative links to javadoc. |
| */ |
| private final File reportOutputDirectory; |
| |
| private final boolean disableInternalJavadocLinkValidation; |
| |
| /** |
| * Default constructor using <code>Locale.ENGLISH</code> as locale. |
| * Used only in test cases. |
| */ |
| public PluginXdocGenerator() { |
| this(null); |
| } |
| |
| /** |
| * Constructor using <code>Locale.ENGLISH</code> as locale. |
| * |
| * @param project not null Maven project. |
| */ |
| public PluginXdocGenerator(MavenProject project) { |
| this(project, Locale.ENGLISH, new File("").getAbsoluteFile(), false); |
| } |
| |
| /** |
| * @param project not null. |
| * @param locale not null. |
| */ |
| public PluginXdocGenerator( |
| MavenProject project, |
| Locale locale, |
| File reportOutputDirectory, |
| boolean disableInternalJavadocLinkValidation) { |
| this.project = project; |
| this.locale = locale; |
| this.reportOutputDirectory = reportOutputDirectory; |
| this.disableInternalJavadocLinkValidation = disableInternalJavadocLinkValidation; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public void execute(File destinationDirectory, PluginToolsRequest request) throws GeneratorException { |
| try { |
| if (request.getPluginDescriptor().getMojos() != null) { |
| List<MojoDescriptor> mojos = request.getPluginDescriptor().getMojos(); |
| for (MojoDescriptor descriptor : mojos) { |
| processMojoDescriptor(descriptor, destinationDirectory); |
| } |
| } |
| } catch (IOException e) { |
| throw new GeneratorException(e.getMessage(), e); |
| } |
| } |
| |
| /** |
| * @param mojoDescriptor not null |
| * @param destinationDirectory not null |
| * @throws IOException if any |
| */ |
| protected void processMojoDescriptor(MojoDescriptor mojoDescriptor, File destinationDirectory) throws IOException { |
| File outputFile = new File(destinationDirectory, getMojoFilename(mojoDescriptor, "xml")); |
| try (Writer writer = new OutputStreamWriter(new CachingOutputStream(outputFile), UTF_8)) { |
| XMLWriter w = new PrettyPrintXMLWriter(new PrintWriter(writer), UTF_8.name(), null); |
| writeBody(mojoDescriptor, w); |
| |
| writer.flush(); |
| } |
| } |
| |
| /** |
| * @param mojo not null |
| * @param ext not null |
| * @return the output file name |
| */ |
| private String getMojoFilename(MojoDescriptor mojo, String ext) { |
| return mojo.getGoal() + "-mojo." + ext; |
| } |
| |
| /** |
| * @param mojoDescriptor not null |
| * @param w not null |
| */ |
| private void writeBody(MojoDescriptor mojoDescriptor, XMLWriter w) { |
| w.startElement("document"); |
| w.addAttribute("xmlns", "http://maven.apache.org/XDOC/2.0"); |
| w.addAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); |
| w.addAttribute( |
| "xsi:schemaLocation", "http://maven.apache.org/XDOC/2.0 http://maven.apache.org/xsd/xdoc-2.0.xsd"); |
| |
| // ---------------------------------------------------------------------- |
| // |
| // ---------------------------------------------------------------------- |
| |
| w.startElement("properties"); |
| |
| w.startElement("title"); |
| w.writeText(mojoDescriptor.getFullGoalName()); |
| w.endElement(); // title |
| |
| w.endElement(); // properties |
| |
| // ---------------------------------------------------------------------- |
| // |
| // ---------------------------------------------------------------------- |
| |
| w.startElement("body"); |
| |
| w.startElement("section"); |
| |
| w.addAttribute("name", mojoDescriptor.getFullGoalName()); |
| |
| writeReportNotice(mojoDescriptor, w); |
| |
| w.startElement("p"); |
| w.writeMarkup(getString("pluginxdoc.mojodescriptor.fullname")); |
| w.endElement(); // p |
| w.startElement("p"); |
| w.writeMarkup(mojoDescriptor.getPluginDescriptor().getGroupId() + ":" |
| + mojoDescriptor.getPluginDescriptor().getArtifactId() + ":" |
| + mojoDescriptor.getPluginDescriptor().getVersion() + ":" + mojoDescriptor.getGoal()); |
| w.endElement(); // p |
| |
| String context = "goal " + mojoDescriptor.getGoal(); |
| if (StringUtils.isNotEmpty(mojoDescriptor.getDeprecated())) { |
| w.startElement("p"); |
| w.writeMarkup(getString("pluginxdoc.mojodescriptor.deprecated")); |
| w.endElement(); // p |
| w.startElement("div"); |
| w.writeMarkup(getXhtmlWithValidatedLinks(mojoDescriptor.getDeprecated(), context)); |
| w.endElement(); // div |
| } |
| |
| w.startElement("p"); |
| w.writeMarkup(getString("pluginxdoc.description")); |
| w.endElement(); // p |
| w.startElement("div"); |
| if (StringUtils.isNotEmpty(mojoDescriptor.getDescription())) { |
| w.writeMarkup(getXhtmlWithValidatedLinks(mojoDescriptor.getDescription(), context)); |
| } else { |
| w.writeText(getString("pluginxdoc.nodescription")); |
| } |
| w.endElement(); // div |
| |
| writeGoalAttributes(mojoDescriptor, w); |
| |
| writeGoalParameterTable(mojoDescriptor, w); |
| |
| w.endElement(); // section |
| |
| w.endElement(); // body |
| |
| w.endElement(); // document |
| } |
| |
| /** |
| * @param mojoDescriptor not null |
| * @param w not null |
| */ |
| private void writeReportNotice(MojoDescriptor mojoDescriptor, XMLWriter w) { |
| if (GeneratorUtils.isMavenReport(mojoDescriptor.getImplementation(), project)) { |
| w.startElement("p"); |
| w.writeMarkup(getString("pluginxdoc.mojodescriptor.notice.note")); |
| w.writeText(getString("pluginxdoc.mojodescriptor.notice.isMavenReport")); |
| w.endElement(); // p |
| } |
| } |
| |
| /** |
| * @param mojoDescriptor not null |
| * @param w not null |
| */ |
| private void writeGoalAttributes(MojoDescriptor mojoDescriptor, XMLWriter w) { |
| w.startElement("p"); |
| w.writeMarkup(getString("pluginxdoc.mojodescriptor.attributes")); |
| w.endElement(); // p |
| |
| boolean addedUl = false; |
| String value; |
| if (mojoDescriptor.isProjectRequired()) { |
| addedUl = addUl(w, addedUl); |
| w.startElement("li"); |
| w.writeMarkup(getString("pluginxdoc.mojodescriptor.projectRequired")); |
| w.endElement(); // li |
| } |
| |
| if (mojoDescriptor.isRequiresReports()) { |
| addedUl = addUl(w, addedUl); |
| w.startElement("li"); |
| w.writeMarkup(getString("pluginxdoc.mojodescriptor.reportingMojo")); |
| w.endElement(); // li |
| } |
| |
| if (mojoDescriptor.isAggregator()) { |
| addedUl = addUl(w, addedUl); |
| w.startElement("li"); |
| w.writeMarkup(getString("pluginxdoc.mojodescriptor.aggregator")); |
| w.endElement(); // li |
| } |
| |
| if (mojoDescriptor.isDirectInvocationOnly()) { |
| addedUl = addUl(w, addedUl); |
| w.startElement("li"); |
| w.writeMarkup(getString("pluginxdoc.mojodescriptor.directInvocationOnly")); |
| w.endElement(); // li |
| } |
| |
| value = mojoDescriptor.isDependencyResolutionRequired(); |
| if (value != null && !value.isEmpty()) { |
| addedUl = addUl(w, addedUl); |
| w.startElement("li"); |
| w.writeMarkup(format("pluginxdoc.mojodescriptor.dependencyResolutionRequired", value)); |
| w.endElement(); // li |
| } |
| |
| if (mojoDescriptor instanceof ExtendedMojoDescriptor) { |
| ExtendedMojoDescriptor extendedMojoDescriptor = (ExtendedMojoDescriptor) mojoDescriptor; |
| |
| value = extendedMojoDescriptor.getDependencyCollectionRequired(); |
| if (value != null && !value.isEmpty()) { |
| addedUl = addUl(w, addedUl); |
| w.startElement("li"); |
| w.writeMarkup(format("pluginxdoc.mojodescriptor.dependencyCollectionRequired", value)); |
| w.endElement(); // li |
| } |
| } |
| |
| addedUl = addUl(w, addedUl); |
| w.startElement("li"); |
| w.writeMarkup(getString( |
| mojoDescriptor.isThreadSafe() |
| ? "pluginxdoc.mojodescriptor.threadSafe" |
| : "pluginxdoc.mojodescriptor.notThreadSafe")); |
| w.endElement(); // li |
| |
| value = mojoDescriptor.getSince(); |
| if (value != null && !value.isEmpty()) { |
| addedUl = addUl(w, addedUl); |
| w.startElement("li"); |
| w.writeMarkup(format("pluginxdoc.mojodescriptor.since", value)); |
| w.endElement(); // li |
| } |
| |
| value = mojoDescriptor.getPhase(); |
| if (value != null && !value.isEmpty()) { |
| addedUl = addUl(w, addedUl); |
| w.startElement("li"); |
| w.writeMarkup(format("pluginxdoc.mojodescriptor.phase", value)); |
| w.endElement(); // li |
| } |
| |
| value = mojoDescriptor.getExecutePhase(); |
| if (value != null && !value.isEmpty()) { |
| addedUl = addUl(w, addedUl); |
| w.startElement("li"); |
| w.writeMarkup(format("pluginxdoc.mojodescriptor.executePhase", value)); |
| w.endElement(); // li |
| } |
| |
| value = mojoDescriptor.getExecuteGoal(); |
| if (value != null && !value.isEmpty()) { |
| addedUl = addUl(w, addedUl); |
| w.startElement("li"); |
| w.writeMarkup(format("pluginxdoc.mojodescriptor.executeGoal", value)); |
| w.endElement(); // li |
| } |
| |
| value = mojoDescriptor.getExecuteLifecycle(); |
| if (value != null && !value.isEmpty()) { |
| addedUl = addUl(w, addedUl); |
| w.startElement("li"); |
| w.writeMarkup(format("pluginxdoc.mojodescriptor.executeLifecycle", value)); |
| w.endElement(); // li |
| } |
| |
| if (mojoDescriptor.isOnlineRequired()) { |
| addedUl = addUl(w, addedUl); |
| w.startElement("li"); |
| w.writeMarkup(getString("pluginxdoc.mojodescriptor.onlineRequired")); |
| w.endElement(); // li |
| } |
| |
| if (!mojoDescriptor.isInheritedByDefault()) { |
| addedUl = addUl(w, addedUl); |
| w.startElement("li"); |
| w.writeMarkup(getString("pluginxdoc.mojodescriptor.inheritedByDefault")); |
| w.endElement(); // li |
| } |
| |
| if (addedUl) { |
| w.endElement(); // ul |
| } |
| } |
| |
| /** |
| * @param mojoDescriptor not null |
| * @param w not null |
| */ |
| private void writeGoalParameterTable(MojoDescriptor mojoDescriptor, XMLWriter w) { |
| List<Parameter> parameterList = mojoDescriptor.getParameters(); |
| |
| // remove components and read-only parameters |
| List<Parameter> list = filterParameters(parameterList); |
| |
| if (!list.isEmpty()) { |
| writeParameterSummary(list, w, mojoDescriptor.getGoal()); |
| writeParameterDetails(list, w, mojoDescriptor.getGoal()); |
| } else { |
| w.startElement("subsection"); |
| w.addAttribute("name", getString("pluginxdoc.mojodescriptor.parameters")); |
| |
| w.startElement("p"); |
| w.writeMarkup(getString("pluginxdoc.mojodescriptor.noParameter")); |
| w.endElement(); // p |
| |
| w.endElement(); |
| } |
| } |
| |
| /** |
| * Filter parameters to only retain those which must be documented, i.e. neither components nor readonly. |
| * |
| * @param parameterList not null |
| * @return the parameters list without components. |
| */ |
| private List<Parameter> filterParameters(List<Parameter> parameterList) { |
| List<Parameter> filtered = new ArrayList<>(); |
| |
| if (parameterList != null) { |
| for (Parameter parameter : parameterList) { |
| if (parameter.isEditable()) { |
| String expression = parameter.getExpression(); |
| |
| if (expression == null || !expression.startsWith("${component.")) { |
| filtered.add(parameter); |
| } |
| } |
| } |
| } |
| |
| return filtered; |
| } |
| |
| /** |
| * @param parameterList not null |
| * @param w not null |
| */ |
| private void writeParameterDetails(List<Parameter> parameterList, XMLWriter w, String goal) { |
| w.startElement("subsection"); |
| w.addAttribute("name", getString("pluginxdoc.mojodescriptor.parameter.details")); |
| |
| for (Iterator<Parameter> parameters = parameterList.iterator(); parameters.hasNext(); ) { |
| Parameter parameter = parameters.next(); |
| |
| w.startElement("h4"); |
| w.writeMarkup(format("pluginxdoc.mojodescriptor.parameter.name_internal", parameter.getName())); |
| w.endElement(); |
| |
| String context = "Parameter " + parameter.getName() + " in goal " + goal; |
| if (StringUtils.isNotEmpty(parameter.getDeprecated())) { |
| w.startElement("div"); |
| String deprecated = getXhtmlWithValidatedLinks(parameter.getDeprecated(), context); |
| w.writeMarkup(format("pluginxdoc.mojodescriptor.parameter.deprecated", deprecated)); |
| w.endElement(); // div |
| } |
| |
| w.startElement("div"); |
| if (StringUtils.isNotEmpty(parameter.getDescription())) { |
| w.writeMarkup(getXhtmlWithValidatedLinks(parameter.getDescription(), context)); |
| } else { |
| w.writeMarkup(getString("pluginxdoc.nodescription")); |
| } |
| w.endElement(); // div |
| |
| boolean addedUl = false; |
| addedUl = addUl(w, addedUl, parameter.getType()); |
| String typeValue = getLinkedType(parameter, false); |
| writeDetail(getString("pluginxdoc.mojodescriptor.parameter.type"), typeValue, w); |
| |
| if (StringUtils.isNotEmpty(parameter.getSince())) { |
| addedUl = addUl(w, addedUl); |
| writeDetail(getString("pluginxdoc.mojodescriptor.parameter.since"), parameter.getSince(), w); |
| } |
| |
| if (parameter.isRequired()) { |
| addedUl = addUl(w, addedUl); |
| writeDetail(getString("pluginxdoc.mojodescriptor.parameter.required"), getString("pluginxdoc.yes"), w); |
| } else { |
| addedUl = addUl(w, addedUl); |
| writeDetail(getString("pluginxdoc.mojodescriptor.parameter.required"), getString("pluginxdoc.no"), w); |
| } |
| |
| String expression = parameter.getExpression(); |
| addedUl = addUl(w, addedUl, expression); |
| String property = getPropertyFromExpression(expression); |
| if (property == null) { |
| writeDetail(getString("pluginxdoc.mojodescriptor.parameter.expression"), expression, w); |
| } else { |
| writeDetail(getString("pluginxdoc.mojodescriptor.parameter.property"), property, w); |
| } |
| |
| addedUl = addUl(w, addedUl, parameter.getDefaultValue()); |
| writeDetail( |
| getString("pluginxdoc.mojodescriptor.parameter.default"), |
| escapeXml(parameter.getDefaultValue()), |
| w); |
| |
| addedUl = addUl(w, addedUl, parameter.getAlias()); |
| writeDetail(getString("pluginxdoc.mojodescriptor.parameter.alias"), escapeXml(parameter.getAlias()), w); |
| |
| if (addedUl) { |
| w.endElement(); // ul |
| } |
| |
| if (parameters.hasNext()) { |
| w.writeMarkup("<hr/>"); |
| } |
| } |
| |
| w.endElement(); |
| } |
| |
| static String getShortType(String type) { |
| // split into type arguments and main type |
| int startTypeArguments = type.indexOf('<'); |
| if (startTypeArguments == -1) { |
| return getShortTypeOfSimpleType(type); |
| } else { |
| StringBuilder shortType = new StringBuilder(); |
| shortType.append(getShortTypeOfSimpleType(type.substring(0, startTypeArguments))); |
| shortType |
| .append("<") |
| .append(getShortTypeOfTypeArgument(type.substring(startTypeArguments + 1, type.lastIndexOf(">")))) |
| .append(">"); |
| return shortType.toString(); |
| } |
| } |
| |
| private static String getShortTypeOfTypeArgument(String type) { |
| String[] typeArguments = type.split(",\\s*"); |
| StringBuilder shortType = new StringBuilder(); |
| for (int i = 0; i < typeArguments.length; i++) { |
| String typeArgument = typeArguments[i]; |
| if (typeArgument.contains("<")) { |
| // nested type arguments lead to ellipsis |
| return "..."; |
| } else { |
| shortType.append(getShortTypeOfSimpleType(typeArgument)); |
| if (i < typeArguments.length - 1) { |
| shortType.append(","); |
| } |
| } |
| } |
| return shortType.toString(); |
| } |
| |
| private static String getShortTypeOfSimpleType(String type) { |
| int index = type.lastIndexOf('.'); |
| return type.substring(index + 1); |
| } |
| |
| private String getLinkedType(Parameter parameter, boolean isShortType) { |
| final String typeValue; |
| if (isShortType) { |
| typeValue = getShortType(parameter.getType()); |
| } else { |
| typeValue = parameter.getType(); |
| } |
| if (parameter instanceof EnhancedParameterWrapper) { |
| EnhancedParameterWrapper enhancedParameter = (EnhancedParameterWrapper) parameter; |
| if (enhancedParameter.getTypeJavadocUrl() != null) { |
| URI javadocUrl = enhancedParameter.getTypeJavadocUrl(); |
| // optionally check if link is valid |
| if (javadocUrl.isAbsolute() |
| || disableInternalJavadocLinkValidation |
| || JavadocLinkGenerator.isLinkValid(javadocUrl, reportOutputDirectory.toPath())) { |
| return format( |
| "pluginxdoc.mojodescriptor.parameter.type_link", |
| new Object[] {escapeXml(typeValue), enhancedParameter.getTypeJavadocUrl()}); |
| } |
| } |
| } |
| return escapeXml(typeValue); |
| } |
| |
| private boolean addUl(XMLWriter w, boolean addedUl, String content) { |
| if (content != null && !content.isEmpty()) { |
| return addUl(w, addedUl); |
| } |
| return addedUl; |
| } |
| |
| private boolean addUl(XMLWriter w, boolean addedUl) { |
| if (!addedUl) { |
| w.startElement("ul"); |
| addedUl = true; |
| } |
| return addedUl; |
| } |
| |
| private String getPropertyFromExpression(String expression) { |
| if ((expression != null && !expression.isEmpty()) |
| && expression.startsWith("${") |
| && expression.endsWith("}") |
| && !expression.substring(2).contains("${")) { |
| // expression="${xxx}" -> property="xxx" |
| return expression.substring(2, expression.length() - 1); |
| } |
| // no property can be extracted |
| return null; |
| } |
| |
| /** |
| * @param param not null |
| * @param value could be null |
| * @param w not null |
| */ |
| private void writeDetail(String param, String value, XMLWriter w) { |
| if (value != null && !value.isEmpty()) { |
| w.startElement("li"); |
| w.writeMarkup(format("pluginxdoc.detail", new String[] {param, value})); |
| w.endElement(); // li |
| } |
| } |
| |
| /** |
| * @param parameterList not null |
| * @param w not null |
| */ |
| private void writeParameterSummary(List<Parameter> parameterList, XMLWriter w, String goal) { |
| List<Parameter> requiredParams = getParametersByRequired(true, parameterList); |
| if (!requiredParams.isEmpty()) { |
| writeParameterList(getString("pluginxdoc.mojodescriptor.requiredParameters"), requiredParams, w, goal); |
| } |
| |
| List<Parameter> optionalParams = getParametersByRequired(false, parameterList); |
| if (!optionalParams.isEmpty()) { |
| writeParameterList(getString("pluginxdoc.mojodescriptor.optionalParameters"), optionalParams, w, goal); |
| } |
| } |
| |
| /** |
| * @param title not null |
| * @param parameterList not null |
| * @param w not null |
| */ |
| private void writeParameterList(String title, List<Parameter> parameterList, XMLWriter w, String goal) { |
| w.startElement("subsection"); |
| w.addAttribute("name", title); |
| |
| w.startElement("table"); |
| w.addAttribute("border", "0"); |
| w.addAttribute("class", "bodyTable"); |
| |
| w.startElement("tr"); |
| w.startElement("th"); |
| w.writeText(getString("pluginxdoc.mojodescriptor.parameter.name")); |
| w.endElement(); // th |
| w.startElement("th"); |
| w.writeText(getString("pluginxdoc.mojodescriptor.parameter.type")); |
| w.endElement(); // th |
| w.startElement("th"); |
| w.writeText(getString("pluginxdoc.mojodescriptor.parameter.since")); |
| w.endElement(); // th |
| w.startElement("th"); |
| w.writeText(getString("pluginxdoc.mojodescriptor.parameter.description")); |
| w.endElement(); // th |
| w.endElement(); // tr |
| |
| for (Parameter parameter : parameterList) { |
| w.startElement("tr"); |
| |
| // name |
| w.startElement("td"); |
| w.writeMarkup(format("pluginxdoc.mojodescriptor.parameter.name_link", parameter.getName())); |
| w.endElement(); // td |
| |
| // type |
| w.startElement("td"); |
| w.writeMarkup("<code>" + getLinkedType(parameter, true) + "</code>"); |
| w.endElement(); // td |
| |
| // since |
| w.startElement("td"); |
| if (StringUtils.isNotEmpty(parameter.getSince())) { |
| w.writeMarkup("<code>" + parameter.getSince() + "</code>"); |
| } else { |
| w.writeMarkup("<code>-</code>"); |
| } |
| w.endElement(); // td |
| |
| // description |
| w.startElement("td"); |
| String description; |
| String context = "Parameter " + parameter.getName() + " in goal " + goal; |
| if (StringUtils.isNotEmpty(parameter.getDeprecated())) { |
| String deprecated = getXhtmlWithValidatedLinks(parameter.getDescription(), context); |
| description = format("pluginxdoc.mojodescriptor.parameter.deprecated", deprecated); |
| } else if (StringUtils.isNotEmpty(parameter.getDescription())) { |
| description = getXhtmlWithValidatedLinks(parameter.getDescription(), context); |
| } else { |
| description = getString("pluginxdoc.nodescription"); |
| } |
| w.writeMarkup(description + "<br/>"); |
| |
| if (StringUtils.isNotEmpty(parameter.getDefaultValue())) { |
| w.writeMarkup(format( |
| "pluginxdoc.mojodescriptor.parameter.defaultValue", escapeXml(parameter.getDefaultValue()))); |
| w.writeMarkup("<br/>"); |
| } |
| |
| String property = getPropertyFromExpression(parameter.getExpression()); |
| if (property != null) { |
| w.writeMarkup(format("pluginxdoc.mojodescriptor.parameter.property.description", property)); |
| w.writeMarkup("<br/>"); |
| } |
| |
| if (StringUtils.isNotEmpty(parameter.getAlias())) { |
| w.writeMarkup(format( |
| "pluginxdoc.mojodescriptor.parameter.alias.description", escapeXml(parameter.getAlias()))); |
| } |
| |
| w.endElement(); // td |
| w.endElement(); // tr |
| } |
| |
| w.endElement(); // table |
| w.endElement(); // section |
| } |
| |
| /** |
| * @param required <code>true</code> for required parameters, <code>false</code> otherwise. |
| * @param parameterList not null |
| * @return list of parameters depending the value of <code>required</code> |
| */ |
| private List<Parameter> getParametersByRequired(boolean required, List<Parameter> parameterList) { |
| List<Parameter> list = new ArrayList<>(); |
| |
| for (Parameter parameter : parameterList) { |
| if (parameter.isRequired() == required) { |
| list.add(parameter); |
| } |
| } |
| |
| return list; |
| } |
| |
| /** |
| * Gets the resource bundle for the <code>locale</code> instance variable. |
| * |
| * @return The resource bundle for the <code>locale</code> instance variable. |
| */ |
| private ResourceBundle getBundle() { |
| return ResourceBundle.getBundle("pluginxdoc", locale, getClass().getClassLoader()); |
| } |
| |
| /** |
| * @param key not null |
| * @return Localized, text identified by <code>key</code>. |
| * @see #getBundle() |
| */ |
| private String getString(String key) { |
| return getBundle().getString(key); |
| } |
| |
| /** |
| * Convenience method. |
| * |
| * @param key not null |
| * @param arg1 not null |
| * @return Localized, formatted text identified by <code>key</code>. |
| * @see #format(String, Object[]) |
| */ |
| private String format(String key, Object arg1) { |
| return format(key, new Object[] {arg1}); |
| } |
| |
| /** |
| * Looks up the value for <code>key</code> in the <code>ResourceBundle</code>, |
| * then formats that value for the specified <code>Locale</code> using <code>args</code>. |
| * |
| * @param key not null |
| * @param args not null |
| * @return Localized, formatted text identified by <code>key</code>. |
| */ |
| private String format(String key, Object[] args) { |
| String pattern = getString(key); |
| // we don't need quoting so spare us the confusion in the resource bundle to double them up in some keys |
| pattern = StringUtils.replace(pattern, "'", "''"); |
| |
| MessageFormat messageFormat = new MessageFormat(""); |
| messageFormat.setLocale(locale); |
| messageFormat.applyPattern(pattern); |
| |
| return messageFormat.format(args); |
| } |
| |
| /** |
| * @param text the string to escape |
| * @return A string escaped with XML entities |
| */ |
| private String escapeXml(String text) { |
| if (text != null) { |
| text = text.replace("&", "&"); |
| text = text.replace("<", "<"); |
| text = text.replace(">", ">"); |
| text = text.replace("\"", """); |
| text = text.replace("\'", "'"); |
| } |
| return text; |
| } |
| |
| String getXhtmlWithValidatedLinks(String xhtmlText, String context) { |
| if (disableInternalJavadocLinkValidation) { |
| return xhtmlText; |
| } |
| StringBuffer sanitizedXhtmlText = new StringBuffer(); |
| // find all links which are not absolute |
| Matcher matcher = HTML_LINK_PATTERN.matcher(xhtmlText); |
| while (matcher.find()) { |
| URI link; |
| try { |
| link = new URI(matcher.group(1)); |
| if (!link.isAbsolute() && !JavadocLinkGenerator.isLinkValid(link, reportOutputDirectory.toPath())) { |
| matcher.appendReplacement(sanitizedXhtmlText, matcher.group(2)); |
| LOG.debug("Removed invalid link {} in {}", link, context); |
| } else { |
| matcher.appendReplacement(sanitizedXhtmlText, matcher.group(0)); |
| } |
| } catch (URISyntaxException e) { |
| LOG.warn("Invalid URI {} found in {}. Cannot validate, leave untouched", matcher.group(1), context); |
| matcher.appendReplacement(sanitizedXhtmlText, matcher.group(0)); |
| } |
| } |
| matcher.appendTail(sanitizedXhtmlText); |
| return sanitizedXhtmlText.toString(); |
| } |
| } |