This is an automated email from the ASF dual-hosted git repository.

kwin pushed a commit to branch feature/improve-javadoc-link-validation
in repository https://gitbox.apache.org/repos/asf/maven-plugin-tools.git

commit d10e78fb3d48aa6de7b44b64e193ef39dffb5e37
Author: Konrad Windszus <[email protected]>
AuthorDate: Wed Oct 26 17:36:39 2022 +0200

    [MPLUGIN-433] Allow to disable link validation
    
    Also validate internal links to javadocs in mojo/parameter description
    and deprecated
---
 .../plugin/plugin/report_old/PluginReport.java     |  9 ++-
 .../maven/plugin/plugin/report/PluginReport.java   | 16 +++-
 .../plugin/generator/PluginXdocGenerator.java      | 87 ++++++++++++++++++----
 .../plugin/generator/PluginXdocGeneratorTest.java  | 19 +++++
 4 files changed, 110 insertions(+), 21 deletions(-)

diff --git 
a/maven-plugin-plugin/src/main/java/org/apache/maven/plugin/plugin/report_old/PluginReport.java
 
b/maven-plugin-plugin/src/main/java/org/apache/maven/plugin/plugin/report_old/PluginReport.java
index de607f09..d3bd6182 100644
--- 
a/maven-plugin-plugin/src/main/java/org/apache/maven/plugin/plugin/report_old/PluginReport.java
+++ 
b/maven-plugin-plugin/src/main/java/org/apache/maven/plugin/plugin/report_old/PluginReport.java
@@ -219,10 +219,11 @@ public class PluginReport
     private File enhancedPluginXmlFile;
 
     /**
-     * In case the internal javadoc site has not been generated (e.g. when 
using an aggregator javadoc report)
-     * link validation needs to be disabled by setting this value to {@code 
true}.
-     * This might have the drawback that some links being generated in the 
report are broken in case not all
-     * parameter types and javadoc link references are resolvable through the 
sites being given to 
+     * In case the internal javadoc site has not been generated when running 
this report goal
+     * (e.g. when using an aggregator javadoc report) link validation needs to 
be disabled by setting
+     * this value to {@code true}.
+     * This might have the drawback that some links being generated in the 
report might be broken
+     * in case not all parameter types and javadoc link references are 
resolvable through the sites being given to
      * {@link DescriptorGeneratorMojo}.
      * 
      * @since 3.7.0
diff --git 
a/maven-plugin-report-plugin/src/main/java/org/apache/maven/plugin/plugin/report/PluginReport.java
 
b/maven-plugin-report-plugin/src/main/java/org/apache/maven/plugin/plugin/report/PluginReport.java
index c865899c..1fc55777 100644
--- 
a/maven-plugin-report-plugin/src/main/java/org/apache/maven/plugin/plugin/report/PluginReport.java
+++ 
b/maven-plugin-report-plugin/src/main/java/org/apache/maven/plugin/plugin/report/PluginReport.java
@@ -215,6 +215,19 @@ public class PluginReport
                 readonly = true )
     private File enhancedPluginXmlFile;
 
+    /**
+     * In case the internal javadoc site has not been generated when running 
this report goal
+     * (e.g. when using an aggregator javadoc report) link validation needs to 
be disabled by setting
+     * this value to {@code true}.
+     * This might have the drawback that some links being generated in the 
report might be broken
+     * in case not all parameter types and javadoc link references are 
resolvable through the sites being given to
+     * goal {@code plugin:descriptor}.
+     * 
+     * @since 3.7.0
+     */
+    @Parameter
+    private boolean disableInternalJavadocLinkValidation;
+
     /**
      * {@inheritDoc}
      */
@@ -317,7 +330,8 @@ public class PluginReport
             File outputDir = outputDirectory;
             outputDir.mkdirs();
 
-            PluginXdocGenerator generator = new PluginXdocGenerator( 
getProject(), locale, getReportOutputDirectory() );
+            PluginXdocGenerator generator = new PluginXdocGenerator( 
getProject(), locale, getReportOutputDirectory(),
+                                                                     
disableInternalJavadocLinkValidation );
             PluginToolsRequest pluginToolsRequest = new 
DefaultPluginToolsRequest( getProject(), pluginDescriptor );
             generator.execute( outputDir, pluginToolsRequest );
         }
diff --git 
a/maven-plugin-tools-generators/src/main/java/org/apache/maven/tools/plugin/generator/PluginXdocGenerator.java
 
b/maven-plugin-tools-generators/src/main/java/org/apache/maven/tools/plugin/generator/PluginXdocGenerator.java
index 2694ad08..7ca8a377 100644
--- 
a/maven-plugin-tools-generators/src/main/java/org/apache/maven/tools/plugin/generator/PluginXdocGenerator.java
+++ 
b/maven-plugin-tools-generators/src/main/java/org/apache/maven/tools/plugin/generator/PluginXdocGenerator.java
@@ -25,12 +25,15 @@ 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;
@@ -43,6 +46,8 @@ 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;
 
@@ -52,6 +57,14 @@ import static java.nio.charset.StandardCharsets.UTF_8;
 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
      */
@@ -93,7 +106,8 @@ public class PluginXdocGenerator
      * @param project not null.
      * @param locale  not null wanted locale.
      */
-    public PluginXdocGenerator( MavenProject project, Locale locale, File 
reportOutputDirectory, boolean disableInternalJavadocLinkValidation )
+    public PluginXdocGenerator( MavenProject project, Locale locale, File 
reportOutputDirectory,
+                                boolean disableInternalJavadocLinkValidation )
     {
         this.project = project;
         if ( locale == null )
@@ -207,13 +221,14 @@ public class PluginXdocGenerator
                            + 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( mojoDescriptor.getDeprecated() );
+            w.writeMarkup( getXhtmlWithValidatedLinks( 
mojoDescriptor.getDeprecated(), context ) );
             w.endElement(); // div
         }
 
@@ -223,7 +238,7 @@ public class PluginXdocGenerator
         w.startElement( "div" );
         if ( StringUtils.isNotEmpty( mojoDescriptor.getDescription() ) )
         {
-            w.writeMarkup( mojoDescriptor.getDescription() );
+            w.writeMarkup( getXhtmlWithValidatedLinks( 
mojoDescriptor.getDescription(), context ) );
         }
         else
         {
@@ -411,8 +426,8 @@ public class PluginXdocGenerator
 
         if ( !list.isEmpty() )
         {
-            writeParameterSummary( list, w );
-            writeParameterDetails( list, w );
+            writeParameterSummary( list, w, mojoDescriptor.getGoal() );
+            writeParameterDetails( list, w, mojoDescriptor.getGoal() );
         }
         else
         {
@@ -460,7 +475,7 @@ public class PluginXdocGenerator
      * @param parameterList  not null
      * @param w              not null
      */
-    private void writeParameterDetails( List<Parameter> parameterList, 
XMLWriter w )
+    private void writeParameterDetails( List<Parameter> parameterList, 
XMLWriter w, String goal )
     {
         w.startElement( "subsection" );
         w.addAttribute( "name", getString( 
"pluginxdoc.mojodescriptor.parameter.details" ) );
@@ -473,17 +488,20 @@ public class PluginXdocGenerator
             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" );
-                w.writeMarkup( format( 
"pluginxdoc.mojodescriptor.parameter.deprecated", parameter.getDeprecated() ) );
+                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( parameter.getDescription() );
+                
+                w.writeMarkup( getXhtmlWithValidatedLinks( 
parameter.getDescription(), context ) );
             }
             else
             {
@@ -616,10 +634,11 @@ public class PluginXdocGenerator
             EnhancedParameterWrapper enhancedParameter = 
(EnhancedParameterWrapper) parameter;
             if ( enhancedParameter.getTypeJavadocUrl() != null )
             {
-                // check if link is valid
                 URI javadocUrl = enhancedParameter.getTypeJavadocUrl();
+                // optionally check if link is valid
                 if ( javadocUrl.isAbsolute() 
-                     || !disableInternalJavadocLinkValidation && 
JavadocLinkGenerator.isLinkValid( javadocUrl, reportOutputDirectory.toPath() ) )
+                     || !disableInternalJavadocLinkValidation 
+                        && JavadocLinkGenerator.isLinkValid( javadocUrl, 
reportOutputDirectory.toPath() ) )
                 {
                     return format( 
"pluginxdoc.mojodescriptor.parameter.type_link",
                                    new Object[] { escapeXml( typeValue ), 
enhancedParameter.getTypeJavadocUrl() } );
@@ -679,20 +698,20 @@ public class PluginXdocGenerator
      * @param parameterList  not null
      * @param w              not null
      */
-    private void writeParameterSummary( List<Parameter> parameterList, 
XMLWriter w )
+    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 );
+                                requiredParams, w, goal );
         }
 
         List<Parameter> optionalParams = getParametersByRequired( false, 
parameterList );
         if ( !optionalParams.isEmpty() )
         {
             writeParameterList( getString( 
"pluginxdoc.mojodescriptor.optionalParameters" ),
-                                optionalParams, w );
+                                optionalParams, w, goal );
         }
     }
 
@@ -701,7 +720,7 @@ public class PluginXdocGenerator
      * @param parameterList  not null
      * @param w              not null
      */
-    private void writeParameterList( String title, List<Parameter> 
parameterList, XMLWriter w )
+    private void writeParameterList( String title, List<Parameter> 
parameterList, XMLWriter w, String goal )
     {
         w.startElement( "subsection" );
         w.addAttribute( "name", title );
@@ -753,13 +772,15 @@ public class PluginXdocGenerator
             // description
             w.startElement( "td" );
             String description;
+            String context = "Parameter " + parameter.getName() + " in goal " 
+ goal;
             if ( StringUtils.isNotEmpty( parameter.getDeprecated() ) )
             {
-                description = format( 
"pluginxdoc.mojodescriptor.parameter.deprecated", parameter.getDeprecated() );
+                String deprecated = getXhtmlWithValidatedLinks( 
parameter.getDescription(), context );
+                description = format( 
"pluginxdoc.mojodescriptor.parameter.deprecated", deprecated );
             }
             else if ( StringUtils.isNotEmpty( parameter.getDescription() ) )
             {
-                description = parameter.getDescription();
+                description = getXhtmlWithValidatedLinks( 
parameter.getDescription(), context );
             }
             else
             {
@@ -886,4 +907,38 @@ public class PluginXdocGenerator
         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();
+    }
 }
diff --git 
a/maven-plugin-tools-generators/src/test/java/org/apache/maven/tools/plugin/generator/PluginXdocGeneratorTest.java
 
b/maven-plugin-tools-generators/src/test/java/org/apache/maven/tools/plugin/generator/PluginXdocGeneratorTest.java
index 05903058..9cab7af3 100644
--- 
a/maven-plugin-tools-generators/src/test/java/org/apache/maven/tools/plugin/generator/PluginXdocGeneratorTest.java
+++ 
b/maven-plugin-tools-generators/src/test/java/org/apache/maven/tools/plugin/generator/PluginXdocGeneratorTest.java
@@ -21,6 +21,7 @@ package org.apache.maven.tools.plugin.generator;
 
 import java.io.File;
 import java.io.InputStream;
+import java.util.Locale;
 
 import org.codehaus.plexus.util.ReaderFactory;
 import org.codehaus.plexus.util.xml.Xpp3Dom;
@@ -63,4 +64,22 @@ public class PluginXdocGeneratorTest
         assertEquals("Map<String,Integer>", PluginXdocGenerator.getShortType( 
"java.util.Map<java.lang.String,java.lang.Integer>" ) );
         assertEquals("List<...>", PluginXdocGenerator.getShortType( 
"java.util.List<java.util.List<java.lang.String>>" ) );
     }
+
+    @Test
+    void testGetXhtmlWithValidatedLinks()
+    {
+        File baseDir = new File( this.getClass().getResource( "" ).getFile() );
+        PluginXdocGenerator xdocGenerator = new PluginXdocGenerator( null, 
Locale.ROOT, baseDir, false );
+        PluginXdocGenerator xdocGeneratorWithDisabledLinkValidator = new 
PluginXdocGenerator( null, Locale.ROOT, baseDir, true );
+        String externalLink = "test<a 
href=\"http://example.com/test\";>External Link</a>..and a second<a 
href=\"http://localhost/example\";>link</a>end";
+        assertEquals( externalLink, xdocGenerator.getXhtmlWithValidatedLinks( 
externalLink, "test" ) );
+        assertEquals( externalLink, 
xdocGeneratorWithDisabledLinkValidator.getXhtmlWithValidatedLinks( 
externalLink, "test" ) );
+        String validInternalLink = "test<a 
href=\"./PluginXDocGeneratorTest.class\">Internal Link</a>..and a second<a 
href=\"http://localhost/example\";>link</a>end";
+        assertEquals( validInternalLink, 
xdocGenerator.getXhtmlWithValidatedLinks( validInternalLink, "test" ) );
+        assertEquals( validInternalLink, 
xdocGeneratorWithDisabledLinkValidator.getXhtmlWithValidatedLinks( 
validInternalLink, "test" ) );
+        String invalidInternalLink = "test<a 
href=\"./PluginXDocGeneratorTestinvalid.class\">Internal Link</a>..and a 
second<a href=\"http://localhost/example\";>link</a>end";
+        String sanitizedInvalidInternalLink = "testInternal Link..and a 
second<a href=\"http://localhost/example\";>link</a>end";
+        assertEquals( sanitizedInvalidInternalLink, 
xdocGenerator.getXhtmlWithValidatedLinks( invalidInternalLink, "test" ) );
+        assertEquals( invalidInternalLink, 
xdocGeneratorWithDisabledLinkValidator.getXhtmlWithValidatedLinks( 
invalidInternalLink, "test" ) );
+    }
 }

Reply via email to