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