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

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

import com.metaeffekt.artifact.terms.model.NormalizationMetaData;
import com.metaeffekt.artifact.terms.model.TermsMetaData;
import org.metaeffekt.common.notice.model.ComponentDefinition;
import org.metaeffekt.common.notice.model.NoticeParameters;
import org.metaeffekt.notice.engine.utils.NoticeUtils;

import java.util.*;

public class NoticeParameterValidator {

    private final NormalizationMetaData normalizationMetaData;

    private final NoticeUtils noticeUtils;

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

    public void validateNoticeParameter(NoticeParameters noticeParameters, NoticeParameterValidationContext context) {
        final ComponentDefinition mainComponent = noticeParameters.getComponent();
        validateMainComponentDefinition(mainComponent, context);
        validateComponentDefinition(mainComponent, context);

        for (ComponentDefinition subcomponent: noticeParameters.getSubcomponents()) {
            validateComponentDefinition(subcomponent, context);
        }
        
        for (ContextError contextError : context.getMessages()) {
            switch (contextError.type) {
                case ERROR:
                    context.error(contextError.message);
                    break;
                case WARNING:
                    context.warn(contextError.message);
                    break;
                case INFO:
                    context.info(contextError.message);
                    break;
            }
        }
    }

    public void validateComponentDefinition(ComponentDefinition componentDefinition, NoticeParameterValidationContext context) {
        String componentDefinitionId;

        if (componentDefinition == null) {
            //context.error("Detected null component definition.");
            return;
        }

        if (componentDefinition.getName() != null) {
            componentDefinitionId = componentDefinition.getName();
        } else {
            componentDefinitionId = noticeUtils.getEffectiveLicenses(componentDefinition).toString();
        }

        noticeParameterStatus(componentDefinition, componentDefinitionId, context);
        validateCopyrights(componentDefinition, componentDefinitionId, context);
        validateNote(componentDefinition, componentDefinitionId, context);
        validateVariables(componentDefinition, componentDefinitionId, context);

        validateLicenses(componentDefinition, componentDefinitionId, context);
    }

    public void validateMainComponentDefinition(ComponentDefinition componentDefinition, NoticeParameterValidationContext context) {
        if (componentDefinition == null) {
            context.error("The main component is not defined! Hint: Add a main component to the notice parameter.");
        } else {
            if (componentDefinition.getName() == null || componentDefinition.getName().isEmpty()){
                context.error("The main component needs a name! Hint: Check component name available.");
            }
        }
    }
    
    //Information from NoticeParameter generation
    public void noticeParameterStatus(ComponentDefinition componentDefinition, String id, NoticeParameterValidationContext context) {
        if (componentDefinition == null) return;
        if (componentDefinition.getComponentStatus() != null && !componentDefinition.getComponentStatus().isEmpty()) {
            String msg = "[Component: " + id + "]: " + componentDefinition.getComponentStatus();
            ContextError error = new ContextError(Type.ERROR, msg);
            context.getMessages().add(error);
        }
    }

    public void validateCopyrights(ComponentDefinition componentDefinition, String id, NoticeParameterValidationContext context) {
        if (componentDefinition == null) return;
        for (String license : noticeUtils.getEffectiveLicenses(componentDefinition)) {
            final TermsMetaData tmd = getTermsMetaData(license, context);
            if (tmd.getRequiresCopyright() != null) {
                if (tmd.getRequiresCopyright() && !componentDefinition.hasCopyrights()) {
                    if (!componentDefinition.isMissingCopyrights() || tmd.isMissingCopyrightNotAllowed()) { //null check?
                        if (tmd.isMissingCopyrightNotAllowed()) {
                            String msg = "[Component: " + id + "]: " +  license + " requires copyrights. Add Copyright. Hint: This license does not allow NO copyrights. " +
                                    "Check for default copyright sentence in license.";
                            ContextError error = new ContextError(Type.ERROR, msg);
                            context.getMessages().add(error);
                        } else {
                            String msg = "[Component: " + id + "]: " + license + " requires copyrights. Hint: Insert " +
                                    "copyrights or set flag \"missingCopyrights: true\" in notice parameter";
                            ContextError error = new ContextError(Type.ERROR, msg);
                            context.getMessages().add(error);
                        }
                    }
                } else if (!tmd.getRequiresCopyright() && componentDefinition.hasCopyrights()) {
                    String msg = "[Component: " + id + "]: " +  license + " does not require copyrights, but there are copyrights " +
                            "present in the notice parameter. Hint: Check whether this is on purpose / Consider splitting this " +
                            "component to enable exact assignment of copyrights";
                    ContextError error = new ContextError(Type.INFO, msg);
                    context.getMessages().add(error);
                }
            } else {
                if (!componentDefinition.hasCopyrights() && !componentDefinition.isMissingCopyrights()) {
                    String msg = "[Component: " + id + "]: No information available whether " + license + " requires copyrights. Maybe missing copyrights.";
                    ContextError error = new ContextError(Type.INFO, msg);
                    context.getMessages().add(error);
                }
            }
        }
    }
    
    public void validateNote(ComponentDefinition componentDefinition, String id, NoticeParameterValidationContext context){
        if (componentDefinition == null) return;
        for (String license : noticeUtils.getEffectiveLicenses(componentDefinition)) {
            final TermsMetaData termsMetaData = getTermsMetaData(license, context);
            if (!componentDefinition.isNoteSet()) {
                if (termsMetaData.isRequiresNote()) {
                    if (termsMetaData.getNoteChecklist() != null && !termsMetaData.getNoteChecklist().isEmpty()) {
                        StringBuilder msg = new StringBuilder("[Component: " + id + "]: " + license +
                                " requires a note! Please add all of the following information to the note:");
                        for (String todo : termsMetaData.getNoteChecklist()) {
                            msg.append("\n - ").append(todo);
                        }
                        ContextError error = new ContextError(Type.WARNING, msg.toString());
                        context.getMessages().add(error);
                    } else {
                        String msg = "[Component: " + id + "]: " + license + " requires a note! Hint: Add a note (no checklist available).";
                        ContextError error = new ContextError(Type.WARNING, msg);
                        context.getMessages().add(error);
                    }
                }
            }
            if (componentDefinition.isNoteSet() && componentDefinition.getNote().isEmpty()){
                String msg = "[Component: " + id + "]: Empty note specified. Hint: Check whether note is required.";
                ContextError error = new ContextError(Type.WARNING, msg);
                context.getMessages().add(error);
            }
        }
    }
    
    private void validateVariables(ComponentDefinition componentDefinition, String id, NoticeParameterValidationContext context) {
        if (componentDefinition == null) return;

        int licensesWithVariables = 0;
        for (String effectiveLicense : noticeUtils.getEffectiveLicenses(componentDefinition)) {
            TermsMetaData tmd = getTermsMetaData(effectiveLicense, context);
            if (tmd.getLicenseTemplate() != null && tmd.getLicenseTemplate().contains("{{")) {
                if (componentDefinition.getVariables() == null) {
                    String msg = "[Component: " + id + "]: Provide variable set for " + effectiveLicense + ".";
                    ContextError error = new ContextError(Type.ERROR, msg);
                    context.getMessages().add(error);
                }
                licensesWithVariables++;
            }
        }
        if (componentDefinition.getVariables() == null) return;

        if (licensesWithVariables == 0) {
            String msg = "[Component: " + id + "]: None of the licenses in this component requires variables, but variables are specified. Hint: Check whether license is missing or variables are obsolete.";
            ContextError error = new ContextError(Type.WARNING, msg);
            context.getMessages().add(error);
        } else if (licensesWithVariables == 1) {
            //check if they match
            for (String effectiveLicense : noticeUtils.getEffectiveLicenses(componentDefinition)) {
                TermsMetaData tmd = getTermsMetaData(effectiveLicense, context);
                if (tmd.getLicenseTemplate() != null && tmd.getLicenseTemplate().contains("{{")) {
                    String licenseTemplate = tmd.getLicenseTemplate();
                    for (Map.Entry entry : componentDefinition.getVariables().entrySet()) {
                        String key = "{{" + entry.getKey() + "}}";
                        if (licenseTemplate.contains(key)) {
                            licenseTemplate = licenseTemplate.replace(key, "");
                        } else {
                            String msg = "[Component: " + id + "]: Wrong variable specified. " + key + "is wrong.";
                            ContextError error = new ContextError(Type.ERROR, msg);
                            context.getMessages().add(error);
                        }
                    }
                    if (licenseTemplate.matches(".*\\{\\{([^\\}]+)}}.*")) {
                        String msg = "[Component: " + id + "]: There are still un-replaced variables in the notice Parameter";
                        ContextError error = new ContextError(Type.ERROR, msg);
                        context.getMessages().add(error);
                    }
                }
            }
        } else if (licensesWithVariables > 1) {
            String msg = "[Component: " + id + "]: At least two of the licenses in this component require variables, but only one variable set is specified. Hint: Split into subcomponents and add variable set.";
            ContextError error = new ContextError(Type.ERROR, msg);
            context.getMessages().add(error);
        }

        if (componentDefinition.getVariables().containsValue("")) {
            String msg = "[Component: " + id + "]: At least one variable in component has empty content. Provide Variable content";
            ContextError error = new ContextError(Type.ERROR, msg);
            context.getMessages().add(error);
        }
    }

    public void validateLicenses(ComponentDefinition componentDefinition, String id, NoticeParameterValidationContext context) {
        if(componentDefinition == null) return;
        for (String effectiveLicense : noticeUtils.getEffectiveLicenses(componentDefinition)) {
            // FIXME: use structured data isUnspecific
            if (effectiveLicense.contains("undefined")) {
                String msg = "[Component: " + id + "]: " + effectiveLicense + " is not appropriate as effective license.";
                ContextError error = new ContextError(Type.WARNING, msg);
                context.getMessages().add(error);
            }
        }

        // NOTE: not enforcing any effective license rules here. Effective licenses may be determined using a customer
        //   rule set.
    }

    public TermsMetaData getTermsMetaData(String license, NoticeParameterValidationContext context) {
        final TermsMetaData termsMetaData = normalizationMetaData.resolveTermsMetaData(license);

        if (termsMetaData == null) {
            String msg = "No terms metadata for " + license + "! Hint: Isolate and provide license text to be added to metadata.";
            ContextError error = new ContextError(Type.ERROR, msg);
            context.getMessages().add(error);
            return NoticeUtils.createDefaultTermsMetaData(license);
        } else {
            return termsMetaData;
        }
    }

    public enum Type {
        WARNING,
        ERROR,
        INFO
    }

    public class ContextError {
        Type type;
        String message;
        public ContextError(Type type, String message) {
            this.type = type;
            this.message = message;
        }

        public void addError(NoticeParameterValidationContext context) {
            context.getMessages().add(this);
        }

        @Override
        public int hashCode() {
            return Objects.hash(type, message);
        }

        @Override
        public boolean equals(Object o) {
            if (o == null) {
                return false;
            }
            
            if (o instanceof ContextError) {
                ContextError toCompare = (ContextError) o;
                if (!Objects.equals(toCompare.type, this.type)) {
                    return false;
                }
                if (!Objects.equals(toCompare.message, this.message)) {
                    return false;
                }
            } else {
                return false;
            }
            return true;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy