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

org.spdx.maven.MavenToSpdxLicenseMapper Maven / Gradle / Ivy

/*
 * Copyright 2014 Source Auditor Inc.
 *
 * Licensed 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.spdx.maven;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.maven.model.License;

import org.apache.maven.plugin.logging.Log;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import org.spdx.rdfparser.InvalidSPDXAnalysisException;
import org.spdx.rdfparser.SpdxRdfConstants;
import org.spdx.rdfparser.license.AnyLicenseInfo;
import org.spdx.rdfparser.license.ConjunctiveLicenseSet;
import org.spdx.rdfparser.license.LicenseInfoFactory;
import org.spdx.rdfparser.license.SpdxListedLicense;
import org.spdx.rdfparser.license.SpdxNoAssertionLicense;

/**
 * Singleton class which maps Maven license objects to SPDX licenses.
 * 
 * The license mapping uses the JSON file from the spdx.org/licenses/licenses.json file
 * 
 * If the site spdx.org/licenses is not accessible, then static version of the file will be used
 * 
 * The seeAlso property of the SPDX file is matched to the Maven license URL.
 * 
 * @author Gary O'Neall
 *
 */
public class MavenToSpdxLicenseMapper
{
    private static final String SPDX_LICENSE_URL_PREFIX = "https://spdx.org/licenses/";
    private static final String LISTED_LICENSE_JSON_URL = SPDX_LICENSE_URL_PREFIX + "licenses.json";
    private static final String LISTED_LICENSE_JSON_PATH = "resources/licenses.json";

    static MavenToSpdxLicenseMapper instance;
    private Map urlStringToSpdxLicenseId;
    
    private MavenToSpdxLicenseMapper(Log log) throws LicenseMapperException {
        // Can not instantiate directly - singleton class
        InputStream is = null;
        try
        {
            URL listedLicenseJsonUrl  = new URL( LISTED_LICENSE_JSON_URL );
            is = listedLicenseJsonUrl.openStream();
        }
        catch ( MalformedURLException e )
        {
            if (log != null) {
                log.warn( "Invalid JSON URL for SPDX listed licenses.  Using cached version" );
            }
        } catch (IOException e) {
            if (log != null) {
                log.warn( "IO Exception opening web page for JSON for SPDX listed licenses.  Using cached version" );
            }
		}
        if (is == null) {
            // use the cached version
            is = LicenseManager.class.getClassLoader().getResourceAsStream(LISTED_LICENSE_JSON_PATH);
        }
        InputStreamReader reader = new InputStreamReader( is );
        try {
            initializeUrlMap( reader, log );
        } finally {
            try
            {
                reader.close();
            }
            catch ( IOException e )
            {
               if (log != null) {
                   log.warn( "IO error closing listed license reader: "+e.getMessage() );
               }
            }
        }
       
    }
    
    public static MavenToSpdxLicenseMapper getInstance( Log log ) throws LicenseMapperException {
        if (instance == null) {
            instance = new MavenToSpdxLicenseMapper( log );
        }
        return instance;
    }
    
    /**
     * @param url URL string for a license
     * @return SPDX ID associated with the URL
     */
    public String urlToSpdxId( String url ) {
        return this.urlStringToSpdxLicenseId.get( url );
    }

    /**
     * Initialize the urlSTringToSpdxLicense map with the SPDX listed licenses
     * @param jsonReader Reader for the JSON input file containing the listed licenses
     * @param log Optional logger
     * @throws LicenseMapperException 
     */
    private void initializeUrlMap( Reader jsonReader, Log log ) throws LicenseMapperException
    {
        JSONParser parser = new JSONParser();       
        Object parsedObject = null;
        try
        {
            parsedObject = parser.parse( jsonReader );
        }
        catch ( IOException e1 )
        {
            if (log != null) {
                log.error( "I/O error parsing listed licenses JSON file: "+e1.getMessage() );
            }
            throw( new LicenseMapperException( "I/O Error parsing listed licenses" ));
        }
        catch ( ParseException e1 )
        {
            if (log != null) {
                log.error( "JSON parsing error parsing listed licenses JSON file: "+e1.getMessage() );
            }
            throw( new LicenseMapperException( "JSON parsing error parsing listed licenses" ));
        }
        JSONObject listedLicenseSource = (JSONObject)parsedObject;
        
        JSONArray listedLicenses = (JSONArray)listedLicenseSource.get( "licenses" );
        urlStringToSpdxLicenseId = new HashMap();
        List urlsWithMultipleIds = new ArrayList();
        for ( int i = 0; i < listedLicenses.size(); i++ ) {
            JSONObject listedLicense = (JSONObject)listedLicenses.get( i );
            String licenseId = (String)listedLicense.get( SpdxRdfConstants.PROP_LICENSE_ID );
            this.urlStringToSpdxLicenseId.put( SPDX_LICENSE_URL_PREFIX + licenseId, licenseId );
            JSONArray urls = (JSONArray)listedLicense.get( SpdxRdfConstants.RDFS_PROP_SEE_ALSO );
            if ( urls != null ) {
                for ( int j = 0; j < urls.size(); j++ ) {
                    String url = (String)urls.get( j );
                    url = url.replaceAll("https", "http");
                    if (this.urlStringToSpdxLicenseId.containsKey( url )) {
                        urlsWithMultipleIds.add( url );
                    } else {
                        this.urlStringToSpdxLicenseId.put( url, licenseId );
                    }
                }
            }
        }
        // Remove any mappings which have ambiguous URL mappings
        for (String redundantUrl:urlsWithMultipleIds) {
            this.urlStringToSpdxLicenseId.remove( redundantUrl );
        }
        addManualMappings();
    }
    
    /**
     * This is a bit of an override on the official SPDX license list
     * Add some specific URL mappings that are commonly used in SPDX files
     */
    private void addManualMappings()
    {
        // TODO: Request these be added to the SPDX license list and remove once they
        // have been added
        this.urlStringToSpdxLicenseId.put( "http://www.apache.org/licenses/LICENSE-2.0.txt", "Apache-2.0" );
        this.urlStringToSpdxLicenseId.put( "http://www.opensource.org/licenses/cpl1.0.txt", "CPL-1.0" );
        this.urlStringToSpdxLicenseId.put( "http://www.opensource.org/licenses/mit-license.php", "MIT" );
        // The following is in the listed licenses, but is duplicated in multiple SPDX license ID's
        // adding it back for the license it was originally targeted for
        this.urlStringToSpdxLicenseId.put( "http://www.mozilla.org/MPL/MPL-1.0.txt", "MPL-1.0" );
    }

    /**
     * Map a list of Maven licenses to an SPDX license.  If no licenses
     * are supplied, SpdxNoAssertion license is returned.  if a single
     * license is supplied, and a URL can be found matching a listed license,
     * the listed license is returned.  if a single
     * license is supplied, and a URL can not be found matching a listed license,
     * SpdxNoAssertion is returned.  If
     * multiple licenses are supplied, a conjunctive license is returned
     * containing all mapped SPDX licenses.
     * @return
     * @throws LicenseManagerException 
     */
    public AnyLicenseInfo mavenLicenseListToSpdxLicense( List licenseList ) {
        if ( licenseList == null ) {
            return new SpdxNoAssertionLicense();
        }
        List spdxLicenses = new ArrayList();
        Iterator iter = licenseList.iterator();
        while( iter.hasNext() ) {
            License license = iter.next();
            SpdxListedLicense listedLicense = mavenLicenseToSpdxListedLicense( license );
            if (listedLicense != null) {
                spdxLicenses.add( listedLicense );
            }
        }
        if ( spdxLicenses.size() < 1) {
            return new SpdxNoAssertionLicense();
        } else if ( spdxLicenses.size() == 1 ) {
            return spdxLicenses.get( 0 );
        } else {
            AnyLicenseInfo[] licensesInSet = spdxLicenses.toArray( new AnyLicenseInfo[spdxLicenses.size()] );
            AnyLicenseInfo conjunctiveLicense = new ConjunctiveLicenseSet( licensesInSet );
            return conjunctiveLicense;
        }
    }

    private SpdxListedLicense mavenLicenseToSpdxListedLicense( License license )
    {
        if ( license == null ) {
            return null;
        }
        if ( license.getUrl() == null || license.getUrl().isEmpty() ) {
            return null;
        }
        String spdxId = this.urlStringToSpdxLicenseId.get( license.getUrl().replaceAll("https", "http") );
        if (spdxId == null) {
            return null;
        }
        try
        {
            return LicenseInfoFactory.getListedLicenseById( spdxId );
        }
        catch ( InvalidSPDXAnalysisException e )
        {
            return null;
        }
    }

    /**
     * @return Map of URL's to listed license ID's
     */
    public Map getMap()
    {
        return this.urlStringToSpdxLicenseId;
    }
    
    
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy