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

com.metaeffekt.artifact.analysis.flow.notice.NoticeParameterBuilderAnalysis Maven / Gradle / Ivy

There is a newer version: 0.126.0
Show newest version
/*
 * 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