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

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