com.metaeffekt.artifact.analysis.bom.LicenseProcessor Maven / Gradle / Ivy
The newest version!
package com.metaeffekt.artifact.analysis.bom;
import com.metaeffekt.artifact.analysis.metascan.Constants;
import com.metaeffekt.artifact.analysis.bom.spdx.LicenseStringConverter;
import com.metaeffekt.artifact.analysis.utils.InventoryUtils;
import com.metaeffekt.artifact.terms.model.LicenseTextEntry;
import com.metaeffekt.artifact.terms.model.LicenseTextProvider;
import com.metaeffekt.artifact.terms.model.NormalizationMetaData;
import com.metaeffekt.artifact.terms.model.TermsMetaData;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.metaeffekt.common.notice.model.ComponentDefinition;
import org.metaeffekt.common.notice.model.NoticeParameters;
import org.metaeffekt.common.notice.model.UnassignedInformation;
import org.metaeffekt.core.inventory.processor.model.AbstractModelBase;
import org.metaeffekt.core.inventory.processor.model.Artifact;
import java.util.*;
import java.util.stream.Collectors;
/**
* A helper class used in conjunction with CycloneDX and SPDX to perform various actions designed to help find, filter
* and manage licenses and license expressions.
*/
@Slf4j
public class LicenseProcessor {
public static Map getReferencedLicenseText(Collection referencedLicenses,
LicenseTextProvider licenseTextProvider, NormalizationMetaData normalizationMetaData) {
if (referencedLicenses.isEmpty()) {
return null;
}
final Map identifierToLicenseText = new HashMap<>();
final Set referencedCanonicalNames = referencedLicenses.stream()
.map(TermsMetaData::getCanonicalName).collect(Collectors.toSet());
final LicenseStringConverter licenseStringConverter = new LicenseStringConverter(normalizationMetaData, null);
final Map licenseTextEntryByName;
if (licenseTextProvider != null) {
licenseTextEntryByName = licenseTextProvider.resolve(referencedCanonicalNames);
} else {
licenseTextEntryByName = Collections.emptyMap();
}
// process licenses for which texts have been found
for (Map.Entry licenseNameToTextEntry : licenseTextEntryByName.entrySet()) {
final String canonicalName = licenseNameToTextEntry.getKey();
TermsMetaData tmd = normalizationMetaData.findTermsMetaData(canonicalName);
if (tmd == null) {
tmd = normalizationMetaData.findUsingCanonicalNameInHistory(canonicalName);
if (tmd == null) continue;
}
final String identifier = licenseStringConverter.getLicenseRefForTmd(tmd);
identifierToLicenseText.put(identifier, licenseNameToTextEntry.getValue().getLicenseText());
}
// add null for licenses without texts
referencedCanonicalNames.removeAll(licenseTextEntryByName.keySet());
for (String canonicalName : referencedCanonicalNames) {
TermsMetaData tmd = normalizationMetaData.findTermsMetaData(canonicalName);
if (tmd == null) {
tmd = normalizationMetaData.findUsingCanonicalNameInHistory(canonicalName);
if (tmd == null) continue;
}
final String identifier = licenseStringConverter.getLicenseRefForTmd(tmd);
identifierToLicenseText.put(identifier, null);
}
return identifierToLicenseText;
}
public static List aggregateEffectiveLicenses(NoticeParameters noticeParameters) {
final Set aggregated = new HashSet<>();
if (noticeParameters.getComponent() != null) {
aggregated.addAll(aggregateEffectiveLicenses(noticeParameters.getComponent()));
}
if (noticeParameters.getSubcomponents() != null) {
for (ComponentDefinition componentDefinition : noticeParameters.getSubcomponents()) {
aggregated.addAll(aggregateEffectiveLicenses(componentDefinition));
}
}
return aggregated.stream().sorted(String::compareToIgnoreCase).collect(Collectors.toList());
}
private static Collection aggregateEffectiveLicenses(ComponentDefinition component) {
if (component != null) {
if (component.getEffectiveLicenses() == null || component.getEffectiveLicenses().isEmpty()) {
final List associatedLicenses = component.getAssociatedLicenses();
return InventoryUtils.tokenizeLicense(InventoryUtils.deriveEffectiveLicenses(associatedLicenses), true,
false);
} else {
return component.getEffectiveLicenses();
}
}
return Collections.emptyList();
}
public static NoticeParameters readNoticeParameters(AbstractModelBase modelBase) {
// get notice parameter from the artifact
String noticeParametersString = modelBase.get(Constants.KEY_NOTICE_PARAMETER);
// FIXME-KKL: resolve issue
// the inherited notice parameter is curated; (could be also an exact match; since no inventory filtering is
// applied yet)
if (StringUtils.isBlank(noticeParametersString)) {
noticeParametersString = modelBase.get("Inherited Notice Parameter");
}
// the derived notice parameter is automatically determined
if (StringUtils.isBlank(noticeParametersString)) {
noticeParametersString = modelBase.get(Constants.KEY_DERIVED_NOTICE_PARAMETER);
}
if (StringUtils.isNotBlank(noticeParametersString)) {
// convert notice parameter string into object
try {
return NoticeParameters.readYaml(noticeParametersString);
} catch (RuntimeException e) {
log.warn("Unable to parse notice parameter:\n[{}]", noticeParametersString);
}
}
String associatedLicenses = null;
List copyrights = null;
// fallback to other provided licenses/copyrights
if (modelBase instanceof Artifact) {
associatedLicenses = deriveAssociatedLicenses((Artifact) modelBase);
copyrights = extractCopyrights((Artifact) modelBase);
}
if (StringUtils.isNotEmpty(associatedLicenses)) {
final ComponentDefinition componentDefinition = new ComponentDefinition();
componentDefinition.setAssociatedLicenses(InventoryUtils.tokenizeLicense(associatedLicenses, true, true));
final NoticeParameters noticeParameters = new NoticeParameters();
noticeParameters.setComponent(componentDefinition);
UnassignedInformation unassignedInformation = new UnassignedInformation();
unassignedInformation.setCopyrights(copyrights);
noticeParameters.setUnassignedInformation(unassignedInformation);
return noticeParameters;
} else if (copyrights != null && !copyrights.isEmpty()) {
final NoticeParameters noticeParameters = new NoticeParameters();
UnassignedInformation unassignedInformation = new UnassignedInformation();
unassignedInformation.setCopyrights(copyrights);
noticeParameters.setUnassignedInformation(unassignedInformation);
return noticeParameters;
}
// unable to proceed with empty licenses / notice parameter
return null;
}
private static String deriveAssociatedLicenses(Artifact artifact) {
// getLicenses delivers the curated associated licenses
String associatedLicenses = artifact.getLicense();
// FIXME: currently a fallback strategy
// FIXME: merge binary and source license lists (via set union) to create the most complete possible list
// FIXME: consider approach via notice parameter for each level and merging the component pattern in the end
if (StringUtils.isEmpty(associatedLicenses)) {
associatedLicenses = artifact.get("Binary Artifact - Derived Licenses");
}
// fallback to detected licenses on binary
if (StringUtils.isEmpty(associatedLicenses)) {
associatedLicenses = artifact.get(Constants.KEY_DERIVED_LICENSES);
}
// fallback to source artifact
if (StringUtils.isEmpty(associatedLicenses)) {
associatedLicenses = artifact.get("Source Artifact - Derived Licenses");
}
// fallback on source archive
if (StringUtils.isEmpty(associatedLicenses)) {
associatedLicenses = artifact.get("Source Archive - Derived Licenses");
}
if (StringUtils.isEmpty(associatedLicenses)) {
associatedLicenses = artifact.get("Descriptor - Derived Licenses");
}
// fallback to package specified licenses (mapped)
if (StringUtils.isEmpty(associatedLicenses)) {
associatedLicenses = artifact.get("Specified Package License (mapped)");
}
return associatedLicenses;
}
/**
* Attempts to extract copyright information from the artifact or returns "NOASSERTION".
*
* @return text containing copyright information or "NOASSERTION"
*/
private static List extractCopyrights(Artifact artifact) {
String copyrights = artifact.get(Constants.KEY_EXTRACTED_COPYRIGHTS_SCANCODE);
// FIXME: currently a fallback strategy
if (StringUtils.isEmpty(copyrights)) {
copyrights = artifact.get("Binary Artifact - Extracted Copyrights (ScanCode)");
}
if (StringUtils.isEmpty(copyrights)) {
copyrights = artifact.get("Source Artifact - Extracted Copyrights (ScanCode)");
}
if (StringUtils.isEmpty(copyrights)) {
copyrights = artifact.get("Source Archive - Extracted Copyrights (ScanCode)");
}
if (StringUtils.isEmpty(copyrights)) {
copyrights = artifact.get("Descriptor - Extracted Copyrights (ScanCode)");
}
if (!StringUtils.isEmpty(copyrights)) {
return InventoryUtils.filterCopyrightsAndAuthorsList(copyrights);
}
return Collections.emptyList();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy