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

com.metaeffekt.artifact.analysis.spdxbom.MapperRunner Maven / Gradle / Ivy

/*
 * 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.spdxbom;


import com.metaeffekt.artifact.analysis.spdxbom.config.AssembledConfig;
import com.metaeffekt.artifact.analysis.spdxbom.context.SpdxDocumentContext;
import com.metaeffekt.artifact.analysis.spdxbom.mapper.ArtifactMapper;
import com.metaeffekt.artifact.analysis.spdxbom.mapper.exception.NoApplicableMapperException;
import org.metaeffekt.core.inventory.processor.model.Artifact;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spdx.library.InvalidSPDXAnalysisException;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.TreeMap;
import java.util.stream.Collectors;

/**
 * Finds and runs the correct mappers (as assembled configs) per-artifact.
* Not threadsafe. */ public class MapperRunner { private static final Logger LOG = LoggerFactory.getLogger(MapperRunner.class); /** * A list of mapper configurations.
* Configs wrap mappers for case matching and execution. */ protected final AssembledConfig[] assembledConfigs; /** * Constructs a new object. * @param assembledConfigs the list of usable mapper configs */ public MapperRunner(List assembledConfigs) { if (assembledConfigs == null) { throw new IllegalArgumentException("assembledConfigs may not be null."); } else if (assembledConfigs.isEmpty()) { throw new IllegalArgumentException("assembledConfigs must contain configs."); } this.assembledConfigs = assembledConfigs.toArray(new AssembledConfig[0]); } public List getApplicableConfigs(Artifact artifact) { List applicableConfigs = new ArrayList<>(); for (AssembledConfig config : assembledConfigs) { if (config.isApplicable(artifact)) { applicableConfigs.add(config); } } return applicableConfigs; } /** * Determines the "best" mapper to use for this artifact.
* Uses {@link #getApplicableConfigs(Artifact)}, then scores them. * @param artifact the artifact to be mapped * @return returns a mapper that best fits the artifact * @throws NoApplicableMapperException when no mapper is configured work with this artifact */ protected AssembledConfig getBestConfig(Artifact artifact) throws NoApplicableMapperException { List applicableConfigs = getApplicableConfigs(artifact); if (applicableConfigs.isEmpty()) { // fail if no mapper applies LOG.error("Couldnot find an applicable mapper for artifact [{}].", artifact.createStringRepresentation()); throw new NoApplicableMapperException("Could not find an applicable mapper."); } // nifty streamy thing to get all configs with maximum property List maximalConfigs = applicableConfigs.stream() .collect(Collectors.groupingBy(AssembledConfig::getSpecificity, TreeMap::new, Collectors.toList())) .lastEntry() .getValue(); // sanity check the nifty streamy thing if (maximalConfigs.isEmpty()) { throw new RuntimeException("Can't happen: no maximalConfigs found from non-empty applicableConfigs."); } else if (maximalConfigs.size() > 1) { // sort configs alphabetically maximalConfigs.sort(Comparator.comparing(config -> config.getMapperToUse().getClass().getSimpleName())); LOG.warn("Found multiple applicable configs with maximal specificity. Choosing alphabetically..."); } // select config to run return maximalConfigs.get(0); } /** * Get and run the most specific mapper that is applicable to this artifact. * * @param artifact to be converted into an spdx item * @param spdxDocumentContext required for conversion * * @return Returns the converted Item. * * @throws InvalidSPDXAnalysisException Throws in case of issues with conversion. */ public ArtifactMapper.Result map(Artifact artifact, SpdxDocumentContext spdxDocumentContext) throws InvalidSPDXAnalysisException, NoApplicableMapperException { return getBestConfig(artifact) .getMapperToUse() .getMapped(artifact, spdxDocumentContext); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy