You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by gb...@apache.org on 2018/02/24 19:48:13 UTC
[maven-javadoc-plugin] 01/01: [MJAVADOC-427] "Error fetching URL"
for valid non-Java API links
This is an automated email from the ASF dual-hosted git repository.
gboue pushed a commit to branch MJAVADOC-427
in repository https://gitbox.apache.org/repos/asf/maven-javadoc-plugin.git
commit 0ade0576e8a294459153161a3d5071814e588dcd
Author: Guillaume Boué <gb...@apache.org>
AuthorDate: Sat Feb 24 20:23:16 2018 +0100
[MJAVADOC-427] "Error fetching URL" for valid non-Java API links
javadoc tool currently doesn't follow redirects for -link URLs, so we
follow them ourselves and pass the last redirect location to javadoc.
---
src/it/projects/MJAVADOC-325/verify.bsh | 2 +-
src/it/projects/MJAVADOC-427/invoker.properties | 21 ++++++
src/it/projects/MJAVADOC-427/pom.xml | 61 ++++++++++++++++
.../src/main/java/mjavadoc427/App.java} | 77 +++++++++-----------
.../verify.bsh => MJAVADOC-427/verify.groovy} | 68 +++++++-----------
src/it/projects/detectLinks/verify.bsh | 8 +--
.../maven/plugins/javadoc/AbstractJavadocMojo.java | 27 ++++++-
.../apache/maven/plugins/javadoc/JavadocUtil.java | 45 ++++++++++++
.../maven/plugins/javadoc/JavadocUtilTest.java | 84 ++++++++++++++++++++++
9 files changed, 303 insertions(+), 90 deletions(-)
diff --git a/src/it/projects/MJAVADOC-325/verify.bsh b/src/it/projects/MJAVADOC-325/verify.bsh
index 7c4ce44..3c60e6c 100644
--- a/src/it/projects/MJAVADOC-325/verify.bsh
+++ b/src/it/projects/MJAVADOC-325/verify.bsh
@@ -30,7 +30,7 @@ if ( !optionsFile.exists() )
}
String optionsContent = FileUtils.fileRead( optionsFile );
-String javaApiLink = "'http://docs.oracle.com/javase/1,5,0/docs/api'";
+String javaApiLink = "'https://docs.oracle.com/javase/1.5.0/docs/api'";
if ( !optionsContent.contains( javaApiLink ) )
{
diff --git a/src/it/projects/MJAVADOC-427/invoker.properties b/src/it/projects/MJAVADOC-427/invoker.properties
new file mode 100644
index 0000000..aee4e3b
--- /dev/null
+++ b/src/it/projects/MJAVADOC-427/invoker.properties
@@ -0,0 +1,21 @@
+# 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.
+
+invoker.goals=clean javadoc:javadoc
+
+# slf4j javadoc is hosted on https site with a "let's encrypt" certificate, signed by IdenTrust only trusted since 8u101 (JDK-8154757)
+invoker.java.version = 1.8.0.101+
diff --git a/src/it/projects/MJAVADOC-427/pom.xml b/src/it/projects/MJAVADOC-427/pom.xml
new file mode 100644
index 0000000..bf7a406
--- /dev/null
+++ b/src/it/projects/MJAVADOC-427/pom.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ 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.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.apache.maven.plugins.maven-javadoc-plugin.it</groupId>
+ <artifactId>mjavadoc-427</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ <packaging>jar</packaging>
+ <url>https://issues.apache.org/jira/browse/MJAVADOC-427</url>
+ <description>Tests that the plugin follows redirects</description>
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+
+ <dependencies>
+ <!-- url of slf4j api is http, and javadoc is redirected to https -->
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <version>1.7.12</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <version>@pom.version@</version>
+ <configuration>
+ <detectLinks>true</detectLinks>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+
+</project>
diff --git a/src/it/projects/MJAVADOC-325/verify.bsh b/src/it/projects/MJAVADOC-427/src/main/java/mjavadoc427/App.java
similarity index 57%
copy from src/it/projects/MJAVADOC-325/verify.bsh
copy to src/it/projects/MJAVADOC-427/src/main/java/mjavadoc427/App.java
index 7c4ce44..75194f3 100644
--- a/src/it/projects/MJAVADOC-325/verify.bsh
+++ b/src/it/projects/MJAVADOC-427/src/main/java/mjavadoc427/App.java
@@ -1,42 +1,35 @@
-
-/*
- * 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.
- */
-
-import java.io.*;
-import org.codehaus.plexus.util.*;
-
-File optionsFile = new File( basedir, "target/site/apidocs/options" );
-
-if ( !optionsFile.exists() )
-{
- System.err.println( optionsFile.getAbsolutePath() + " is missing." );
- return false;
-}
-
-String optionsContent = FileUtils.fileRead( optionsFile );
-String javaApiLink = "'http://docs.oracle.com/javase/1,5,0/docs/api'";
-
-if ( !optionsContent.contains( javaApiLink ) )
-{
- System.err.println( "Options is missing the following line:" );
- System.err.println( javaApiLink );
- return false;
-}
-
-return true;
\ No newline at end of file
+package mjavadoc427;
+
+/*
+ * 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.
+ */
+
+import org.slf4j.LoggerFactory;
+
+/**
+ * Link to slf4j {@link LoggerFactory}.
+ */
+public class App
+{
+
+ public LoggerFactory getLoggerFactory()
+ {
+ return null;
+ }
+
+}
diff --git a/src/it/projects/MJAVADOC-325/verify.bsh b/src/it/projects/MJAVADOC-427/verify.groovy
similarity index 56%
copy from src/it/projects/MJAVADOC-325/verify.bsh
copy to src/it/projects/MJAVADOC-427/verify.groovy
index 7c4ce44..8e3c9ab 100644
--- a/src/it/projects/MJAVADOC-325/verify.bsh
+++ b/src/it/projects/MJAVADOC-427/verify.groovy
@@ -1,42 +1,26 @@
-
-/*
- * 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.
- */
-
-import java.io.*;
-import org.codehaus.plexus.util.*;
-
-File optionsFile = new File( basedir, "target/site/apidocs/options" );
-
-if ( !optionsFile.exists() )
-{
- System.err.println( optionsFile.getAbsolutePath() + " is missing." );
- return false;
-}
-
-String optionsContent = FileUtils.fileRead( optionsFile );
-String javaApiLink = "'http://docs.oracle.com/javase/1,5,0/docs/api'";
-
-if ( !optionsContent.contains( javaApiLink ) )
-{
- System.err.println( "Options is missing the following line:" );
- System.err.println( javaApiLink );
- return false;
-}
-
-return true;
\ No newline at end of file
+/*
+ * 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.
+ */
+
+def file = new File( basedir, 'target/site/apidocs/mjavadoc427/App.html' );
+
+assert file.exists()
+
+// assert that javadoc of class correctly contains link, just like method details
+assert file.text =~ /Link to slf4j <a href=".*?".*?><code>LoggerFactory<\/code><\/a>/
+assert file.text =~ /<pre>public.*?<a href=".*?".*?>LoggerFactory<\/a>.*?getLoggerFactory.*?\(\)<\/pre>/
diff --git a/src/it/projects/detectLinks/verify.bsh b/src/it/projects/detectLinks/verify.bsh
index 4e68ec2..3669ab0 100644
--- a/src/it/projects/detectLinks/verify.bsh
+++ b/src/it/projects/detectLinks/verify.bsh
@@ -69,7 +69,7 @@ try
System.err.println( "-link not added: " + options1 );
return false;
}
- if ( !contentOptions1.substring( link1 ).contains( "http://commons.apache.org/lang/apidocs" ) )
+ if ( !contentOptions1.substring( link1 ).contains( "commons.apache.org" ) )
{
System.err.println( "link for commons-lang not added: " + options1 );
if ( !log.contains( "Error fetching link: http://commons.apache.org/lang/apidocs" ) )
@@ -77,7 +77,7 @@ try
return false;
}
}
- if ( !contentOptions1.substring( link1 ).contains( "http://junit.org/apidocs" ) )
+ if ( !contentOptions1.substring( link1 ).contains( "junit.org" ) )
{
System.err.println( "link for junit not added: " + options1 );
if ( !log.contains( "Error fetching link: http://junit.org/apidocs" ) )
@@ -108,7 +108,7 @@ try
System.err.println( "-link not added: " + options2 );
return false;
}
- if ( !contentOptions2.substring( link2 ).contains( "http://commons.apache.org/lang/apidocs" ) )
+ if ( !contentOptions2.substring( link2 ).contains( "commons.apache.org" ) )
{
System.err.println( "link for commons-lang not added: " + options2 );
if ( !log.contains( "Error fetching link: http://commons.apache.org/lang/apidocs" ) )
@@ -116,7 +116,7 @@ try
return false;
}
}
- if ( !contentOptions2.substring( link2 ).contains( "http://junit.org/apidocs" ) )
+ if ( !contentOptions2.substring( link2 ).contains( "junit.org" ) )
{
System.err.println( "link for junit not added: " + options2 );
if ( !log.contains( "Error fetching link: http://junit.org/apidocs" ) )
diff --git a/src/main/java/org/apache/maven/plugins/javadoc/AbstractJavadocMojo.java b/src/main/java/org/apache/maven/plugins/javadoc/AbstractJavadocMojo.java
index afe3654..b403c00 100644
--- a/src/main/java/org/apache/maven/plugins/javadoc/AbstractJavadocMojo.java
+++ b/src/main/java/org/apache/maven/plugins/javadoc/AbstractJavadocMojo.java
@@ -3163,7 +3163,7 @@ public abstract class AbstractJavadocMojo
links.addAll( getDependenciesLinks() );
- return links;
+ return followLinks( links );
}
private Set<Group> collectGroups()
@@ -5839,6 +5839,31 @@ public abstract class AbstractJavadocMojo
}
/**
+ * Follows all of the given links, and returns their last redirect locations. Ordering is kept.
+ * This is necessary because javadoc tool doesn't follow links, see JDK-8190312 (MJAVADOC-427, MJAVADOC-487)
+ *
+ * @param links Links to follow.
+ * @return Last redirect location of all the links.
+ */
+ private Set<String> followLinks( Set<String> links )
+ {
+ Set<String> redirectLinks = new LinkedHashSet<>( links.size() );
+ for ( String link : links )
+ {
+ try
+ {
+ redirectLinks.add( JavadocUtil.getRedirectUrl( new URI( link ).toURL(), settings ).toString() );
+ }
+ catch ( Exception e )
+ {
+ // only print in debug, it should have been logged already in warn/error because link isn't valid
+ getLog().debug( "Could not follow " + link + ". Reason: " + e.getMessage() );
+ }
+ }
+ return redirectLinks;
+ }
+
+ /**
* @param link not null
* @param detecting <code>true</code> if the link is generated by
* <code>detectLinks</code>, or <code>false</code> otherwise
diff --git a/src/main/java/org/apache/maven/plugins/javadoc/JavadocUtil.java b/src/main/java/org/apache/maven/plugins/javadoc/JavadocUtil.java
index 73ae0f2..e60699f 100644
--- a/src/main/java/org/apache/maven/plugins/javadoc/JavadocUtil.java
+++ b/src/main/java/org/apache/maven/plugins/javadoc/JavadocUtil.java
@@ -29,6 +29,7 @@ import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.params.ClientPNames;
+import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.conn.params.ConnRoutePNames;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
@@ -72,6 +73,7 @@ import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Modifier;
import java.net.SocketTimeoutException;
+import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
@@ -1639,6 +1641,49 @@ public class JavadocUtil
}
/**
+ * Execute an Http request at the given URL, follows redirects, and returns the last redirect locations. For URLs
+ * that aren't http/https, this does nothing and simply returns the given URL unchanged.
+ *
+ * @param url URL.
+ * @param settings Maven settings.
+ * @return Last redirect location.
+ * @throws IOException if there was an error during the Http request.
+ */
+ protected static URL getRedirectUrl( URL url, Settings settings )
+ throws IOException
+ {
+ String protocol = url.getProtocol();
+ if ( !"http".equals( protocol ) && !"https".equals( protocol ) )
+ {
+ return url;
+ }
+ HttpClient httpClient = null;
+ try
+ {
+ httpClient = createHttpClient( settings, url );
+ HttpClientContext httpContext = HttpClientContext.create();
+ HttpGet httpMethod = new HttpGet( url.toString() );
+ HttpResponse response = httpClient.execute( httpMethod, httpContext );
+ int status = response.getStatusLine().getStatusCode();
+ if ( status != HttpStatus.SC_OK )
+ {
+ throw new FileNotFoundException( "Unexpected HTTP status code " + status + " getting resource "
+ + url.toExternalForm() + "." );
+ }
+
+ List<URI> redirects = httpContext.getRedirectLocations();
+ return redirects.isEmpty() ? url : redirects.get( redirects.size() - 1 ).toURL();
+ }
+ finally
+ {
+ if ( httpClient != null )
+ {
+ httpClient.getConnectionManager().shutdown();
+ }
+ }
+ }
+
+ /**
* Validates an <code>URL</code> to point to a valid <code>package-list</code> resource.
*
* @param url The URL to validate.
diff --git a/src/test/java/org/apache/maven/plugins/javadoc/JavadocUtilTest.java b/src/test/java/org/apache/maven/plugins/javadoc/JavadocUtilTest.java
index e13f176..ed6ee00 100644
--- a/src/test/java/org/apache/maven/plugins/javadoc/JavadocUtilTest.java
+++ b/src/test/java/org/apache/maven/plugins/javadoc/JavadocUtilTest.java
@@ -22,7 +22,9 @@ package org.apache.maven.plugins.javadoc;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.io.OutputStream;
import java.net.SocketTimeoutException;
+import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
@@ -32,6 +34,10 @@ import java.util.Map;
import java.util.Set;
import java.util.regex.PatternSyntaxException;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.maven.plugins.javadoc.JavadocUtil;
import org.apache.maven.plugins.javadoc.ProxyServer.AuthAsyncProxyServlet;
@@ -39,6 +45,10 @@ import org.apache.maven.settings.Proxy;
import org.apache.maven.settings.Settings;
import org.codehaus.plexus.PlexusTestCase;
import org.codehaus.plexus.util.FileUtils;
+import org.mortbay.jetty.Server;
+import org.mortbay.jetty.handler.AbstractHandler;
+import org.mortbay.jetty.handler.MovedContextHandler;
+import org.mortbay.util.ByteArrayISO8859Writer;
/**
* @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
@@ -507,6 +517,65 @@ public class JavadocUtilTest
}
}
+ public void testGetRedirectUrlNotHttp()
+ throws Exception
+ {
+ URL url = new URI( "ftp://some.where" ).toURL();
+ assertEquals( url.toString(), JavadocUtil.getRedirectUrl( url, new Settings() ).toString() );
+
+ url = new URI( "file://some/where" ).toURL();
+ assertEquals( url.toString(), JavadocUtil.getRedirectUrl( url, new Settings() ).toString() );
+ }
+
+ /**
+ * Tests a redirect from localhost:port1 to localhost:port2
+ */
+ public void testGetRedirectUrl()
+ throws Exception
+ {
+ Server server = null, redirectServer = null;
+ try
+ {
+ redirectServer = new Server( 0 );
+ redirectServer.addHandler( new AbstractHandler()
+ {
+ @Override
+ public void handle( String target, HttpServletRequest request, HttpServletResponse response,
+ int dispatch )
+ throws IOException, ServletException
+ {
+ response.setStatus( HttpServletResponse.SC_OK );
+ ByteArrayISO8859Writer writer = new ByteArrayISO8859Writer( 100 );
+ writer.write( "<html>Hello world</html>" );
+ writer.flush();
+ response.setContentLength( writer.size() );
+ OutputStream out = response.getOutputStream();
+ writer.writeTo( out );
+ out.close();
+ writer.close();
+ }
+ } );
+ redirectServer.start();
+
+ server = new Server( 0 );
+ MovedContextHandler handler = new MovedContextHandler();
+ int redirectPort = redirectServer.getConnectors()[0].getLocalPort();
+ handler.setNewContextURL( "http://localhost:" + redirectPort );
+ server.addHandler( handler );
+ server.start();
+
+ URL url = new URI( "http://localhost:" + server.getConnectors()[0].getLocalPort() ).toURL();
+ URL redirectUrl = JavadocUtil.getRedirectUrl( url, new Settings() );
+
+ assertTrue( redirectUrl.toString().startsWith( "http://localhost:" + redirectPort ) );
+ }
+ finally
+ {
+ stopSilently( server );
+ stopSilently( redirectServer );
+ }
+ }
+
/**
* Method to test copyJavadocResources()
*
@@ -626,4 +695,19 @@ public class JavadocUtilTest
assertEquals( path1 + ps + path2 + ps + path1 + ps + path2, JavadocUtil.unifyPathSeparator( path1 + ";"
+ path2 + ":" + path1 + ":" + path2 ) );
}
+
+ private void stopSilently( Server server )
+ {
+ try
+ {
+ if ( server != null )
+ {
+ server.stop();
+ }
+ }
+ catch ( Exception e )
+ {
+ // ignored
+ }
+ }
}
--
To stop receiving notification emails like this one, please contact
gboue@apache.org.