
org.apache.jackrabbit.vault.validation.context.AbstractDependencyResolver Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of vault-validation Show documentation
Show all versions of vault-validation Show documentation
Provides a validation framework with SPI and API for performing validations on FileVault packages
/*
* 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:
*
* - trying lower bound version
* - trying higher bound version
* - trying LATEST version
*
* 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