org.jasig.maven.notice.LicenseLookupHelper Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of maven-notice-plugin Show documentation
Show all versions of maven-notice-plugin Show documentation
Generates Apache style NOTICE files
/**
* Licensed to Jasig under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Jasig 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.jasig.maven.notice;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.regex.Pattern;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import org.apache.commons.collections.map.LRUMap;
import org.apache.commons.io.IOUtils;
import org.apache.maven.artifact.versioning.ArtifactVersion;
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.logging.Log;
import org.jasig.maven.notice.lookup.ArtifactLicense;
import org.jasig.maven.notice.lookup.LicenseLookup;
import org.jasig.maven.notice.lookup.MappedVersion;
import org.jasig.maven.notice.lookup.VersionType;
import org.jasig.maven.notice.util.ResourceFinder;
/**
* Utility to load license-lookup XML files and search through the loaded results for matches on a specified
* artifact.
*
* @author Eric Dalquist
* @version $Revision: 22453 $
*/
public class LicenseLookupHelper {
/**
* Cache parse results for the 20 most recently used LicenseLookup files
*/
@SuppressWarnings("unchecked")
private static final Map LICENSE_LOOKUP_CACHE = new LRUMap(20);
private static final ReadWriteLock LICENSE_LOOKUP_CACHE_LOCK = new ReentrantReadWriteLock();
private final Map, ArtifactLicense>> mergedLicenseLookup = new LinkedHashMap,ArtifactLicense>>();
private final Log logger;
private final ResourceFinder resourceFinder;
public LicenseLookupHelper(Log logger, ResourceFinder resourceFinder, String[] licenseLookupFiles) throws MojoFailureException {
this.logger = logger;
this.resourceFinder = resourceFinder;
final Unmarshaller unmarshaller = LicenseLookupContext.getUnmarshaller();
if (licenseLookupFiles == null) {
licenseLookupFiles = new String[0];
}
for (final String licenseLookupFile : licenseLookupFiles) {
final LicenseLookup licenseLookup = this.loadLicenseLookup(unmarshaller, licenseLookupFile);
for (final ArtifactLicense artifactLicense : licenseLookup.getArtifact()) {
final String groupId = artifactLicense.getGroupId();
final String artifactId = artifactLicense.getArtifactId();
final String artifactKey = getArtifactKey(groupId, artifactId);
Map, ArtifactLicense> artifactVersions = this.mergedLicenseLookup.get(artifactKey);
if (artifactVersions == null) {
artifactVersions = new LinkedHashMap, ArtifactLicense>();
this.mergedLicenseLookup.put(artifactKey, artifactVersions);
}
final List version = artifactLicense.getVersion();
artifactVersions.put(version, artifactLicense);
this.logger.debug("Mapped " + artifactLicense + " from: " + licenseLookupFile);
}
}
}
public ResolvedLicense lookupLicenseMapping(String groupId, String artifactId, ArtifactVersion artifactVersion) {
//Find license info mapped to the group/artifact
final String artifactKey = getArtifactKey(groupId, artifactId);
final Map, ArtifactLicense> artifactVersions = this.mergedLicenseLookup.get(artifactKey);
if (artifactVersions == null) {
return null;
}
VersionType matchType = null;
ArtifactLicense artifactLicense = null;
//Search the mapped versions lists for a matching version
for (final Entry, ArtifactLicense> versionEntry : artifactVersions.entrySet()) {
final List versions = versionEntry.getKey();
//If no versions are specified for an artifact all versions match
if (matchType == null && versions.size() == 0) {
artifactLicense = versionEntry.getValue();
}
else {
for (final MappedVersion version : versions) {
//Use the first REGEX match found, skip checking any subsequent REGEX versions
if (VersionType.REGEX == matchType && VersionType.REGEX == version.getType()) {
continue;
}
final boolean matches = this.compareVersions(version, artifactVersion);
if (matches) {
matchType = version.getType();
artifactLicense = versionEntry.getValue();
//If a STRING match is found break the loop. First exact match is always used
if (VersionType.STRING == matchType) {
break;
}
}
}
}
//If a STRING match is found break the loop. First exact match is always used
if (VersionType.STRING == matchType) {
break;
}
}
this.logger.debug("Found " + artifactLicense + " with match " + matchType + " for: " + groupId + ":" + artifactId + ":" + artifactVersion);
return new ResolvedLicense(matchType, artifactLicense);
}
protected boolean compareVersions(final MappedVersion version, ArtifactVersion artifactVersion) {
switch (version.getType()) {
case REGEX: {
final Pattern versionPattern = Pattern.compile(version.getValue());
return versionPattern.matcher(artifactVersion.toString()).matches();
}
default: {
final ArtifactVersion mappedVersion = new DefaultArtifactVersion(version.getValue());
return mappedVersion.equals(artifactVersion);
}
}
}
protected String getArtifactKey(String groupId, String artifactId) {
return groupId + ":" + artifactId;
}
protected LicenseLookup loadLicenseLookup(Unmarshaller unmarshaller, String licenseLookupFile) throws MojoFailureException {
final URL licenseLookupUrl = resourceFinder.findResource(licenseLookupFile);
//Try loading the LicenseLookup from cache
final Lock readLock = LICENSE_LOOKUP_CACHE_LOCK.readLock();
LicenseLookup licenseLookup = this.loadLicenseLookup(unmarshaller, licenseLookupFile, licenseLookupUrl, readLock, false);
if (licenseLookup != null) {
return licenseLookup;
}
//Must not have been in the cache, grab the write lock and check again
final Lock writeLock = LICENSE_LOOKUP_CACHE_LOCK.writeLock();
return loadLicenseLookup(unmarshaller, licenseLookupFile, licenseLookupUrl, writeLock, true);
}
protected LicenseLookup loadLicenseLookup(Unmarshaller unmarshaller, String licenseLookupFile, URL licenseLookupUrl, Lock lock, boolean create) throws MojoFailureException {
final String licenseLookupKey = licenseLookupUrl.toString();
lock.lock();
try {
//Look in the cache to see if the lookup file has already been parsed
LicenseLookup licenseLookup = LICENSE_LOOKUP_CACHE.get(licenseLookupKey);
if (licenseLookup != null) {
logger.info("Loading license lookup mappings from '" + licenseLookupUrl + "' (cached)");
return licenseLookup;
}
//Cache miss, check if we should parse the file, return null if not
if (!create) {
return null;
}
logger.info("Loading license lookup mappings from '" + licenseLookupUrl + "'");
InputStream lookupStream = null;
try {
lookupStream = licenseLookupUrl.openStream();
licenseLookup = (LicenseLookup)unmarshaller.unmarshal(lookupStream);
LICENSE_LOOKUP_CACHE.put(licenseLookupKey, licenseLookup);
return licenseLookup;
}
catch (IOException e) {
throw new MojoFailureException("Failed to read '" + licenseLookupFile + "' from '" + licenseLookupUrl + "'", e);
}
catch (JAXBException e) {
throw new MojoFailureException("Failed to parse '" + licenseLookupFile + "' from '" + licenseLookupUrl + "'", e);
}
finally {
IOUtils.closeQuietly(lookupStream);
}
}
finally {
lock.unlock();
}
}
}