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

com.metaeffekt.artifact.enrichment.converter.EnrichmentPipelineConverter 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.enrichment.converter;

import com.metaeffekt.artifact.analysis.vulnerability.enrichment.vulnerabilitystatus.VulnerabilityStatus;
import com.metaeffekt.artifact.enrichment.EnrichmentIds;
import com.metaeffekt.artifact.enrichment.InventoryEnricher;
import com.metaeffekt.artifact.enrichment.InventoryEnrichmentPipeline;
import com.metaeffekt.artifact.enrichment.configurations.InventoryValidationEnrichmentConfiguration;
import org.metaeffekt.core.inventory.processor.configuration.ProcessConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.File;
import java.io.StringWriter;
import java.util.Collection;
import java.util.Map;
import java.util.function.Function;

public abstract class EnrichmentPipelineConverter {

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


    public static String toPom(InventoryEnrichmentPipeline pipeline) throws ParserConfigurationException, TransformerException {
        final DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
        final DocumentBuilder docBuilder = docFactory.newDocumentBuilder();

        final Document document = docBuilder.newDocument();

        final Element project = document.createElement("project");
        document.appendChild(project);

        createTextContentNodeIfNN(document, project, "modelVersion", "4.0.0");
        createTextContentNodeIfNN(document, project, "groupId", "org.metaeffekt");
        createTextContentNodeIfNN(document, project, "artifactId", "ae-generated-pom");
        createTextContentNodeIfNN(document, project, "version", "1.0.0-SNAPSHOT");

        final Element build = document.createElement("build");
        project.appendChild(build);

        final Element plugins = document.createElement("plugins");
        build.appendChild(plugins);

        final Element plugin = document.createElement("plugin");
        plugins.appendChild(plugin);

        createTextContentNodeIfNN(document, plugin, "groupId", "com.metaeffekt.artifact.analysis");
        createTextContentNodeIfNN(document, plugin, "artifactId", "ae-inventory-enrichment-plugin");
        createTextContentNodeIfNN(document, plugin, "version", "HEAD-SNAPSHOT");

        final Element executions = document.createElement("executions");
        plugin.appendChild(executions);

        final Element execution = document.createElement("execution");
        executions.appendChild(execution);

        createTextContentNodeIfNN(document, execution, "id", "inventory-enrichment");

        final Element goals = document.createElement("goals");
        execution.appendChild(goals);

        createTextContentNodeIfNN(document, goals, "goal", "enrich-inventory");

        final Element configuration = document.createElement("configuration");
        execution.appendChild(configuration);

        createTextContentNodeIfNN(document, configuration, "inventoryInputFile", pipeline.getInventorySourceFile(), File::getAbsolutePath);
        createTextContentNodeIfNN(document, configuration, "inventoryOutputFile", pipeline.getInventoryResultFile(), File::getAbsolutePath);
        createTextContentNodeIfNN(document, configuration, "mirrorDirectory", pipeline.getBaseMirrorDirectory(), File::getAbsolutePath);
        createTextContentNodeIfNN(document, configuration, "writeIntermediateInventories", pipeline.isWriteIntermediateInventories());
        createTextContentNodeIfNN(document, configuration, "storeIntermediateStepsInInventoryInfo", pipeline.isStoreIntermediateStepsInInventoryInfo());
        createTextContentNodeIfNN(document, configuration, "intermediateInventoriesDirectory", pipeline.getIntermediateInventoriesDirectory(), File::getAbsolutePath);
        createTextContentNodeIfNN(document, configuration, "resumeAtEnrichment", pipeline.getResumeAtEnricher(), e -> e.getConfiguration().getId());

        final Element enrichmentOrder = document.createElement("enrichmentOrder");
        configuration.appendChild(enrichmentOrder);

        for (InventoryEnricher enricher : pipeline.getEnrichers()) {
            final EnrichmentIds id = EnrichmentIds.fromEnricherClass(enricher.getClass());
            if (id == null) {
                throw new IllegalStateException("Enricher [" + enricher.getClass() + "] is not registered in EnrichmentIds");
            }

            createTextContentNodeIfNN(document, enrichmentOrder, "id", id.id);
        }


        for (InventoryEnricher enricher : pipeline.getEnrichers()) {
            final EnrichmentIds id = EnrichmentIds.fromEnricherClass(enricher.getClass());
            if (id == null) {
                throw new IllegalStateException("Enricher [" + enricher.getClass() + "] is not registered in EnrichmentIds");
            }

            final Element enrichment = document.createElement(id.id);
            configuration.appendChild(enrichment);

            final ProcessConfiguration enricherConfiguration = enricher.getConfiguration();

            if (enricherConfiguration != null) {
                final Map configurationMap = enricherConfiguration.getProperties();

                // only add id and active if they are not the default values
                if (!enricher.getConfiguration().getId().equals(enricher.getConfiguration().buildInitialId())) {
                    createTextContentNodeIfNN(document, enrichment, "id", enricher.getConfiguration().getId());
                }
                if (!enricher.getConfiguration().isActive()) {
                    createTextContentNodeIfNN(document, enrichment, "active", enricher.getConfiguration().isActive());
                }

                final boolean isForceAdd = enricherConfiguration instanceof InventoryValidationEnrichmentConfiguration;

                createAndAppendConfigTags(document, enrichment, configurationMap, isForceAdd);
            }
        }

        final TransformerFactory transformerFactory = TransformerFactory.newInstance();
        final Transformer transformer = transformerFactory.newTransformer();
        final DOMSource source = new DOMSource(document);
        final StringWriter writer = new StringWriter();
        final StreamResult result = new StreamResult(writer);
        transformer.transform(source, result);
        return writer.toString();
    }

    private static void createAndAppendConfigTags(Document document, Element enrichment, Map configurationMap, boolean forceAdd) {
        if (configurationMap != null) {
            for (Map.Entry entry : configurationMap.entrySet()) {
                if (entry.getValue() != null) {
                    if (entry.getValue() instanceof Map) {
                        String tagName = entry.getKey();
                        if (tagName.contains(" ")) {
                            tagName = tagName.replaceAll(" ", "-");
                            LOG.warn("Replaced whitespace in tag name [{}]", tagName);
                        }

                        final Element mapElement = document.createElement(tagName);
                        final Map map = (Map) entry.getValue();
                        createAndAppendConfigTags(document, mapElement, map, forceAdd);
                        if (forceAdd || mapElement.hasChildNodes()) {
                            enrichment.appendChild(mapElement);
                        }
                    } else if (entry.getValue() instanceof Collection) {
                        final Element listElement = document.createElement(entry.getKey());
                        final Collection list = (Collection) entry.getValue();
                        for (Object listEntry : list) {
                            if (isUnsupportedPomType(listEntry)) {
                                LOG.warn("Type is not supported in the pom.xml. Skipping entry [{}]", entry.getKey());
                                continue;
                            }

                            if (listEntry instanceof Map) {
                                final Element mapElement = document.createElement("map");
                                final Map map = (Map) listEntry;
                                createAndAppendConfigTags(document, mapElement, map, forceAdd);
                                if (forceAdd || mapElement.hasChildNodes()) {
                                    listElement.appendChild(mapElement);
                                }
                            } else {
                                createTextContentNodeIfNN(document, listElement, "entry", listEntry);
                            }
                        }
                        if (forceAdd || listElement.hasChildNodes()) {
                            enrichment.appendChild(listElement);
                        }
                    } else if (isUnsupportedPomType(entry.getValue())) {
                        LOG.warn("Type is not supported in the pom.xml. Skipping entry [{}]", entry.getKey());
                    } else {
                        createTextContentNodeIfNN(document, enrichment, entry.getKey(), entry.getValue());
                    }
                }
            }
        }
    }

    private static boolean isUnsupportedPomType(Object check) {
        return check instanceof VulnerabilityStatus;
    }

    private static  void createTextContentNodeIfNN(Document document, Element parent, String tagName, T textContent) {
        if (textContent == null) {
            return;
        }
        if (tagName.contains(" ")) {
            tagName = tagName.replaceAll(" ", "-");
            LOG.warn("Replaced whitespace in tag name [{}]", tagName);
        }
        final Element element = document.createElement(tagName);
        element.appendChild(document.createTextNode(String.valueOf(textContent)));
        parent.appendChild(element);
    }

    private static  void createTextContentNodeIfNN(Document document, Element parent, String tagName, T textContent, Function converter) {
        if (textContent == null) {
            return;
        }
        final Element element = document.createElement(tagName);
        element.appendChild(document.createTextNode(String.valueOf(converter.apply(textContent))));
        parent.appendChild(element);
    }
}