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

org.metaeffekt.notice.engine.utils.NoticeUtils 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.engine.utils;

import com.metaeffekt.artifact.terms.model.NormalizationMetaData;
import com.metaeffekt.artifact.terms.model.TermsMetaData;
import org.apache.commons.lang.StringUtils;
import org.metaeffekt.common.notice.model.ComponentDefinition;
import org.metaeffekt.common.notice.model.NoticeParameters;
import org.metaeffekt.core.inventory.processor.report.PreFormattedEscapeUtils;
import org.metaeffekt.notice.engine.NoticeEngine;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.stream.Collectors;

public class NoticeUtils {

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

    public static final String SEPARATOR_PLUS = " + ";
    public static final String SEPARATOR_COMMA = ", ";

    public final static PreFormattedEscapeUtils ESCAPE_UTILS = new PreFormattedEscapeUtils();

    public final NormalizationMetaData normalizationMetaData;

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

    private TermsMetaData getTermsMetaDataNullable(String license) {
        return normalizationMetaData.resolveTermsMetaData(license);
    }

    private TermsMetaData getTermsMetaDataNonNull(String license) {
        final TermsMetaData termsMetaData = normalizationMetaData.resolveTermsMetaData(license);
        if (termsMetaData == null) {
            return createDefaultTermsMetaData(license);
        } else {
            return termsMetaData;
        }
    }

    public static TermsMetaData createDefaultTermsMetaData(String name){
        TermsMetaData tmd = new TermsMetaData();
        tmd.setCanonicalName(name);
        tmd.setRequiresNote(true);
        tmd.setRequiresCopyright(false);
        tmd.setTemporaryLMD(true);
        return tmd;
    }

    public String enumerate(List originalLicenseList, String conjunction, String article, String language) {
        if (originalLicenseList == null || originalLicenseList.isEmpty()) return "";
        final StringBuilder sb = new StringBuilder();
        for (int i = 0; i < originalLicenseList.size(); i++) {
            String license = originalLicenseList.get(i);

            if (license.contains(SEPARATOR_PLUS)) {
                license = enrichLicenseOption(license, article, language);
            } else {
                license = prependArticle(license, article, language);
            }

            if (i > 0) sb.append(SEPARATOR_COMMA);
            if (i == originalLicenseList.size() - 1 && originalLicenseList.size() > 1) {
                sb.append(conjunction).append(" ");
            }
            sb.append(license);
        }
        return sb.toString();
    }

    private String enrichLicenseOption(String licenseOption, String article, String language) {
        
        final String[] licenses = licenseOption.split(" \\+ ");
        final StringBuilder internalSb = new StringBuilder();
        for (String license : licenses) {
            if (internalSb.length() > 0) {
                internalSb.append(" ").append(getTranslatedTerm("OR_" + language)).append(" ");
            }
            internalSb.append(prependArticle(license, article, language));
        }
        return getTranslatedTerm("EITHER_" + language) + " " + internalSb;
    }

    private String prependArticle(String license, String article, String language) {
        final TermsMetaData termsMetaData = getTermsMetaDataNonNull(license);
        
        if (!termsMetaData.isArticleRequired() && language.equals("en_US")) {
            return license;       
        }
        if (license.startsWith("Permission Terms") && language.equals("de_DE")) {
            return "von " + license;
        }
        return article + " " + license;
    }

    //TODO: Put this in a resource file
    private String getTranslatedTerm(String term) {
        if (term.equals("OR_en_US")) return "or";
        if (term.equals("OR_de_DE")) return "oder";
        if (term.equals("EITHER_en_US")) return "either";
        if (term.equals("EITHER_de_DE")) return "entweder";
        return null;
    }

    public String enumerateX(List list, String conjunction, String article, String language) {
        String s = enumerate(list, conjunction, article, language);
        s = StringUtils.capitalize(s);
        return s;
    }

    public List getAssociatedLicenses(NoticeParameters noticeParameters) {
        final Set aggregated = new HashSet<>(getAssociatedLicenses(noticeParameters.getComponent()));

        for (ComponentDefinition componentDefinition : noticeParameters.getSubcomponents()) {
            aggregated.addAll(getAssociatedLicenses(componentDefinition));
        }

        return aggregated.stream().sorted(String::compareToIgnoreCase).collect(Collectors.toList());
    }

    public List getEffectiveLicenses(NoticeParameters noticeParameters) {
        final Set aggregated = new HashSet<>(getEffectiveLicenses(noticeParameters.getComponent()));

        for (ComponentDefinition componentDefinition : noticeParameters.getSubcomponents()) {
            aggregated.addAll(getEffectiveLicenses(componentDefinition));
        }
        return aggregated.stream().sorted(String::compareToIgnoreCase).collect(Collectors.toList());
    }

    public boolean hasLicensingOption(NoticeParameters noticeParameters) {
        return !getAssociatedLicenses(noticeParameters).equals(getEffectiveLicenses(noticeParameters));
    }

    public List getComponentsWithLicenseOption(NoticeParameters noticeParameters) {
        List componentDefinitionList = new ArrayList();
        if (getOptionalLicenses(noticeParameters.getComponent()) == true) {
            componentDefinitionList.add((noticeParameters.getComponent()));
        }
        for (ComponentDefinition componentDefinition : noticeParameters.getSubcomponents()) {
            if (getOptionalLicenses(componentDefinition) == true) {
                componentDefinitionList.add((componentDefinition));
            }
        }
        return componentDefinitionList;
    }

    private boolean getOptionalLicenses(ComponentDefinition component) {
        return !(component.getEffectiveLicenses() == null);
    }

    private Collection getAssociatedLicenses(ComponentDefinition component) {
        return component.getAssociatedLicenses();
    }

    public Collection getEffectiveLicenses(ComponentDefinition component) {
        if (component.getEffectiveLicenses() == null || component.getEffectiveLicenses().isEmpty()) {
            return component.getAssociatedLicenses();
        } else {
            return component.getEffectiveLicenses();
        }
    }

    public static class NoticeSummary {
        boolean requiresSourceCodeProvision = false;
        boolean requiresLicenseAndNoticeProvision = false;

        List licensesRequiringSourceCodeProvisioning = new ArrayList<>();
        List licensesRequiringLicenseAndNoticeProvisioning = new ArrayList<>();

        public List getLicensesRequiringLicenseAndNoticeProvisioning() {
            return licensesRequiringLicenseAndNoticeProvisioning;
        }

        public List getLicensesRequiringSourceCodeProvisioning() {
            return licensesRequiringSourceCodeProvisioning;
        }

        public boolean isRequiresLicenseAndNoticeProvision() {
            return requiresLicenseAndNoticeProvision;
        }

        public boolean isRequiresSourceCodeProvision() {
            return requiresSourceCodeProvision;
        }

        @Override
        public String toString() {
            return "NoticeSummary{" +
                    "requiresSourceCodeProvision=" + requiresSourceCodeProvision +
                    ", requiresLicenseAndNoticeProvision=" + requiresLicenseAndNoticeProvision +
                    ", licensesRequiringSourceCodeProvisioning=" + licensesRequiringSourceCodeProvisioning +
                    ", licensesRequiringLicenseAndNoticeProvisioning=" + licensesRequiringLicenseAndNoticeProvisioning +
                    '}';
        }
    }

    public NoticeSummary evaluateMeta(NoticeParameters noticeParameters) throws Exception {
        List effectiveLicense = getEffectiveLicenses(noticeParameters);
        NoticeSummary noticeSummary = new NoticeSummary();

        for (String license : effectiveLicense) {
            TermsMetaData termsMetaData = getTermsMetaDataNonNull(license);
            if (termsMetaData.isRequiresSourceCodeProvision()) {
                noticeSummary.requiresSourceCodeProvision = true;
                noticeSummary.licensesRequiringSourceCodeProvisioning.add(license);
            }
        }
        return noticeSummary;
    }
    
    public String getLicenseTemplateName(String license, NoticeEngine noticeEngine) {

        try {
            /*
             * 1. If templateId is specified in TMD: return template ID
             * 2. If license exists in noticeTemplate: return license
             * 3. If representedAs of license exists in noticeTemplate: return representedAs
             * 4. noticeID of representedLicense
             * 5. Repeat 2 and 3 with updatedCanonicalName (canonicalNameHistory)
             * 6. return Generate Template if generation possible
             * 7. return Default Template
             */

            final String language = noticeEngine.getProjectContext().getLanguageMode().toString();
            String template;

            TermsMetaData tmd = normalizationMetaData.resolveTermsMetaData(license);

            // resolve using dedicated template id; the tmd links to the template
            if (tmd != null) {

                // continue with updated license name
                license = tmd.getCanonicalName();

                if (tmd.getNoticeTemplateId() != null) {
                    template = "notice-template/" + language + "/template-id/" + tmd.getNoticeTemplateId() + ".vm";
                    if (noticeEngine.resourceExists(template)) return template;
                }
            }

            template = "notice-template/" + language + "/license-templates/" + license + ".vm";

            // the license may have been renamed, without updating the template name
            if (tmd != null && tmd.getCanonicalNameHistory() != null) {
                for (String historicalCanonicalName : tmd.getCanonicalNameHistory()) {
                    template = "notice-template/" + language + "/license-templates/" + historicalCanonicalName + ".vm";
                    if (noticeEngine.resourceExists(template)) break;
                }
            }

            // return in case the specific template exists
            if (noticeEngine.resourceExists(template)) return template;

            // continue via representedLicenseName

            String representedLicenseName = representedLicenseName(license);
            template = "notice-template/" + language + "/license-templates/" + representedLicenseName + ".vm";
            if (noticeEngine.resourceExists(template)) return template;

            tmd = getTermsMetaDataNullable(representedLicenseName);
            if (tmd != null) {
                if (tmd.getNoticeTemplateId() != null) {
                    template = "notice-template/" + language + "/template-id/" + tmd.getNoticeTemplateId() + ".vm";
                    if (noticeEngine.resourceExists(template)) return template;
                }
            }

            // history fallback; should not be required anymore; since covered above
            final Map historicalCanonicalNameMap = normalizationMetaData.getHistoricalCanonicalNameMap();
            if (historicalCanonicalNameMap.containsValue(license)) {
                for (String key : historicalCanonicalNameMap.keySet()) {
                    String value = historicalCanonicalNameMap.get(key);
                    if (value.equals(license)) {
                        String noticeTemplateID = getTermsMetaDataNonNull(key).getNoticeTemplateId();
                        if (noticeTemplateID != null) {
                            template = "notice-template/" + language + "/template-id/" + noticeTemplateID + ".vm";
                            if (noticeEngine.resourceExists(template)) return template;
                        }
                        template = "notice-template/" + language + "/license-templates/" + key + ".vm";
                        if (noticeEngine.resourceExists(template)) return template;
                    }
                    if (value.equals(representedLicenseName)) {
                        String noticeTemplateID = getTermsMetaDataNonNull(key).getNoticeTemplateId();
                        if (noticeTemplateID != null) {
                            template = "notice-template/" + language + "/template-id/" + noticeTemplateID + ".vm";
                            if (noticeEngine.resourceExists(template)) return template;
                        }
                        template = "notice-template/" + language + "/license-templates/" + key + ".vm";
                        if (noticeEngine.resourceExists(template)) return template;
                    }
                }
            }

            if (generateTemplatePossible(license)) {
                return "notice-template/" + language + "/license-templates/Generate Template.vm";
            } else {
                return "notice-template/" + language + "/license-templates/Default Template.vm";
            }
        } catch (Exception e) {
            throw new IllegalStateException(e.getMessage(), e);
        }
    }

    private boolean generateTemplatePossible(String license) {
        final TermsMetaData tmd = getTermsMetaDataNullable(license);
        if (tmd == null) return false;
        if (tmd.getType() != null && (tmd.isException() || tmd.isExpression() || tmd.isMarker())) return false;
        if (license.contains("(or any later version)")) return false;
        if (tmd.isUnspecific()) return false;
        return tmd.getRequiresCopyright() != null && tmd.getRequiresLicenseText() != null;
    }

    public List processingCopyrights(List inputCopyrights) {
        List copyrights = new ArrayList<>();
        HashSet hashSet = new HashSet<>(inputCopyrights);
        copyrights.addAll(hashSet);
        copyrights.sort(Comparator.naturalOrder());
        return copyrights;
    }
    
    public String getDisplayName(String license) {
        TermsMetaData termsMetaData = getTermsMetaDataNonNull(license);
        if (termsMetaData.getDisplayName() != null) {
            return termsMetaData.getDisplayName();    
        }
        return license;
    }
    
    public List getDisplayNames(List licenses) {
        List displayNames = new ArrayList<>();
        for (String license : licenses) {
            displayNames.add(getDisplayName(license));
        }
        return displayNames;
    }

    public String representedLicenseName(String license) {
        String representedLicenseName;
        TermsMetaData termsMetaData = getTermsMetaDataNonNull(license);
        if (termsMetaData.getRepresentedAs() != null) {
            TermsMetaData representedTMD = getTermsMetaDataNonNull(termsMetaData.getRepresentedAs());
            if (representedTMD.getBaseTerms() != null) {
                representedLicenseName = representedTMD.getBaseTerms();
            }
            else {
                representedLicenseName = termsMetaData.getRepresentedAs();
            }
        } 
        else if (termsMetaData.getBaseTerms() != null){
            representedLicenseName = termsMetaData.getBaseTerms();
        }
        else {
            representedLicenseName = license;
        }
        return representedLicenseName;
    }

    public String getLicenseTemplate(String effectiveLicense, ComponentDefinition componentDefinition) throws Exception {
        TermsMetaData termsMetaData = getTermsMetaDataNonNull(effectiveLicense);
        String licenseTemplate = termsMetaData.getLicenseTemplate();
        if (licenseTemplate == null && termsMetaData.getRepresentedAs() != null) {

            // in case no template was found use the represented license as fallback
            termsMetaData = getTermsMetaDataNonNull(termsMetaData.getRepresentedAs());
            licenseTemplate = termsMetaData.getLicenseTemplate();
        }

        if (licenseTemplate == null) {
           return "";
        }

        // in case a template is available the variable replacement is performed
        return replacePlaceHolders(licenseTemplate, componentDefinition);
    }
    
    private String replacePlaceHolders(String licenseTemplate, ComponentDefinition componentDefinition) throws Exception {
        // Every key should only be used once per license and there should not be multiple Licenses containing
        // placeholders within one component.
        if (!licenseTemplate.contains("{{")) return licenseTemplate;
        if (componentDefinition.getVariables() != null) {
            for (Map.Entry entry : componentDefinition.getVariables().entrySet()) {
                String key = "{{" + entry.getKey() + "}}";
                if (licenseTemplate.contains(key)) {
                    licenseTemplate = licenseTemplate.replace(key, ESCAPE_UTILS.xml(entry.getValue()));
                } else {
                    LOG.warn("The variable {} can't be found in the license template.", entry.getKey());
                }
            }
        }
        // FIXME: No validation whether the input is set at the right placeHolder
        if (licenseTemplate.matches(".*\\{\\{([^\\}]+)}}.*")) {
            throwException("There are still un-replaced variables in the notice Parameter:\n" +
                    "======\n" +
                    "identified license: " + componentDefinition.getAssociatedLicenses() + "\n" +
                    "license template:\n" +
                    ">>>>>>\n" +
                    licenseTemplate.replace("{{", "{*******{").replace("}}", "}******}") + "\n" +
                    "<<<<<<\n");
        }

        return licenseTemplate;
    }
    public boolean nameExisting(ComponentDefinition componentDefinition){
        if (componentDefinition.getName() != null){
            return true;
        }
        return false;
    }
    
    public boolean componentSeparationRequired(NoticeParameters noticeParameters){
        boolean componentSeparationRequired = false;
        List effectiveLicenses = new ArrayList<>();
        for (ComponentDefinition subcomponent : noticeParameters.getSubcomponents()){
            if (nameExisting(subcomponent)) componentSeparationRequired = true;
            effectiveLicenses.addAll(subcomponent.getAssociatedLicenses());
        }
        for (String license : getEffectiveLicenses(noticeParameters.getComponent())){
            if (effectiveLicenses.contains(license)) componentSeparationRequired = true;
        }
        if (componentSeparationRequired) return true;
        return false;
    }
    
    public List getSelectedComponents(List subcomponents, boolean namedComponents){
        List selectedComponents = new ArrayList<>();
        for (ComponentDefinition subcomponent : subcomponents){
            if (nameExisting(subcomponent) && namedComponents){
                selectedComponents.add(subcomponent);
            }
            else if (!nameExisting(subcomponent) && !namedComponents){
                selectedComponents.add(subcomponent);
            }
        }
        return selectedComponents;
    }

    public List getEffectiveLicensesUnnamedComponents(List subcomponents){
        List unnamedComponents = getSelectedComponents(subcomponents, false);
        List effectiveLicenses = new ArrayList<>();
        for (ComponentDefinition unnamedComponent : unnamedComponents){
            effectiveLicenses.addAll(getEffectiveLicenses(unnamedComponent));
        }
        Set set = new HashSet<>(effectiveLicenses);
        effectiveLicenses.clear();
        effectiveLicenses.addAll(set);
        return effectiveLicenses;
    }
    
    private void throwException(String exception){
        throw new IllegalStateException(exception);
    }

    public boolean requiresCopyright(String license) {
        // only call if getRequiresCopyright was checked on null
        final TermsMetaData termsMetaData = getTermsMetaDataNullable(license);
        if (termsMetaData != null) {
            return termsMetaData.getRequiresCopyright();
        }
        return false;
    }
    public boolean requiresLicenseText(String license) {
        // only call if getRequiresLicenseText was checked on null
        return getTermsMetaDataNonNull(license).getRequiresLicenseText();
    }
    
    public String getRightLicenseTemplate(String license) {
        TermsMetaData tmd = getTermsMetaDataNullable(license);
        if (tmd.getLicenseTemplate() != null) return license;
        return representedLicenseName(license);
    }

    public NormalizationMetaData getNormalizationMetaData() {
        return normalizationMetaData;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy