com.metaeffekt.artifact.analysis.flow.notice.NoticeParameterBuilderAnalysis Maven / Gradle / Ivy
/*
* Copyright 2021-2024 the original author or authors.
*
* 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 com.metaeffekt.artifact.analysis.flow.notice;
import com.metaeffekt.artifact.analysis.metascan.MergedScanResult;
import com.metaeffekt.artifact.analysis.utils.InventoryUtils;
import com.metaeffekt.artifact.analysis.workbench.InventoryTransformer;
import com.metaeffekt.artifact.terms.model.MergedSegmentResult;
import com.metaeffekt.artifact.terms.model.NormalizationMetaData;
import com.metaeffekt.artifact.terms.model.TermsMetaData;
import com.metaeffekt.artifact.terms.model.Variables;
import lombok.Getter;
import lombok.Setter;
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.Artifact;
import org.metaeffekt.core.inventory.processor.model.Inventory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import static com.metaeffekt.artifact.analysis.metascan.Constants.KEY_DERIVED_NOTICE_PARAMETER;
/**
* Builds NoticeParameters based on scanner results. Uses analysis paths to construct NoticeParameters.
*/
public class NoticeParameterBuilderAnalysis {
private final Logger LOG = LoggerFactory.getLogger(getClass());
private static final String KEY_ANALYSIS_PATH = "Analysis Path";
private static final String KEY_SOURCE_ANALYSIS_PATH = "Source Artifact - Path";
private static final String KEY_SOURCE_ARCHIVE_PATH = "Source Archive - Path";
private final NormalizationMetaData normalizationMetaData;
private final InventoryTransformer transformer;
public NoticeParameterBuilderAnalysis(NormalizationMetaData normalizationMetaData) {
this.normalizationMetaData = normalizationMetaData;
this.transformer = new InventoryTransformer(normalizationMetaData);
}
public Inventory enrichInventoryWithNoticeParameter(Inventory inventory) throws IOException {
int i = 1;
for (Artifact artifact : inventory.getArtifacts()) {
LOG.debug("Building notice parameter for {} ({}/{})", artifact.deriveQualifier(), i++, inventory.getArtifacts().size());
String noticeParam = buildNoticeParameter(artifact);
artifact.set(KEY_DERIVED_NOTICE_PARAMETER, noticeParam);
}
return inventory;
}
public String buildNoticeParameter(Artifact artifact) throws IOException {
// FIXME: apply dedicated combinatorics; discuss
// observed artifact + binary artifact + source artifact
// observed artifact + binary artifact + source artifact
// observed artifact + binary artifact
// binary artifact
// binary artifact + descriptor
// descriptor
// source artifact
MergedScanResult mergedScanResult = new MergedScanResult();
mergedScanResult.mergeResults(artifact, getAnalysisTargetFile(artifact, "Binary Artifact - Analysis Path"));
mergedScanResult.mergeResults(artifact, getAnalysisTargetFile(artifact, "Source Artifact - Analysis Path"));
mergedScanResult.mergeResults(artifact, getAnalysisTargetFile(artifact, "Source Archive - Analysis Path"));
mergedScanResult.mergeResults(artifact, getAnalysisTargetFile(artifact, "Descriptor - Analysis Path"));
mergedScanResult.mergeResults(artifact, getAnalysisTargetFile(artifact, KEY_ANALYSIS_PATH));
List mergedScanResultList = mergedScanResult.getMergedScanResult();
if (!mergedScanResultList.isEmpty()) {
List components = getComponentList(mergedScanResultList);
if (!components.isEmpty()) {
NoticeParameters noticeParameters = writeNoticeParameter(components);
NoticeParameterPostProcessing postProcessing = new NoticeParameterPostProcessing();
postProcessing.postProcessNoticeParameter(noticeParameters);
return noticeParameters.toYamlString();
}
}
return null;
}
private static File getAnalysisTargetFile(Artifact artifact, String keyAnalysisPath) {
String analysisDir = artifact.get(keyAnalysisPath);
if (analysisDir == null) return null;
final File analysisFile = new File(analysisDir);
final File targetFolder = new File(analysisDir + "-analysis");
if (!targetFolder.exists()) return null;
return analysisFile;
}
private List getComponentList(List scanResult) throws IOException {
List components = new ArrayList<>();
for (MergedSegmentResult segmentResult : scanResult) {
ComponentSet componentSet = new ComponentSet();
// FIXME: does not unify BSD (undefined) and BSD alike
final List resolvedLicenses = transformer.transformLicenses(segmentResult.getResolvedLicenses());
final List copyrights = segmentResult.getCopyrights();
if (resolvedLicenses.isEmpty()) {
if (!segmentResult.getCopyrights().isEmpty()) {
componentSet.addUnassignedCopyright(segmentResult.getCopyrights());
components.add(componentSet);
}
continue; //TODO: evaluate Scancode licenses}
}
InventoryUtils.initialize(normalizationMetaData);
InventoryUtils.removeMarkers(resolvedLicenses, normalizationMetaData);
if (resolvedLicenses.isEmpty()) continue;
componentSet.setLicenses(resolvedLicenses);
if (!segmentResult.getVariables().isEmpty()) {
componentSet.addVariables(segmentResult.getVariables());
}
if (resolvedLicenses.size() > 1) {
if (splitRequired(componentSet, normalizationMetaData)) {
componentSet.setSimple(true);
}
}
boolean existing = false;
for (ComponentSet component : components) {
if (component.getLicenses().equals(resolvedLicenses)) {
if (!segmentResult.getVariables().isEmpty() && segmentResult.getVariables().equals(component.getVariables())) {
continue;
}
component.addCopyrights(copyrights);
existing = true;
break;
}
}
if (!existing) {
componentSet.setCopyrights(copyrights);
components.add(componentSet);
}
}
//splitting if possible
for (int componentCount = 0; componentCount < components.size(); componentCount++) {
ComponentSet component = components.get(componentCount);
if (!component.isSimple()) continue;
List licenses = component.getLicenses();
if (licenses != null && !licenses.isEmpty() && component.getCopyrights().isEmpty()) {
List newComponents = new ArrayList<>();
for (int j = 0; j < licenses.size(); j++) {
String license = licenses.get(j);
TermsMetaData termsMetaData = normalizationMetaData.getTermsMetaData(license);
if (termsMetaData != null && (termsMetaData.hasVariables() || termsMetaData.getRequiresCopyright() != null && termsMetaData.getRequiresCopyright())) {
ComponentSet componentSet = new ComponentSet();
componentSet.setLicenses(new ArrayList<>(Collections.singleton(license)));
component.getLicenses().remove(license);
if (termsMetaData.hasVariables()) {
for (Variables variable : component.getVariables()) {
if (variable.getLicense().equals(license)) {
List variablesList = new ArrayList<>();
variablesList.add(variable);
componentSet.addVariables(variablesList);
component.getVariables().remove(variable);
break;
}
}
}
newComponents.add(componentSet);
}
}
if (!licenses.isEmpty()) newComponents.add(component);
components.remove(component);
components.addAll(newComponents);
} else {
int variableCount = 0;
for (int j = 0; j < licenses.size(); j++) {
String license = licenses.get(j);
TermsMetaData termsMetaData = normalizationMetaData.getTermsMetaData(license);
if (termsMetaData != null && termsMetaData.hasVariables()) {
variableCount++;
if (variableCount > 1) {
ComponentSet componentSet = new ComponentSet();
componentSet.setSimple(true);
componentSet.setLicenses(Collections.singletonList(license));
component.getLicenses().remove(license);
for (Variables variable : component.getVariables()) {
if (variable.getLicense().equals(license)) {
List variablesList = new ArrayList<>();
variablesList.add(variable);
componentSet.addVariables(variablesList);
component.getVariables().remove(variable);
break;
}
}
componentSet.setCopyrights(component.getCopyrights());
components.add(componentSet);
}
}
}
}
}
return components;
}
public NoticeParameters writeNoticeParameter(List components) {
NoticeParameters noticeParameters = new NoticeParameters();
boolean mainComponent = false;
List subcomponents = new ArrayList<>();
UnassignedInformation unassignedInformation = new UnassignedInformation();
boolean requiresCopyright = false;
for (ComponentSet componentSet : components) {
if (!componentSet.getUnassignedCopyrights().isEmpty()) {
unassignedInformation.addCopyrights(componentSet.getUnassignedCopyrights());
continue;
}
ComponentDefinition componentDefinition = new ComponentDefinition();
if (!componentSet.isSimple()) {
String license = componentSet.getLicenses().get(0);
TermsMetaData termsMetaData = normalizationMetaData.getTermsMetaData(license);
if (termsMetaData != null) {
if (termsMetaData.getRequiresCopyright() != null && termsMetaData.getRequiresCopyright()) {
if (componentSet.getCopyrights() != null) {
componentDefinition.setCopyrights(componentSet.getCopyrights());
}
}
if (termsMetaData.getRequiresCopyright() == null && !componentSet.getCopyrights().isEmpty()) {
componentDefinition.setCopyrights(componentSet.getCopyrights());
}
}
componentDefinition.setAssociatedLicenses(componentSet.getLicenses());
if (!componentSet.getVariables().isEmpty()) {
Map values = componentSet.getVariables().get(0).getValues();
componentDefinition.setVariables(values);
}
//TODO: Derive to effectiveLicense or set componentStatus to "Derivation requires" e.g at multi-licenses
} else {
componentDefinition.setComponentStatus("Segmentation Issue in this component. Split into subcomponents required.");
componentDefinition.setAssociatedLicenses(componentSet.getLicenses());
if (componentDefinition.getCopyrights() != null)
componentDefinition.setCopyrights(componentSet.getCopyrights());
if (!componentSet.getVariables().isEmpty()) {
Map values = componentSet.getVariables().get(0).getValues();
componentDefinition.setVariables(values);
}
}
if (!mainComponent) {
noticeParameters.setComponent(componentDefinition);
mainComponent = true;
} else {
subcomponents.add(componentDefinition);
}
if (!requiresCopyright) {
for (String license : componentSet.getLicenses()) {
TermsMetaData termsMetaData = normalizationMetaData.getTermsMetaData(license);
if (termsMetaData != null) {
if (termsMetaData.getRequiresCopyright() != null) {
if (termsMetaData.getRequiresCopyright()) {
requiresCopyright = true;
break;
}
}
}
}
}
}
if (unassignedInformation.getCopyrights() != null && !requiresCopyright) {
noticeParameters.setUnassignedInformation(unassignedInformation);
}
if (!subcomponents.isEmpty()) noticeParameters.setSubcomponents(subcomponents);
return noticeParameters;
}
private boolean splitRequired(ComponentSet component, NormalizationMetaData normalizationMetaData) {
int variableCount = 0;
boolean requiresCopyright = false;
for (String license : component.getLicenses()) {
TermsMetaData termsMetaData = normalizationMetaData.getTermsMetaData(license);
if (termsMetaData != null) {
if (termsMetaData.hasVariables()) variableCount++;
if (termsMetaData.getRequiresCopyright() == null) {
requiresCopyright = true;
} else if (termsMetaData.getRequiresCopyright()) {
requiresCopyright = true;
}
}
}
return (variableCount > 1 || requiresCopyright);
}
@Getter
@Setter
private class ComponentSet {
protected final List licenses = new ArrayList<>();
protected final List copyrights = new ArrayList<>();
protected final List variables = new ArrayList<>();
protected boolean simple;
protected final List unassignedCopyrights = new ArrayList<>();
public void setLicenses(List licenses) {
this.copyrights.clear();
this.licenses.addAll(licenses);
}
public void setCopyrights(List copyrights) {
this.copyrights.clear();
this.copyrights.addAll(copyrights);
}
public void addUnassignedCopyright(List unassignedCopyrights) {
this.unassignedCopyrights.addAll(unassignedCopyrights);
}
public void addCopyrights(List copyrights) {
this.copyrights.addAll(copyrights);
}
public void addVariables(List variables) {
this.variables.addAll(variables);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy