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

com.metaeffekt.artifact.analysis.version.curation.ConditionalCuratedVersionPartsExtractorCollection Maven / Gradle / Ivy

The 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.version.curation;

import com.metaeffekt.artifact.analysis.dashboard.Dashboard;
import com.metaeffekt.artifact.analysis.utils.JsonSchemaValidator;
import com.metaeffekt.artifact.analysis.utils.SnakeYamlParser;
import com.networknt.schema.SpecVersion;
import org.json.JSONArray;
import org.metaeffekt.core.inventory.processor.report.configuration.CentralSecurityPolicyConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;

public class ConditionalCuratedVersionPartsExtractorCollection {

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

    private final static Map GLOBAL_NATIVE_MATCHERS = new LinkedHashMap<>();

    private final List entries;

    public ConditionalCuratedVersionPartsExtractorCollection(List entries) {
        this.entries = entries;
    }

    public ConditionalCuratedVersionPartsExtractorCollection() {
        this.entries = new ArrayList<>();
    }

    public List getEntries() {
        return entries;
    }

    public List getMatchingExtractors(String version, VersionContext context) {
        final List matchingExtractors = new ArrayList<>();

        for (ConditionalCuratedVersionPartsExtractor entry : entries) {
            if (entry.matches(version, context)) {
                matchingExtractors.add(entry);
            }
        }

        return matchingExtractors;
    }

    public JSONArray toJson() {
        final JSONArray json = new JSONArray();
        for (ConditionalCuratedVersionPartsExtractor entry : entries) {
            json.put(entry.toJson());
        }
        return json;
    }

    @Override
    public String toString() {
        return toJson().toString();
    }

    public static ConditionalCuratedVersionPartsExtractorCollection fromYaml(List yaml) {
        final ConditionalCuratedVersionPartsExtractorCollection matcher = new ConditionalCuratedVersionPartsExtractorCollection();
        if (yaml == null || yaml.isEmpty()) return matcher;

        for (Object entry : yaml) {
            if (entry instanceof Map) {
                try {
                    matcher.getEntries().add(ConditionalCuratedVersionPartsExtractor.fromYaml((Map) entry));
                } catch (Exception e) {
                    LOG.error("Error while parsing curated version extractor entry: " + entry, e);
                }
            } else {
                throw new IllegalArgumentException("Unexpected entry type: " + entry.getClass() + " (" + entry + ")");
            }
        }

        return matcher;
    }

    public static ConditionalCuratedVersionPartsExtractorCollection fromYamlFile(File file) throws IOException {
        assertCuratedVersionsFileValid(file);
        final List yamlData = SnakeYamlParser.parseYamlAsList(SnakeYamlParser.createNoTimestampYaml(), file);
        return fromYaml(yamlData);
    }

    public static List findExtractors(String version, VersionContext context) {
        final List results = new ArrayList<>();

        for (ConditionalCuratedVersionPartsExtractorCollection matcher : GLOBAL_NATIVE_MATCHERS.values()) {
            results.addAll(matcher.getMatchingExtractors(version, context));
        }

        return results;
    }

    public static Optional findFirstExtractor(String version, VersionContext context) {
        for (ConditionalCuratedVersionPartsExtractorCollection matcher : GLOBAL_NATIVE_MATCHERS.values()) {
            final List matchingExtractors = matcher.getMatchingExtractors(version, context);
            if (!matchingExtractors.isEmpty()) {
                return Optional.of(matchingExtractors.get(0));
            }
        }

        return Optional.empty();
    }

    public static void assertCuratedVersionsFileValid(File file) {
        JsonSchemaValidator.assertResourceSchemaAppliesToYamlFile(
                file,
                "specification/jsonschema/curated-versions-matching.json",
                SpecVersion.VersionFlag.V201909,
                "Curated versions Matching",
                CentralSecurityPolicyConfiguration.JSON_SCHEMA_VALIDATION_ERRORS_DEFAULT
                // CentralSecurityPolicyConfiguration.JsonSchemaValidationErrorsHandling.LENIENT
        );
    }

    /**
     * Register a global matcher with a given name.
     *
     * @param name    the name of the matcher, usually the absolute path to the YAML file
     * @param matcher the CuratedVersionMatcher object that has been parsed from the YAML file
     */
    public static void registerGlobalMatcher(String name, ConditionalCuratedVersionPartsExtractorCollection matcher) {
        GLOBAL_NATIVE_MATCHERS.put(name, matcher);
    }

    public static void registerGlobalMatcher(File file) {
        if (file.isDirectory()) {
            for (File child : Objects.requireNonNull(file.listFiles())) {
                registerGlobalMatcher(child);
            }
            return;
        }
        try {
            final ConditionalCuratedVersionPartsExtractorCollection matcher = fromYamlFile(file);
            registerGlobalMatcher(file.getAbsolutePath(), matcher);
        } catch (IOException e) {
            throw new RuntimeException("Failed to load curated version matcher from file: " + file.getAbsolutePath(), e);
        }
    }

    public static void unregisterGlobalMatcher(String name) {
        if (GLOBAL_NATIVE_MATCHERS.remove(name) != null) {
            LOG.warn("Unregistered the global matcher [{}]", name);
        }
    }

    public static void unregisterGlobalMatcher(File file) {
        unregisterGlobalMatcher(file.getAbsolutePath());
    }

    public static Optional applyFirstStep(Optional extractor, String version, VersionContext context) {
        if (extractor == null || !extractor.isPresent()) return Optional.empty();
        final ExtractedCuratedVersionParts result = extractor.get().applyFirstStep(version, context);
        return Optional.ofNullable(result);
    }

    static {
        final InputStream stream = getFileFromResourceAsStream("enrichment/version/curated-versions.yaml");
        final List yamlData = SnakeYamlParser.parseYamlAsList(SnakeYamlParser.createNoTimestampYaml(), stream);
        final ConditionalCuratedVersionPartsExtractorCollection matcher = fromYaml(yamlData);
        registerGlobalMatcher("resources-curated-versions", matcher);
    }

    private static InputStream getFileFromResourceAsStream(String filename) {
        return Dashboard.class.getClassLoader().getResourceAsStream(filename);
    }
}