diff --git a/pom.xml b/pom.xml
index 25889532c..56ec6cd13 100644
--- a/pom.xml
+++ b/pom.xml
@@ -294,6 +294,11 @@
2.3.20
+
+ org.apache.httpcomponents
+ httpclient
+
+
log4j
log4j
diff --git a/src/it/download-licenses-force/invoker.properties b/src/it/download-licenses-force/invoker.properties
index 2d950418f..fa44d6e30 100644
--- a/src/it/download-licenses-force/invoker.properties
+++ b/src/it/download-licenses-force/invoker.properties
@@ -1 +1 @@
-invoker.goals = clean license:download-licenses -Dlicense.forceDownload=true -Dlicense.errorRemedy=xmlOutput
+invoker.goals = clean license:download-licenses -Dlicense.forceDownload=true -Dlicense.errorRemedy=xmlOutput -Dlicense.sortByGroupIdAndArtifactId=true
diff --git a/src/it/download-licenses-force/licenses.expected.xml b/src/it/download-licenses-force/licenses.expected.xml
index fc69a29a5..f39c8759d 100644
--- a/src/it/download-licenses-force/licenses.expected.xml
+++ b/src/it/download-licenses-force/licenses.expected.xml
@@ -13,5 +13,18 @@
+
+ org.hibernate
+ hibernate-search-parent
+ 5.10.3.Final
+
+
+ GNU Lesser General Public License v2.1 or later
+ http://www.opensource.org/licenses/LGPL-2.1
+ gnu lesser general public license v2.1 or later - lgpl-2.1.txt.html
+ See also: http://hibernate.org/license
+
+
+
diff --git a/src/it/download-licenses-force/pom.xml b/src/it/download-licenses-force/pom.xml
index 4422e9c19..dd92c0d25 100644
--- a/src/it/download-licenses-force/pom.xml
+++ b/src/it/download-licenses-force/pom.xml
@@ -24,6 +24,18 @@
groovy-all
1.0-jsr-04
+
+ org.hibernate
+ hibernate-search-parent
+ pom
+ 5.10.3.Final
+
+
+ *
+ *
+
+
+
diff --git a/src/it/download-licenses-force/postbuild.groovy b/src/it/download-licenses-force/postbuild.groovy
index 4b79c1207..03dc61b55 100644
--- a/src/it/download-licenses-force/postbuild.groovy
+++ b/src/it/download-licenses-force/postbuild.groovy
@@ -30,6 +30,10 @@ assert Files.exists(asl2)
assert !asl2.text.contains('This content is fake.')
assert asl2.text.contains('Version 2.0, January 2004')
+final Path lgpl21 = basePath.resolve('target/generated-resources/licenses/gnu lesser general public license v2.1 or later - lgpl-2.1.txt.html')
+assert Files.exists(lgpl21)
+assert lgpl21.text.contains('Version 2.1, February 1999')
+
final Path expectedLicensesXml = basePath.resolve('licenses.expected.xml')
final Path licensesXml = basePath.resolve('target/generated-resources/licenses.xml')
assert expectedLicensesXml.text.equals(licensesXml.text)
diff --git a/src/main/java/org/codehaus/mojo/license/AbstractDownloadLicensesMojo.java b/src/main/java/org/codehaus/mojo/license/AbstractDownloadLicensesMojo.java
index ba26920fd..635b12f0e 100644
--- a/src/main/java/org/codehaus/mojo/license/AbstractDownloadLicensesMojo.java
+++ b/src/main/java/org/codehaus/mojo/license/AbstractDownloadLicensesMojo.java
@@ -38,6 +38,7 @@
import org.codehaus.mojo.license.model.ProjectLicenseInfo;
import org.codehaus.mojo.license.utils.FileUtil;
import org.codehaus.mojo.license.utils.LicenseDownloader;
+import org.codehaus.mojo.license.utils.LicenseDownloader.LicenseDownloadResult;
import org.codehaus.mojo.license.utils.LicenseSummaryReader;
import org.codehaus.mojo.license.utils.LicenseSummaryWriter;
import org.codehaus.mojo.license.utils.MojoHelper;
@@ -47,7 +48,7 @@
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
-import java.net.MalformedURLException;
+import java.net.URISyntaxException;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.file.Path;
@@ -458,28 +459,37 @@ public void execute()
// The resulting list of licenses after dependency resolution
List depProjectLicenses = new ArrayList<>();
- for ( MavenProject project : dependencies )
+ try ( LicenseDownloader licenseDownloader = new LicenseDownloader() )
{
- Artifact artifact = project.getArtifact();
- getLog().debug( "Checking licenses for project " + artifact );
- String artifactProjectId = getArtifactProjectId( artifact );
- ProjectLicenseInfo depProject;
- if ( configuredDepLicensesMap.containsKey( artifactProjectId ) )
+ for ( MavenProject project : dependencies )
{
- depProject = configuredDepLicensesMap.get( artifactProjectId );
- depProject.setVersion( artifact.getVersion() );
- }
- else
- {
- depProject = createDependencyProject( project );
- }
- if ( !offline )
- {
- downloadLicenses( depProject );
+ Artifact artifact = project.getArtifact();
+ getLog().debug( "Checking licenses for project " + artifact );
+ String artifactProjectId = getArtifactProjectId( artifact );
+ ProjectLicenseInfo depProject;
+ if ( configuredDepLicensesMap.containsKey( artifactProjectId ) )
+ {
+ depProject = configuredDepLicensesMap.get( artifactProjectId );
+ depProject.setVersion( artifact.getVersion() );
+ }
+ else
+ {
+ depProject = createDependencyProject( project );
+ }
+ if ( !offline )
+ {
+ downloadLicenses( licenseDownloader, depProject );
+ }
+ depProjectLicenses.add( depProject );
}
- depProjectLicenses.add( depProject );
+ }
+ catch ( Exception e )
+ {
+ throw new RuntimeException( e );
}
+
+
try
{
if ( sortByGroupIdAndArtifactId )
@@ -867,7 +877,8 @@ private String getLicenseFileName( ProjectLicenseInfo depProject, final URL lice
* @param depProject The project which generated the dependency
* @throws MojoFailureException
*/
- private void downloadLicenses( ProjectLicenseInfo depProject ) throws MojoFailureException
+ private void downloadLicenses( LicenseDownloader licenseDownloader, ProjectLicenseInfo depProject )
+ throws MojoFailureException
{
getLog().debug( "Downloading license(s) for project " + depProject );
@@ -906,9 +917,20 @@ private void downloadLicenses( ProjectLicenseInfo depProject ) throws MojoFailur
{
if ( !downloadedLicenseURLs.containsKey( licenseUrl ) || organizeLicensesByDependencies )
{
- licenseOutputFile = LicenseDownloader.downloadLicense( licenseUrl, proxyLoginPasswordEncoded,
- licenseOutputFile, getLog() );
- downloadedLicenseURLs.put( licenseUrl, licenseOutputFile );
+ final LicenseDownloadResult result =
+ licenseDownloader.downloadLicense( licenseUrl, proxyLoginPasswordEncoded, licenseOutputFile,
+ getLog() );
+
+ if ( result.isSuccess() )
+ {
+ licenseOutputFile = result.getFile();
+ downloadedLicenseURLs.put( licenseUrl, licenseOutputFile );
+ }
+ else
+ {
+ handleError( depProject, result.getErrorMessage() );
+ }
+
}
}
@@ -918,7 +940,7 @@ private void downloadLicenses( ProjectLicenseInfo depProject ) throws MojoFailur
}
}
- catch ( MalformedURLException e )
+ catch ( URISyntaxException e )
{
handleError( depProject, "POM for dependency " + depProject.toString() + " has an invalid license URL: "
+ licenseUrl );
diff --git a/src/main/java/org/codehaus/mojo/license/utils/LicenseDownloader.java b/src/main/java/org/codehaus/mojo/license/utils/LicenseDownloader.java
index cf37477b9..971ccdb2a 100644
--- a/src/main/java/org/codehaus/mojo/license/utils/LicenseDownloader.java
+++ b/src/main/java/org/codehaus/mojo/license/utils/LicenseDownloader.java
@@ -27,10 +27,20 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.net.HttpURLConnection;
-import java.net.URL;
-import java.net.URLConnection;
-
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpStatus;
+import org.apache.http.StatusLine;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.entity.ContentType;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
import org.apache.maven.plugin.logging.Log;
/**
@@ -39,7 +49,7 @@
* @author pgier
* @since 1.0
*/
-public class LicenseDownloader
+public class LicenseDownloader implements AutoCloseable
{
/**
@@ -47,6 +57,18 @@ public class LicenseDownloader
*/
public static final int DEFAULT_CONNECTION_TIMEOUT = 5000;
+ private final CloseableHttpClient client;
+
+ public LicenseDownloader()
+ {
+ final RequestConfig config = RequestConfig.copy( RequestConfig.DEFAULT )
+ .setConnectTimeout( DEFAULT_CONNECTION_TIMEOUT )
+ .setSocketTimeout( DEFAULT_CONNECTION_TIMEOUT )
+ .setConnectionRequestTimeout( DEFAULT_CONNECTION_TIMEOUT )
+ .build();
+ this.client = HttpClients.custom().setDefaultRequestConfig( config ).build();
+ }
+
/**
* Downloads a license file from the given {@code licenseUrlString} stores it locally and
* returns the local path where the license file was stored. Note that the
@@ -59,54 +81,55 @@ public class LicenseDownloader
* @param log
* @return the path to the file where the downloaded license file was stored
* @throws IOException
+ * @throws URISyntaxException
*/
- public static File downloadLicense( String licenseUrlString, String loginPassword, File outputFile, Log log )
- throws IOException
+ public LicenseDownloadResult downloadLicense( String licenseUrlString, String loginPassword, File outputFile,
+ Log log )
+ throws IOException, URISyntaxException
{
if ( licenseUrlString == null || licenseUrlString.length() == 0 )
{
- return outputFile;
+ return LicenseDownloadResult.success( outputFile );
}
- URLConnection connection = newConnection( licenseUrlString, loginPassword );
-
- boolean redirect = false;
- if ( connection instanceof HttpURLConnection )
+ if ( licenseUrlString.startsWith( "file://" ) )
{
- int status = ( (HttpURLConnection) connection ).getResponseCode();
-
- log.debug( String.format( "Got HTTP response %d for URL '%s'", status, licenseUrlString ) );
-
- redirect = HttpURLConnection.HTTP_MOVED_TEMP == status || HttpURLConnection.HTTP_MOVED_PERM == status
- || HttpURLConnection.HTTP_SEE_OTHER == status;
+ Files.copy( Paths.get( new URI( licenseUrlString ) ), outputFile.toPath() );
+ return LicenseDownloadResult.success( outputFile );
}
-
- if ( redirect )
+ else
{
- // get redirect url from "location" header field
- String newUrl = connection.getHeaderField( "Location" );
-
- // open the new connnection again
- connection = newConnection( newUrl, loginPassword );
-
- if ( connection instanceof HttpURLConnection )
+ try ( CloseableHttpResponse response = client.execute( new HttpGet( licenseUrlString ) ) )
{
- int status = ( (HttpURLConnection) connection ).getResponseCode();
- log.debug( String.format( "Got HTTP response %d for URL '%s'", status, licenseUrlString ) );
+ final StatusLine statusLine = response.getStatusLine();
+ if ( statusLine.getStatusCode() != HttpStatus.SC_OK )
+ {
+ return LicenseDownloadResult.failure( "'" + licenseUrlString + "' returned "
+ + statusLine.getStatusCode()
+ + ( statusLine.getReasonPhrase() != null ? " " + statusLine.getReasonPhrase() : "" ) );
+ }
+
+ final HttpEntity entity = response.getEntity();
+ if ( entity != null )
+ {
+ final ContentType contentType = ContentType.get( entity );
+ File updatedFile =
+ updateFileExtension( outputFile, contentType != null ? contentType.getMimeType() : null );
+
+ try ( InputStream in = entity.getContent();
+ FileOutputStream fos = new FileOutputStream( updatedFile ) )
+ {
+ copyStream( in, fos );
+ }
+ return LicenseDownloadResult.success( updatedFile );
+
+ }
+ else
+ {
+ return LicenseDownloadResult.failure( "'" + licenseUrlString + "' returned no body." );
+ }
}
-
}
-
- try ( InputStream licenseInputStream = connection.getInputStream() )
- {
- File updatedFile = updateFileExtension( outputFile, connection.getContentType() );
- try ( FileOutputStream fos = new FileOutputStream( updatedFile ) )
- {
- copyStream( licenseInputStream, fos );
- }
- return updatedFile;
- }
-
}
/**
@@ -127,24 +150,6 @@ private static void copyStream( InputStream inStream, OutputStream outStream )
}
}
- private static URLConnection newConnection( String url, String loginPassword )
- throws IOException
- {
-
- URL licenseUrl = new URL( url );
- URLConnection connection = licenseUrl.openConnection();
-
- if ( loginPassword != null )
- {
- connection.setRequestProperty( "Proxy-Authorization", "Basic " + loginPassword.trim() );
- }
- connection.setConnectTimeout( DEFAULT_CONNECTION_TIMEOUT );
- connection.setReadTimeout( DEFAULT_CONNECTION_TIMEOUT );
-
- return connection;
-
- }
-
private static File updateFileExtension( File outputFile, String mimeType )
{
final String realExtension = getFileExtension( mimeType );
@@ -185,4 +190,55 @@ private static String getFileExtension( String mimeType )
return null;
}
+ @Override
+ public void close()
+ throws Exception
+ {
+ client.close();
+ }
+
+ /**
+ * A result of a license download operation.
+ *
+ * @since 1.18
+ */
+ public static class LicenseDownloadResult
+ {
+ public static LicenseDownloadResult success( File file )
+ {
+ return new LicenseDownloadResult( file, null );
+ }
+
+ public static LicenseDownloadResult failure( String errorMessage )
+ {
+ return new LicenseDownloadResult( null, errorMessage );
+ }
+
+ private LicenseDownloadResult( File file, String errorMessage )
+ {
+ super();
+ this.file = file;
+ this.errorMessage = errorMessage;
+ }
+
+ private final File file;
+
+ private final String errorMessage;
+
+ public File getFile()
+ {
+ return file;
+ }
+
+ public String getErrorMessage()
+ {
+ return errorMessage;
+ }
+
+ public boolean isSuccess()
+ {
+ return errorMessage == null;
+ }
+ }
+
}