
org.mule.maven.client.internal.MuleVersionSelector Maven / Gradle / Ivy
/*
* Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com
* The software in this package is published under the terms of the CPAL v1.0
* license, a copy of which has been included with this distribution in the
* LICENSE.txt file.
*/
package org.mule.maven.client.internal;
import static org.eclipse.aether.util.artifact.ArtifactIdUtils.toId;
import static org.mule.maven.client.internal.AetherMavenClient.MULE_PLUGIN_CLASSIFIER;
import static org.mule.maven.client.internal.util.VersionChecker.areCompatibleVersions;
import static org.mule.maven.client.internal.util.VersionChecker.isHighestVersion;
import org.mule.maven.client.api.exception.IncompatibleMulePluginVersionResolutionException;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import org.eclipse.aether.RepositoryException;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.collection.UnsolvableVersionConflictException;
import org.eclipse.aether.graph.DependencyFilter;
import org.eclipse.aether.graph.DependencyNode;
import org.eclipse.aether.util.graph.transformer.ConflictResolver;
import org.eclipse.aether.util.graph.transformer.NearestVersionSelector;
import org.eclipse.aether.util.graph.visitor.PathRecordingDependencyVisitor;
/**
* Implementation of {@link ConflictResolver} that determines the winner among conflicting using nearest algorithm for none {@code mule-plugin}
* dependencies and Semantic Version for {@code mule-plugin} dependencies.
* It delegates the resolution to a {@link NearestVersionSelector} when conflictItems are not {@code mule-plugin}.
* By design it is not supported to declare {@code mule-plugin} dependencies with {@link org.eclipse.aether.version.VersionRange}, in that case
* this resolver will throw an {@link IllegalArgumentException}.
*
* @since 1.0
*/
public class MuleVersionSelector extends ConflictResolver.VersionSelector {
private NearestVersionSelector nearestVersionSelector;
public MuleVersionSelector(NearestVersionSelector nearestVersionSelector) {
this.nearestVersionSelector = nearestVersionSelector;
}
@Override
public void selectVersion(ConflictResolver.ConflictContext context) throws RepositoryException {
if (context.getItems().stream()
.allMatch(conflictItem -> conflictItem.getNode().getArtifact().getClassifier().equals(MULE_PLUGIN_CLASSIFIER))) {
ConflictResolver.ConflictItem winner = null;
for (ConflictResolver.ConflictItem item : context.getItems()) {
if (item.getNode().getVersionConstraint().getRange() != null) {
throw newVersionRangeNotSupportedFailure(item.getNode().getArtifact(), context);
}
if (winner == null) {
winner = item;
}
String itemVersion = item.getNode().getVersion().toString();
String winnerVersion = winner.getNode().getVersion().toString();
if (!areCompatibleVersions(itemVersion, winnerVersion)) {
throw newIncompatibleMulePluginVersionFailure(item.getNode().getArtifact(), winner.getNode().getArtifact(), context);
}
if (isHighestVersion(itemVersion, winnerVersion)) {
winner = item;
}
}
context.setWinner(winner);
} else {
nearestVersionSelector.selectVersion(context);
}
}
private IllegalArgumentException newVersionRangeNotSupportedFailure(Artifact artifact,
ConflictResolver.ConflictContext context) {
List> paths = getConflictContextPaths(context);
return new IllegalArgumentException(String.format(
"Version ranges for Mule plugin dependencies (%s) are not supported, semantic version is supported instead",
toId(artifact)),
new UnsolvableVersionConflictException(paths));
}
private IncompatibleMulePluginVersionResolutionException newIncompatibleMulePluginVersionFailure(Artifact candidateArtifact,
Artifact winnerArtifact,
ConflictResolver.ConflictContext context) {
return new IncompatibleMulePluginVersionResolutionException(toId(candidateArtifact), toId(winnerArtifact),
toPaths(getConflictContextPaths(context)));
}
private List> getConflictContextPaths(ConflictResolver.ConflictContext context) {
DependencyFilter filter = (node, parents) -> context.isIncluded(node);
PathRecordingDependencyVisitor visitor = new PathRecordingDependencyVisitor(filter);
context.getRoot().accept(visitor);
return visitor.getPaths();
}
private static String toPaths(Collection> paths) {
String result = "";
if (paths != null) {
Collection strings = new LinkedHashSet<>();
for (List path : paths) {
strings.add(toPath(path));
}
result = strings.toString();
}
return result;
}
private static String toPath(List path) {
StringBuilder buffer = new StringBuilder(256);
for (Iterator it = path.iterator(); it.hasNext();) {
DependencyNode node = it.next();
if (node.getDependency() == null) {
continue;
}
Artifact artifact = node.getDependency().getArtifact();
buffer.append(artifact.getGroupId());
buffer.append(':').append(artifact.getArtifactId());
buffer.append(':').append(artifact.getExtension());
if (artifact.getClassifier().length() > 0) {
buffer.append(':').append(artifact.getClassifier());
}
buffer.append(':').append(node.getVersionConstraint());
if (it.hasNext()) {
buffer.append(" -> ");
}
}
return buffer.toString();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy