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

org.apache.jackrabbit.vault.validation.context.AbstractDependencyResolver Maven / Gradle / Ivy

Go to download

Provides a validation framework with SPI and API for performing validations on FileVault packages

There is a newer version: 3.8.4
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.apache.jackrabbit.vault.validation.context;

import java.io.IOException;
import java.net.URI;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import org.apache.jackrabbit.vault.packaging.Dependency;
import org.apache.jackrabbit.vault.packaging.PackageId;
import org.apache.jackrabbit.vault.packaging.PackageInfo;
import org.apache.jackrabbit.vault.packaging.VersionRange;
import org.apache.maven.artifact.Artifact;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Abstract package dependency resolver supporting Maven repository dependency location URIs (starting with {@code maven:}).
 * All package dependencies are mapped to Maven coordinates by this class and then resolved via {@link #resolvePackageInfo(MavenCoordinates)}.
 * The resolver comes with a cache so that the same package dependency is not resolved more than once.
 * This class is not thread-safe.
 * @see PackageInfo
 */
public abstract class AbstractDependencyResolver implements DependencyResolver {

    /**
     * the default logger
     */
    private static final Logger log = LoggerFactory.getLogger(AbstractDependencyResolver.class);

    public static final String MAVEN_REPOSITORY_SCHEME = "maven";
    private final Collection packageInfoCache;

    protected AbstractDependencyResolver() {
        this.packageInfoCache = new LinkedList<>();
    }

    protected AbstractDependencyResolver(@NotNull Collection packageInfoCache) {
        this.packageInfoCache = new LinkedList<>(packageInfoCache);
    }

    @Override
    public @NotNull Collection resolvePackageInfo(@NotNull Dependency[] dependencies, @NotNull Map dependencyLocations) throws IOException {
        List packageInfos = new LinkedList<>();
        // resolve dependencies
        for (Dependency dependency : dependencies) {
            PackageInfo packageInfo = null;
            // 1. try to get from cache
            for (PackageInfo packageInfoFromCache : packageInfoCache) {
                if (dependency.matches(packageInfoFromCache.getId())) {
                    log.debug("Dependency is already resolved from project dependencies: {}", dependency);
                    packageInfo = packageInfoFromCache;
                }
            }
            // 2. try to resolve via provided dependency location URIs
            if (packageInfo == null) {
                for (Map.Entry dependencyLocation : dependencyLocations.entrySet()) {
                    if (dependency.matches(dependencyLocation.getKey())) {
                        packageInfo = resolvePackageInfo(MavenCoordinates.parse(dependencyLocation.getValue()));
                    }
                }
            }
            // 3. try to apply some heuristics
            if (packageInfo == null) {
                packageInfo = resolvePackageInfo(dependency);
            }
            if (packageInfo != null) {
                packageInfos.add(packageInfo);
                if (packageInfoCache.contains(packageInfo)) {
                    packageInfoCache.add(packageInfo);
                }
            }
        }
        return packageInfos;
    }

    /**
     * Uses some heuristics to map the package dependency to Maven coordinates.
     * It tries to resolve the package version ranges in the following order:
     * 
    *
  1. trying lower bound version
  2. *
  3. trying higher bound version
  4. *
  5. trying LATEST version
  6. *
* Each one is triggering {@link #resolvePackageInfo(MavenCoordinates)}. * It doesn't leverage any Maven API for version range resolution, therefore this method should be overwritten if there are better ways to resolve version ranges. * @param dependency the dependency from which to retrieve the package info * @return the resolved package info or {@code null} * @throws IOException */ protected @Nullable PackageInfo resolvePackageInfo(@NotNull Dependency dependency) throws IOException { // resolving a version range is not supported with Maven API, but only with lower level Aether API (requires Maven 3.5 or newer) // https://github.com/eclipse/aether-demo/blob/master/aether-demo-snippets/src/main/java/org/eclipse/aether/examples/FindAvailableVersions.java // therefore do an best effort resolve instead final String groupId = dependency.getGroup(); final String artifactId = dependency.getName(); PackageInfo info = null; if (dependency.getRange().isLowInclusive()) { info = resolvePackageInfo(new MavenCoordinates(groupId, artifactId, dependency.getRange().getLow().toString())); } if (info == null && dependency.getRange().isHighInclusive()) { info = resolvePackageInfo(new MavenCoordinates(groupId, artifactId, dependency.getRange().getHigh().toString())); } if (info == null && VersionRange.INFINITE.equals(dependency.getRange())) { info = resolvePackageInfo(new MavenCoordinates(groupId, artifactId, Artifact.LATEST_VERSION)); } if (info == null) { return null; } return info; } /** * Resolves the main meta information of a package dependency given via Maven coordinates. * @param mavenCoordinates the coordinates of the package dependency * @return the resolved package info or {@code null} * @throws IOException */ public abstract @Nullable PackageInfo resolvePackageInfo(@NotNull MavenCoordinates mavenCoordinates) throws IOException; /** Encapsulates Maven coordinates groupId, artifactId, version, packaging (default {@code zip}), classifier (optional) */ public static final class MavenCoordinates { @NotNull private final String groupId; @NotNull private final String artifactId; @NotNull private final String version; @NotNull private final String packaging; @Nullable private final String classifier; private static final String DEFAULT_PACKAGING = "zip"; public MavenCoordinates(@NotNull String groupId, @NotNull String artifactId, @NotNull String version) { this(groupId, artifactId, version, DEFAULT_PACKAGING, null); } public MavenCoordinates(@NotNull String groupId, @NotNull String artifactId, @NotNull String version, @NotNull String packaging, String classifier) { super(); this.groupId = groupId; this.artifactId = artifactId; this.version = version; this.packaging = packaging; this.classifier = classifier; } /** Parses a Maven URI of the format {@code maven:::[:[: 3) { packaging = parts[3]; } String classifier = null; if (parts.length > 4) { classifier = parts[4]; } return new MavenCoordinates(groupId, artifactId, version, packaging, classifier); } public @NotNull String getGroupId() { return groupId; } public @NotNull String getArtifactId() { return artifactId; } public @Nullable String getVersion() { return version; } public @NotNull String getPackaging() { return packaging; } public @Nullable String getClassifier() { return classifier; } @Override public String toString() { return "MavenCoordinates [" + (groupId != null ? "groupId=" + groupId + ", " : "") + (artifactId != null ? "artifactId=" + artifactId + ", " : "") + (version != null ? "version=" + version + ", " : "") + (packaging != null ? "packaging=" + packaging + ", " : "") + (classifier != null ? "classifier=" + classifier : "") + "]"; } @Override public int hashCode() { return Objects.hash(artifactId, classifier, groupId, packaging, version); } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; MavenCoordinates other = (MavenCoordinates) obj; return Objects.equals(artifactId, other.artifactId) && Objects.equals(classifier, other.classifier) && Objects.equals(groupId, other.groupId) && Objects.equals(packaging, other.packaging) && Objects.equals(version, other.version); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy