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

org.metaeffekt.notice.NoticeParameterProcessor Maven / Gradle / Ivy

There is a newer version: 0.132.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 org.metaeffekt.notice;

import com.metaeffekt.artifact.analysis.utils.InventoryUtils;
import com.metaeffekt.artifact.analysis.utils.StringUtils;
import com.metaeffekt.artifact.terms.model.NormalizationMetaData;
import org.metaeffekt.common.notice.model.ComponentDefinition;
import org.metaeffekt.common.notice.model.NoticeParameters;
import org.metaeffekt.common.notice.model.ProjectContext;
import org.metaeffekt.core.inventory.processor.model.Artifact;
import org.metaeffekt.core.inventory.processor.model.Inventory;
import org.metaeffekt.core.inventory.processor.model.LicenseMetaData;
import org.metaeffekt.core.inventory.processor.reader.InventoryReader;
import org.metaeffekt.notice.engine.NoticeEngine;
import org.metaeffekt.notice.engine.utils.NoticeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import static com.metaeffekt.artifact.analysis.metascan.Constants.KEY_NOTICE_PARAMETER;
import static org.metaeffekt.core.inventory.InventoryUtils.joinEffectiveLicenses;
import static org.metaeffekt.core.inventory.processor.model.Constants.ASTERISK;
import static org.metaeffekt.core.inventory.processor.model.Constants.VERSION_PLACHOLDER_PREFIX;

/**
 * Utility primary used by the metaeffekt workbench using the {@link NoticeEngine} to process inventory content.
 */
public class NoticeParameterProcessor {

    private static final Logger LOG = LoggerFactory.getLogger(NoticeParameterProcessor.class);

    private final NoticeUtils noticeUtils;

    public NoticeParameterProcessor(NormalizationMetaData normalizationMetaData) {
        this.noticeUtils = new NoticeUtils(normalizationMetaData);
    }

    /**
     * Iterates the artifacts in the inventory and processes the Notice Parameter column to produce
     * {@link LicenseMetaData} including the resulting notice.
     *
     * @param inventory The inventory to process.
     */
    public void updateNoticeFromNoticeParameter(Inventory inventory) {
        updateNoticeFromNoticeParameter(inventory, null);
    }

    // FIXME: requires optimization; takes 1min (!!) on HD-AE
    /**
     * Iterates the artifacts in the inventory and processes the Notice Parameter column to produce
     * {@link LicenseMetaData} including the resulting notice.
     *
     * @param inventory The inventory to process.
     * @param projectContext The {@link ProjectContext} instance to be used.
     */
    public void updateNoticeFromNoticeParameter(Inventory inventory, ProjectContext projectContext) {
        final NoticeEngine noticeEngine = new NoticeEngine();
        if (projectContext != null) {
            noticeEngine.setProjectContext(projectContext);
        }

        if (inventory == null || inventory.getArtifacts() == null) return;

        // Pass #1: asterisk and version placeholder
        List secondPass = new ArrayList<>();
        for (final Artifact artifact : inventory.getArtifacts()) {

            if (!InventoryUtils.canCarryLicenseMetaData(artifact)) continue;

            final String noticeParameterYaml = artifact.get(KEY_NOTICE_PARAMETER);
            if (StringUtils.notEmpty(noticeParameterYaml)) {
                if (artifact.getVersion().startsWith(VERSION_PLACHOLDER_PREFIX) ||
                    artifact.getVersion().equals(ASTERISK)) {
                    generateNoticeFromNoticeParameter(inventory, noticeEngine, artifact, noticeParameterYaml);
                } else {
                    secondPass.add(artifact);
                }
            }
        }

        // Pass #2: all others (with version placeholder)
        for (final Artifact artifact : secondPass) {

            if (!InventoryUtils.canCarryLicenseMetaData(artifact)) continue;

            final String noticeParameterYaml = artifact.get(KEY_NOTICE_PARAMETER);
            if (StringUtils.notEmpty(noticeParameterYaml)) {
                generateNoticeFromNoticeParameter(inventory, noticeEngine, artifact, noticeParameterYaml);
            }
        }
    }

    private void generateNoticeFromNoticeParameter(Inventory inventory, NoticeEngine noticeEngine, Artifact artifact, String noticeParameterYaml) {
        try {
            final NoticeParameters parameter = readNoticeParameter(noticeParameterYaml);

            // artifact component name is the reference
            if (StringUtils.notEmpty(artifact.getComponent())) {
                ComponentDefinition component = parameter.getComponent();
                if (component == null) {
                    component = new ComponentDefinition();
                    parameter.setComponent(component);
                }
                component.setName(artifact.getComponent());
            }

            // TODO: update effective license dependent on ProjectContext
            final ComponentDefinition componentDefinition = parameter.getComponent();
            updateEffectiveLicense(componentDefinition);

            if (parameter.getSubcomponents() != null) {
                for (ComponentDefinition subComponentDefinition : parameter.getSubcomponents()) {
                    updateEffectiveLicense(subComponentDefinition);
                }
            }

            final String notice = noticeEngine.applyTemplate(parameter, noticeUtils.getNormalizationMetaData());

            LicenseMetaData licenseMetaData = resolveOrCreateLicenseMetadata(inventory, artifact, parameter);
            if (StringUtils.notEmpty(notice)) {
                licenseMetaData.setNotice(notice);
                addLicenseMetaData(inventory, artifact, licenseMetaData);
            } else {
                LOG.warn("No notice parameter for artifact [{}]. Cannot create notice.", artifact.deriveQualifier());
            }
        } catch (Exception e) {
            LOG.error("Cannot process notice parameter for [{}]. Reason: [{}]", artifact.getId(), e.getMessage());
        }

    }

    private void addLicenseMetaData(Inventory inventory, Artifact artifact, LicenseMetaData licenseMetaData) {
        if (inventory.findMatchingLicenseMetaData(artifact) == null) {
            if (licenseMetaData.getVersion() == null) throw new IllegalStateException("Version is null in " + artifact.getId() + ".");
            if (licenseMetaData.getLicense() == null) throw new IllegalStateException("License is null in " + artifact.getId() + ".");
            if (licenseMetaData.getComponent() == null) throw new IllegalStateException("Component is null in " + artifact.getId() + ".");

            LOG.debug("Adding license metadata for {}/{}/{}.", artifact.getComponent(), artifact.getLicense(), artifact.getVersion());
            inventory.getLicenseMetaData().add(licenseMetaData);

            // check whether we generated an inconsistence
            try {
                inventory.findMatchingLicenseMetaData(artifact);
            } catch (Exception e) {
                // in case yes, we remove the just added license metadata
                inventory.getLicenseMetaData().remove(licenseMetaData);
                LOG.error("Inconsistency detected after creating license metadata for [{}].", artifact.deriveQualifier());
            }
        }
    }

    private void updateEffectiveLicense(ComponentDefinition componentDefinition) {
        // FIXME: ProjectContext evaluation missing; currently using default in InventoryUtils
        final List effectiveLicenses = componentDefinition.getEffectiveLicenses();
        if (effectiveLicenses == null || effectiveLicenses.isEmpty()) {
            final List associatedLicenses = componentDefinition.getAssociatedLicenses();
            final String s = InventoryUtils.deriveEffectiveLicenses(associatedLicenses);
            componentDefinition.setEffectiveLicenses(Arrays.asList(s.split("\\|")));
        }
    }

    public LicenseMetaData resolveOrCreateLicenseMetadata(Inventory inventory, Artifact artifact, NoticeParameters noticeParameter) {
        LicenseMetaData licenseMetaData = null;

        // use existing
        if (StringUtils.notEmpty(artifact.getComponent()) && StringUtils.hasText(artifact.getVersion()) && StringUtils.hasText(artifact.getLicense())) {
            licenseMetaData = inventory.findMatchingLicenseMetaData(artifact);
        }

        // create new
        if (licenseMetaData == null) {
            licenseMetaData = new LicenseMetaData();
            licenseMetaData.setComponent(artifact.getComponent());
            licenseMetaData.setLicense(artifact.getLicense());
            if (artifact.getVersion().startsWith(VERSION_PLACHOLDER_PREFIX)) {
                licenseMetaData.setVersion(ASTERISK);
            } else {
                licenseMetaData.setVersion(artifact.getVersion());
            }
            licenseMetaData.set("Type", "automatic");

            if (noticeParameter != null) {
                licenseMetaData.setLicenseInEffect(joinEffectiveLicenses(noticeUtils.getEffectiveLicenses(noticeParameter)));
            } else {
                licenseMetaData.setLicenseInEffect(InventoryUtils.deriveEffectiveLicenses(artifact.getLicense()));
            }
        }
        return licenseMetaData;
    }

    public void validateNoticeParameter(File inventoryFile) throws IOException {
        final Inventory inventory = new InventoryReader().readInventory(inventoryFile);

        validateNoticeParameter(inventory);
    }

    public void validateNoticeParameter(Inventory inventory) {
        for (final Artifact artifact : inventory.getArtifacts()) {
            final String noticeParameterYaml = artifact.get("Notice Parameter");
            if (StringUtils.notEmpty(noticeParameterYaml)) {
                try {
                    readNoticeParameter(noticeParameterYaml);
                } catch (Exception e) {
                    LOG.error("Error parsing artifact {}.", artifact.getId());
                    LOG.error(e.getMessage(), e);
                }
            }
        }
    }

    public NoticeParameters readNoticeParameter(String noticeParameterYaml) {
        // preprocess (inventory conventions)
        noticeParameterYaml = noticeParameterYaml.replaceAll("\n\\.\\.\\.\\.", "\n    ");
        noticeParameterYaml = noticeParameterYaml.replaceAll("\n\\.\\.", "\n  ");
        char nbsp = 160;
        char sp = 10;
        noticeParameterYaml = noticeParameterYaml.replace(nbsp, sp);
        noticeParameterYaml = noticeParameterYaml.replaceAll("\\s\n", "\n");

        // finally read the notice parameter
        return NoticeParameters.readYaml(noticeParameterYaml);
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy