package org.jboss.windup.rules.apps.java.scan.provider; import java.io.IOException; import java.io.InputStream; import java.util.HashSet; import java.util.Set; import java.util.logging.Logger; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.jboss.windup.config.GraphRewrite; import org.jboss.windup.config.metadata.RuleMetadata; import org.jboss.windup.config.phase.ArchiveMetadataExtractionPhase; import org.jboss.windup.config.query.Query; import org.jboss.windup.config.ruleprovider.IteratingRuleProvider; import org.jboss.windup.graph.model.ArchiveModel; import org.jboss.windup.graph.model.LicenseModel; import org.jboss.windup.graph.model.resource.FileModel; import org.jboss.windup.graph.service.GraphService; import org.jboss.windup.reporting.model.TechnologyTagLevel; import org.jboss.windup.reporting.service.TechnologyTagService; import org.jboss.windup.util.Logging; import org.ocpsoft.rewrite.config.ConditionBuilder; import org.ocpsoft.rewrite.config.Rule; import org.ocpsoft.rewrite.context.EvaluationContext; import javax.enterprise.inject.Vetoed; /** * Discovers Licenses files within archives and adds the {@link LicenseModel} type to the {@link FileModel}. * * @author <a href="mailto:bradsdavis@gmail.com">Brad Davis</a> * @author <a href="mailto:hotmana76@gmail.com">Marek Novotny</a> */ @Vetoed @RuleMetadata(phase = ArchiveMetadataExtractionPhase.class, perform = "DiscoverArchiveLicenseFiles") public class DiscoverArchiveLicenseFilesRuleProvider extends IteratingRuleProvider<ArchiveModel> { private static final Logger LOG = Logging.get(DiscoverArchiveLicenseFilesRuleProvider.class); private static final TechnologyTagLevel TECH_TAG_LEVEL = TechnologyTagLevel.INFORMATIONAL; @Override public ConditionBuilder when() { return Query.fromType(ArchiveModel.class); } @Override public void perform(GraphRewrite event, EvaluationContext context, ArchiveModel payload) { Rule rule = (Rule) context.get(Rule.class); Set<FileModel> licenseFiles = findLicense(payload); if (licenseFiles.isEmpty()) { // no licenses found, skip this one return; } TechnologyTagService technologyTagService = new TechnologyTagService(event.getGraphContext()); GraphService<LicenseModel> licenseService = new GraphService<>(event.getGraphContext(), LicenseModel.class); for (FileModel license : licenseFiles) { LOG.info("Classifying: " + license.getFileName() + " as License within archive: " + payload.getArchiveName()); // http://opensource.org/licenses/ try (InputStream stream = license.asInputStream()) { String content = IOUtils.toString(stream); if (StringUtils.containsIgnoreCase(content, "Apache License, Version 2.0")) { tagLicenseByTechnologyTag(rule, licenseService, technologyTagService, license, "Apache License 2.0", "Apache License 2.0 File", "http://www.apache.org/licenses/LICENSE-2.0"); } else if (StringUtils.containsIgnoreCase(content, "Apache Software License, Version 1.1")) { tagLicenseByTechnologyTag(rule, licenseService, technologyTagService, license, "Apache License 1.1", "Apache License 1.1 File", "http://www.apache.org/licenses/LICENSE-1.1"); } else if (StringUtils.containsIgnoreCase(content, "Copyright (c) 1995-1999 The Apache Group. All rights reserved.")) { tagLicenseByTechnologyTag(rule, licenseService, technologyTagService, license, "Apache License 1.0", "Apache License 1.0 File", "http://www.apache.org/licenses/LICENSE-1.0"); } else if (StringUtils.containsIgnoreCase(content, "GNU General Public License")) { tagLicenseByTechnologyTag(rule, licenseService, technologyTagService, license, "GNU GPL", "GNU General Public License File", "http://opensource.org/licenses/gpl-license"); } else if (StringUtils.containsIgnoreCase(content, "The MIT License (MIT)")) { tagLicenseByTechnologyTag(rule, licenseService, technologyTagService, license, "MIT License", "MIT License File", "http://opensource.org/licenses/MIT"); } else if (StringUtils.containsIgnoreCase(content, "Mozilla Public License, version 2.0")) { tagLicenseByTechnologyTag(rule, licenseService, technologyTagService, license, "Mozilla Public License 2.0", "Mozilla Public License 2.0 File", "http://opensource.org/licenses/MPL-2.0"); } else if (StringUtils.containsIgnoreCase(content, "GNU Lesser General Public License")) { tagLicenseByTechnologyTag(rule, licenseService, technologyTagService, license, "GNU LGPL", "GNU LGPL File", "http://opensource.org/licenses/lgpl-license"); } else if (StringUtils.contains(content, "COMMON DEVELOPMENT AND DISTRIBUTION LICENSE")) { tagLicenseByTechnologyTag(rule, licenseService, technologyTagService, license, "CDDL", "CDDL License File", "http://opensource.org/licenses/CDDL-1.0"); } else if (StringUtils.containsIgnoreCase(content, "Eclipse Public License")) { tagLicenseByTechnologyTag(rule, licenseService, technologyTagService, license, "Eclipse Public License 1.0", "Eclipse Public License 1.0 File", "http://opensource.org/licenses/EPL-1.0"); } else if (StringUtils.containsIgnoreCase(content, "Redistribution and use in source and binary forms")) { tagLicenseByTechnologyTag(rule, licenseService, technologyTagService, license, "BSD License", "BSD License File", "http://opensource.org/licenses/"); } else if (StringUtils.containsIgnoreCase(content, "the work of authorship identified is in the public domain of the country")) { tagLicenseByTechnologyTag(rule, licenseService, technologyTagService, license, "Public Domain License", "Creative Commons Public Domain License File", "http://creativecommons.org/licenses/publicdomain/"); } else { LOG.warning("Must be unknown license type: " + license.getFileName()); tagLicenseByTechnologyTag(rule, licenseService, technologyTagService, license, "Unknown License", "Unknown License File", "Unknown License File"); } } catch (IOException e) { LOG.fine("Error while opening License file: " + license.getFileName() + " with error: " + e.getLocalizedMessage()); } } } private void tagLicenseByTechnologyTag(Rule rule, GraphService<LicenseModel> licenseService, TechnologyTagService technologyTagService, FileModel license, String name, String description, String url) { LOG.info("Identified: " + license.getFileName() + " as: " + name); // create license model for future reporting. LicenseModel model = licenseService.addTypeToModel(license); model.setName(name); model.setURL(url); // even it is not classified or marked as a hint, do include it in reports model.setGenerateSourceReport(true); // also add it as a tag for reporting on main screen. technologyTagService.addTagToFileModel(license, name, TECH_TAG_LEVEL); } private Set<FileModel> findLicense(ArchiveModel archive) { Set<FileModel> licenses = new HashSet<>(); Iterable<FileModel> files = archive.getAllFiles(); for (FileModel model : files) { if (model.isDirectory()) { continue; } String fileName = model.getFileName(); fileName = StringUtils.lowerCase(fileName); if (fileName.endsWith("license.txt") || fileName.endsWith("license") || fileName.endsWith("gpl.txt") || fileName.endsWith("lgpl.txt") || fileName.endsWith("notice.txt") || fileName.endsWith("notice")) { licenses.add(model); } } return licenses; } }