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

org.metaeffekt.artifact.resolver.ArtifactResolverManager Maven / Gradle / Ivy

There is a newer version: 0.134.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.artifact.resolver;

import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.metaeffekt.artifact.resolver.alpine.AlpinePackageResolver;
import org.metaeffekt.artifact.resolver.deb.DebArtifactResolver;
import org.metaeffekt.artifact.resolver.download.WebAccess;
import org.metaeffekt.artifact.resolver.generic.ArtifactIndex;
import org.metaeffekt.artifact.resolver.generic.IndexConfig;
import org.metaeffekt.artifact.resolver.manager.DownloadEnvironmentManager;
import org.metaeffekt.artifact.resolver.maven.MavenArtifactResolver;
import org.metaeffekt.artifact.resolver.model.ArtifactPartResolver;
import org.metaeffekt.artifact.resolver.model.ArtifactPartType;
import org.metaeffekt.artifact.resolver.model.DownloadLocation;
import org.metaeffekt.artifact.resolver.model.ResolvedArtifactPart;
import org.metaeffekt.artifact.resolver.npm.NpmArtifactResolver;
import org.metaeffekt.artifact.resolver.pypi.PyPIArtifactResolver;
import org.metaeffekt.artifact.resolver.rpm.RpmArtifactResolver;
import org.metaeffekt.artifact.resolver.url.UrlArtifactResolver;
import org.metaeffekt.core.inventory.processor.model.Artifact;

import java.util.*;
import java.util.stream.Collectors;

/**
 * Main ArtifactResolver. Manages a configuration of artifact resolvers and runs them.
 */
@Slf4j
public class ArtifactResolverManager {

    private final DownloadLocation downloadLocation;

    private final WebAccess webAccess;

    /**
     * Resolvers that will be iterated through when an artifact is resolved.
     * 
* The order in which resolvers are added here might affect resolver results: *
    *
  • insertion order is iteration order
  • *
  • for each type, only the first successful resolver's result is used * (see {@link #getResolvedArtifactParts(Artifact, Collection)})
  • *
*/ private final List artifactResolverList = new ArrayList<>(); /** * Central configuration of resolver manager and resolvers. */ private ArtifactResolverConfig artifactResolverConfig; /** * Abstraction for our container runtime. Manages execution environments for different configurations. *
* Keeping this around for debugging and resource management purposes. */ private final DownloadEnvironmentManager environmentManager; public ArtifactResolverManager(@NonNull DownloadLocation downloadLocation, @NonNull WebAccess webAccess, @NonNull ArtifactResolverConfig resolverConfig) { this.downloadLocation = downloadLocation; this.webAccess = webAccess; this.artifactResolverConfig = resolverConfig; final IndexConfig indexConfig = artifactResolverConfig.getIndexConfig(); final ArtifactIndex artifactIndex = new ArtifactIndex(indexConfig); artifactResolverList.add(new MavenArtifactResolver(downloadLocation, webAccess, artifactIndex, artifactResolverConfig.getMavenConfig())); artifactResolverList.add(new NpmArtifactResolver(downloadLocation, webAccess)); artifactResolverList.add(new UrlArtifactResolver(downloadLocation, webAccess)); artifactResolverList.add(new PyPIArtifactResolver(downloadLocation)); if (artifactResolverConfig.getRpmIndexConfig() != null) { artifactResolverList.add(new RpmArtifactResolver(downloadLocation, webAccess, artifactResolverConfig.getRpmIndexConfig())); } if (artifactResolverConfig.getDebArtifactResolverConfig() != null) { artifactResolverList.add(new DebArtifactResolver(downloadLocation, webAccess, artifactResolverConfig.getDebArtifactResolverConfig())); } // add environment-based resolvers if (resolverConfig.getEnvironmentManagerConfig() != null && resolverConfig.getEnvironmentManagerConfig().isEnableEnvironmentManager()) { this.environmentManager = DownloadEnvironmentManager.createIfAvailable(resolverConfig.getEnvironmentManagerConfig()); if (this.environmentManager != null) { artifactResolverList.add( new AlpinePackageResolver(downloadLocation, webAccess, environmentManager, resolverConfig)); } } else { environmentManager = null; } } /** * Resolves the binary form for the given artifact. *
* If you wish to resolve multiple types, consider using * {@link #getResolvedArtifactParts(Artifact, Collection) getResolvedArtifactParts} * * @param artifact The artifact to resolve. Various attributes may be used to feature the resolution. * * @return a resolved part object for whatever was resolved */ public ResolvedArtifactPart resolveBinaryArtifact(Artifact artifact) { return getResolvedArtifactPart(artifact, ArtifactPartType.BINARY_ARTIFACT); } public ResolvedArtifactPart resolveSourceArtifact(Artifact artifact) { return getResolvedArtifactPart(artifact, ArtifactPartType.SOURCE_ARTIFACT); } public ResolvedArtifactPart resolveSourceArchive(Artifact artifact) { return getResolvedArtifactPart(artifact, ArtifactPartType.SOURCE_ARCHIVE); } public ResolvedArtifactPart resolveDescriptor(Artifact artifact) { return getResolvedArtifactPart(artifact, ArtifactPartType.DESCRIPTOR); } /** * Resolves the first artifact resolver for the given artifact and type. *
* Backwards-compatibly with the old getResolvedArtifactPart, this now calls * {@link #getResolvedArtifactParts(Artifact, Collection) getResolvedArtifactParts}. * @param artifact artifact to resolve * @param artifactPartType type of resolver to execute * @return result of the first resolver that worked for this artifact. */ private ResolvedArtifactPart getResolvedArtifactPart(@NonNull Artifact artifact, @NonNull ArtifactPartType artifactPartType) { return getResolvedArtifactParts(artifact, Collections.singleton(artifactPartType)).get(artifactPartType); } /** * Get and resolve all available resolver parts (one per type). * @see #getResolvedArtifactParts(Artifact, Collection) * @param artifact artifact to resolve * @return map of partType to resolved part */ public SortedMap getResolvedArtifactParts( @NonNull final Artifact artifact) { return getResolvedArtifactParts(artifact, null); } /** * Get and resolve all available resolver parts (one per type). * @param artifact artifact to resolve * @param partTypes only resolve given partTypes. Null to resolve all. * @return map of partType to resolved part */ public SortedMap getResolvedArtifactParts( @NonNull final Artifact artifact, Collection partTypes) { return processPartResolvers(collectArtifactPartResolvers(artifact, partTypes)); } /** * Runs part resolvers and returns the result. * @param partResolvers collection of part resolvers to run * @return result of all resolve operations */ private SortedMap processPartResolvers( @NonNull List partResolvers) { final SortedMap typeToResolved = new TreeMap<>(); for (ArtifactPartResolver partResolver : partResolvers) { // don't compute if the map already registered this part as resolved if (typeToResolved.get(partResolver.getArtifactPartType()) != null) { continue; } final ResolvedArtifactPart resolvedArtifactPart = partResolver.get(); if (resolvedArtifactPart == null) { // skip if resolve was unsuccessful continue; } // write successful resolve to map typeToResolved.put(partResolver.getArtifactPartType(), resolvedArtifactPart); } return typeToResolved; } /** * Runs resolution on all parts of an artifact and merges results into the original artifact. * * @param artifact artifact to resolve */ public void resolveAndMergeAll(@NonNull Artifact artifact) { final Artifact clone = new Artifact(artifact); final SortedMap resolvedParts = getResolvedArtifactParts(clone, null); // match certain order for these types for historic reasons. we then remove used ones from the map. merge(artifact, resolvedParts.remove(ArtifactPartType.DESCRIPTOR)); merge(artifact, resolvedParts.remove(ArtifactPartType.BINARY_ARTIFACT)); merge(artifact, resolvedParts.remove(ArtifactPartType.SOURCE_ARTIFACT)); merge(artifact, resolvedParts.remove(ArtifactPartType.SOURCE_ARCHIVE)); // merge types that were not removed yet (not merged yet) in enum-given order (sorted map) for (ResolvedArtifactPart resolvedPart : resolvedParts.values()) { merge(artifact, resolvedPart); } } /** * Cheaply merge enriched results back into the original artifact using {@link Artifact#merge(Artifact)}. * * @param artifact artifact to be modified (merged into) * @param resolveArtifactPart part holding an enriched artifact to merge */ private void merge(@NonNull Artifact artifact, ResolvedArtifactPart resolveArtifactPart) { if (resolveArtifactPart != null) { final Artifact enrichedArtifact = resolveArtifactPart.getEnrichedArtifact(); if (enrichedArtifact != null) { artifact.merge(enrichedArtifact); } } } /** * Gets all part resolvers for an artifact, filtering for the given types. * @param artifact artifact to resolve * @param partTypes types to filter for. {@code null} disables filtering. * @return a list of resolvers */ private List collectArtifactPartResolvers(@NonNull final Artifact artifact, final Collection partTypes) { EnumSet partTypeSet = partTypes == null ? null : EnumSet.copyOf(partTypes); return artifactResolverList.stream() .map(artifactResolver -> artifactResolver.collectResolvers(artifact)) .flatMap(resolvers -> resolvers.getArtifactPartResolvers().stream()) .filter(partResolver -> partTypeSet == null || partTypeSet.contains(partResolver.getArtifactPartType())) .collect(Collectors.toList()); } public boolean isEnvironmentEnabled() { return environmentManager != null; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy