/*
* 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.test.runner.classification;
import static java.util.Arrays.asList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.graph.Dependency;
import org.eclipse.aether.graph.DependencyFilter;
import org.eclipse.aether.graph.DependencyNode;
/**
* Base class for pattern filters.
* <p/>
* The artifact pattern syntax is of the form:
* <pre>
* [groupId]:[artifactId]:[extension]:[classifier]:[version]
* </pre>
*
* @since 4.0
*/
public abstract class AbstractPatternDependencyFilter implements DependencyFilter {
public static final String MAVEN_COORDINATES_SEPARATOR = ":";
public static final String STAR_SYMBOL = "*";
private final Set<String> patterns = new HashSet<String>();
/**
* Creates the filter using the Maven coordinates
*
* @param coordinates that define the inclusion patterns
*/
public AbstractPatternDependencyFilter(final Collection<String> coordinates) {
this.patterns.addAll(coordinates);
}
/**
* Creates the filter using the Maven coordinates
*
* @param coordinates that define the inclusion patterns
*/
public AbstractPatternDependencyFilter(final String... coordinates) {
this(asList(coordinates));
}
/**
* {@inheritDoc}
*/
@Override
public boolean accept(final DependencyNode node, List<DependencyNode> parents) {
final Dependency dependency = node.getDependency();
if (dependency == null) {
return true;
}
return accept(dependency.getArtifact());
}
/**
* Checks if the artifact matches for the pattern defined on this filter.
*
* @param artifact {@link Artifact} to check if matches with the filter.
* @return {@code true} if the artifact matches with the pattern defined.
*/
protected boolean accept(final Artifact artifact) {
for (final String pattern : patterns) {
final boolean matched = accept(artifact, pattern);
if (matched) {
return true;
}
}
return false;
}
private boolean accept(final Artifact artifact, final String pattern) {
final String[] tokens =
new String[] {artifact.getGroupId(), artifact.getArtifactId(), artifact.getExtension(), artifact.getClassifier(),
artifact.getBaseVersion()};
final String[] patternTokens = pattern.split(MAVEN_COORDINATES_SEPARATOR);
// Fail immediately if pattern tokens outnumber tokens to match
boolean matched = (patternTokens.length <= tokens.length);
for (int i = 0; matched && i < patternTokens.length; i++) {
matched = matches(tokens[i], patternTokens[i]);
}
return matched;
}
private boolean matches(final String token, final String pattern) {
boolean matches;
if (supportFullWildcardAndImpliedWildcard(pattern)) {
matches = true;
} else if (supportContainsWildcard(pattern)) {
final String contains = pattern.substring(1, pattern.length() - 1);
matches = (token.contains(contains));
} else if (supportLeadingWildcard(pattern)) {
final String suffix = pattern.substring(1, pattern.length());
matches = token.endsWith(suffix);
} else if (supportTrailingWildcard(pattern)) {
final String prefix = pattern.substring(0, pattern.length() - 1);
matches = token.startsWith(prefix);
}
// Support exact match
else {
matches = token.equals(pattern);
}
return matches;
}
private boolean supportFullWildcardAndImpliedWildcard(String pattern) {
return STAR_SYMBOL.equals(pattern) || pattern.length() == 0;
}
private boolean supportContainsWildcard(String pattern) {
return supportLeadingWildcard(pattern) && supportTrailingWildcard(pattern);
}
private boolean supportLeadingWildcard(String pattern) {
return pattern.startsWith(STAR_SYMBOL);
}
private boolean supportTrailingWildcard(String pattern) {
return pattern.endsWith(STAR_SYMBOL);
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null || !getClass().equals(obj.getClass())) {
return false;
}
final AbstractPatternDependencyFilter that = (AbstractPatternDependencyFilter) obj;
return this.patterns.equals(that.patterns);
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
return patterns.hashCode();
}
}