All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jasig.maven.notice.LicenseLookupHelper Maven / Gradle / Ivy

There is a newer version: 1.1.0
Show newest version
/**
 * 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();
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy