org.spdx.maven.MavenToSpdxLicenseMapper.java Source code

Java tutorial

Introduction

Here is the source code for org.spdx.maven.MavenToSpdxLicenseMapper.java

Source

/*
 * Copyright 2014 The Apache Software Foundation.
 *
 * 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 = "http://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<String, String> 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);
            //TODO: Uncomment the line below once the JSON file has been uploaded to the SPDX listed license website
            //is = listedLicenseJsonUrl.openStream();
        } catch (MalformedURLException e) {
            if (log != null) {
                log.warn("Invalid JSON URL 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<String, String>();
        List<String> urlsWithMultipleIds = new ArrayList<String>();
        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);
                    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<License> licenseList) {
        if (licenseList == null) {
            return new SpdxNoAssertionLicense();
        }
        List<AnyLicenseInfo> spdxLicenses = new ArrayList<AnyLicenseInfo>();
        Iterator<License> 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());
        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<String, String> getMap() {
        return this.urlStringToSpdxLicenseId;
    }

}