You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by sl...@apache.org on 2021/01/23 00:47:20 UTC
[maven-common-artifact-filters] 03/04: Broaden the scope of the
optimizations
This is an automated email from the ASF dual-hosted git repository.
slachiewicz pushed a commit to branch speed
in repository https://gitbox.apache.org/repos/asf/maven-common-artifact-filters.git
commit 830b27b5a5aca5f8506b653dc987d893390321cf
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Fri Nov 20 00:08:33 2020 +0100
Broaden the scope of the optimizations
---
pom.xml | 12 +
.../filter/PatternExcludesArtifactFilter.java | 2 +-
.../filter/PatternIncludesArtifactFilter.java | 937 +++++++++++++++------
.../filter/AbstractPatternArtifactFilterTest.java | 105 ++-
.../filter/OldPatternIncludesArtifactFilter.java} | 106 +--
.../artifact/filter/PatternFilterPerfTest.java | 122 +++
6 files changed, 903 insertions(+), 381 deletions(-)
diff --git a/pom.xml b/pom.xml
index b39ffd3..28c3e23 100644
--- a/pom.xml
+++ b/pom.xml
@@ -160,5 +160,17 @@
</exclusions>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.openjdk.jmh</groupId>
+ <artifactId>jmh-core</artifactId>
+ <version>1.26</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.openjdk.jmh</groupId>
+ <artifactId>jmh-generator-annprocess</artifactId>
+ <version>1.26</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
</project>
diff --git a/src/main/java/org/apache/maven/shared/artifact/filter/PatternExcludesArtifactFilter.java b/src/main/java/org/apache/maven/shared/artifact/filter/PatternExcludesArtifactFilter.java
index b0d7a1e..7b7b267 100644
--- a/src/main/java/org/apache/maven/shared/artifact/filter/PatternExcludesArtifactFilter.java
+++ b/src/main/java/org/apache/maven/shared/artifact/filter/PatternExcludesArtifactFilter.java
@@ -56,7 +56,7 @@ public class PatternExcludesArtifactFilter
if ( !shouldInclude )
{
- addFilteredArtifactId( artifact.getId() );
+ addFilteredArtifactId( artifact );
}
return shouldInclude;
diff --git a/src/main/java/org/apache/maven/shared/artifact/filter/PatternIncludesArtifactFilter.java b/src/main/java/org/apache/maven/shared/artifact/filter/PatternIncludesArtifactFilter.java
index 8d01c71..bf5138a 100644
--- a/src/main/java/org/apache/maven/shared/artifact/filter/PatternIncludesArtifactFilter.java
+++ b/src/main/java/org/apache/maven/shared/artifact/filter/PatternIncludesArtifactFilter.java
@@ -20,14 +20,18 @@ package org.apache.maven.shared.artifact.filter;
*/
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
+import java.util.HashMap;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
+import java.util.Map;
+import java.util.Objects;
import java.util.Set;
import org.apache.maven.artifact.Artifact;
-import org.apache.maven.artifact.ArtifactUtils;
import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
@@ -43,19 +47,20 @@ import org.codehaus.plexus.logging.Logger;
public class PatternIncludesArtifactFilter
implements ArtifactFilter, StatisticsReportingArtifactFilter
{
- private final Set<String> simplePositivePatterns;
+ /** Holds the set of compiled patterns */
+ private final Set<Pattern> patterns;
- private final Set<String> positivePatterns;
-
- private final Set<String> simpleNegativePatterns;
-
- private final Set<String> negativePatterns;
+ /** Holds simple patterns: those that can use direct matching */
+ private final Map<Integer, Map<String, Pattern>> simplePatterns;
+ /** Wether the dependency trail should be checked */
private final boolean actTransitively;
- private final Set<String> patternsTriggered = new HashSet<>();
+ /** Set of patterns that have been triggered */
+ private final Set<Pattern> patternsTriggered = new HashSet<>();
- private final List<String> filteredArtifactIds = new ArrayList<>();
+ /** Set of artifacts that have been filtered out */
+ private final List<Artifact> filteredArtifact = new ArrayList<>();
/**
* @param patterns The pattern to be used.
@@ -72,43 +77,55 @@ public class PatternIncludesArtifactFilter
public PatternIncludesArtifactFilter( final Collection<String> patterns, final boolean actTransitively )
{
this.actTransitively = actTransitively;
- final Set<String> pos = new LinkedHashSet<>();
- final Set<String> spos = new LinkedHashSet<>();
- final Set<String> neg = new LinkedHashSet<>();
- final Set<String> sneg = new LinkedHashSet<>();
+ final Set<Pattern> pat = new LinkedHashSet<>();
+ Map<Integer, Map<String, Pattern>> simplePat = null;
+ boolean allPos = true;
if ( patterns != null && !patterns.isEmpty() )
{
for ( String pattern : patterns )
{
- if ( pattern.startsWith( "!" ) )
+
+ Pattern p = compile( pattern );
+ allPos &= !( p instanceof NegativePattern );
+ pat.add( p );
+ }
+ }
+ // If all patterns are positive, we can check for simple patterns
+ // Simple patterns will match the first tokens and contain no wildcards,
+ // so we can put them in a map and check them using a simple map lookup.
+ if ( allPos )
+ {
+ for ( Iterator<Pattern> it = pat.iterator(); it.hasNext(); )
+ {
+ Pattern p = it.next();
+ String peq = p.translateEquals();
+ if ( peq != null )
{
- if ( pattern.contains( "*" ) )
+ int nb = 0;
+ for ( char ch : peq.toCharArray() )
{
- neg.add( pattern.substring( 1 ) );
+ if ( ch == ':' )
+ {
+ nb++;
+ }
}
- else
+ if ( simplePat == null )
{
- sneg.add( pattern.substring( 1 ) );
+ simplePat = new HashMap<>();
}
- }
- else
- {
- if ( pattern.contains( "*" ) )
+ Map<String, Pattern> peqm = simplePat.get( nb );
+ if ( peqm == null )
{
- pos.add( pattern );
- }
- else
- {
- spos.add( pattern );
+ peqm = new HashMap<>();
+ simplePat.put( nb, peqm );
}
+ peqm.put( peq, p );
+ it.remove();
}
}
}
-
- positivePatterns = pos;
- simplePositivePatterns = spos;
- negativePatterns = neg;
- simpleNegativePatterns = sneg;
+ this.simplePatterns = simplePat;
+ this.patterns = pat;
}
/** {@inheritDoc} */
@@ -118,7 +135,7 @@ public class PatternIncludesArtifactFilter
if ( !shouldInclude )
{
- addFilteredArtifactId( artifact.getId() );
+ addFilteredArtifactId( artifact );
}
return shouldInclude;
@@ -130,369 +147,783 @@ public class PatternIncludesArtifactFilter
*/
protected boolean patternMatches( final Artifact artifact )
{
- return positiveMatch( artifact ) == Boolean.TRUE || negativeMatch( artifact ) == Boolean.FALSE;
+ // Check if the main artifact matches
+ char[][] tokens = new char[][] {
+ emptyOrChars( artifact.getGroupId() ),
+ emptyOrChars( artifact.getArtifactId() ),
+ emptyOrChars( artifact.getType() ),
+ emptyOrChars( artifact.getBaseVersion() )
+ };
+ Boolean match = match( tokens );
+ if ( match != null )
+ {
+ return match;
+ }
+
+ if ( actTransitively )
+ {
+ final List<String> depTrail = artifact.getDependencyTrail();
+
+ if ( depTrail != null && depTrail.size() > 1 )
+ {
+ for ( String trailItem : depTrail )
+ {
+ char[][] depTokens = tokenizeAndSplit( trailItem );
+ match = match( depTokens );
+ if ( match != null)
+ {
+ return match;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private Boolean match( char[][] tokens )
+ {
+ if ( simplePatterns != null && simplePatterns.size() > 0 )
+ {
+ // We add the parts one by one to the builder
+ StringBuilder sb = new StringBuilder();
+ for ( int i = 0; i < 4; i++ )
+ {
+ if ( i > 0 )
+ {
+ sb.append( ":" );
+ }
+ sb.append( tokens[i] );
+ Map<String, Pattern> map = simplePatterns.get( i );
+ if ( map != null )
+ {
+ // Check if one of the pattern matches
+ Pattern p = map.get( sb.toString() );
+ if ( p != null )
+ {
+ patternsTriggered.add( p );
+ return true;
+ }
+ }
+ }
+ }
+ // Check all other patterns
+ for ( Pattern pattern : patterns )
+ {
+ if ( pattern.matches( tokens ) )
+ {
+ patternsTriggered.add( pattern );
+ return !(pattern instanceof NegativePattern);
+ }
+ }
+
+ return null;
}
/**
- * @param artifactId add artifact to the filtered artifacts list.
+ * @param artifact add artifact to the filtered artifacts list.
*/
- protected void addFilteredArtifactId( final String artifactId )
+ protected void addFilteredArtifactId( final Artifact artifact )
{
- filteredArtifactIds.add( artifactId );
+ filteredArtifact.add( artifact );
}
- private Boolean negativeMatch( final Artifact artifact )
+ /** {@inheritDoc} */
+ public void reportMissedCriteria( final Logger logger )
{
- if ( simpleNegativePatterns != null && !simpleNegativePatterns.isEmpty() )
+ // if there are no patterns, there is nothing to report.
+ if ( !patterns.isEmpty() )
{
- if ( simpleMatch( artifact, simpleNegativePatterns ) )
+ final List<Pattern> missed = new ArrayList<>( patterns );
+ missed.removeAll( patternsTriggered );
+
+ if ( !missed.isEmpty() && logger.isWarnEnabled() )
{
- return true;
+ final StringBuilder buffer = new StringBuilder();
+
+ buffer.append( "The following patterns were never triggered in this " );
+ buffer.append( getFilterDescription() );
+ buffer.append( ':' );
+
+ for ( Pattern pattern : missed )
+ {
+ buffer.append( "\no '" ).append( pattern ).append( "'" );
+ }
+
+ buffer.append( "\n" );
+
+ logger.warn( buffer.toString() );
}
}
- if ( negativePatterns == null || negativePatterns.isEmpty() )
- {
- return null;
- }
- else
+ }
+
+ @Override
+ public String toString()
+ {
+ return "Includes filter:" + getPatternsAsString();
+ }
+
+ /**
+ * @return pattern as a string.
+ */
+ protected String getPatternsAsString()
+ {
+ final StringBuilder buffer = new StringBuilder();
+ for ( Pattern pattern : patterns )
{
- return match( artifact, negativePatterns );
+ buffer.append( "\no '" ).append( pattern ).append( "'" );
}
+
+ return buffer.toString();
}
/**
- * @param artifact check for positive match.
- * @return true/false.
+ * @return description.
*/
- protected Boolean positiveMatch( final Artifact artifact )
+ protected String getFilterDescription()
{
- if ( simplePositivePatterns != null && !simplePositivePatterns.isEmpty() )
+ return "artifact inclusion filter";
+ }
+
+ /** {@inheritDoc} */
+ public void reportFilteredArtifacts( final Logger logger )
+ {
+ if ( !filteredArtifact.isEmpty() && logger.isDebugEnabled() )
{
- if ( simpleMatch( artifact, simplePositivePatterns ) )
+ final StringBuilder buffer =
+ new StringBuilder( "The following artifacts were removed by this " + getFilterDescription() + ": " );
+
+ for ( Artifact artifactId : filteredArtifact )
{
- return true;
+ buffer.append( '\n' ).append( artifactId.getId() );
}
+
+ logger.debug( buffer.toString() );
}
- if ( positivePatterns == null || positivePatterns.isEmpty() )
+ }
+
+ /** {@inheritDoc} */
+ public boolean hasMissedCriteria()
+ {
+ // if there are no patterns, there is nothing to report.
+ if ( !patterns.isEmpty() )
{
- return null;
+ final List<Pattern> missed = new ArrayList<>( patterns );
+ missed.removeAll( patternsTriggered );
+
+ return !missed.isEmpty();
}
- else
+
+ return false;
+ }
+
+ private static final char[] EMPTY = new char[0];
+
+ private static final char[] ANY = new char[] { '*' };
+
+ static char[] emptyOrChars( String str )
+ {
+ return str != null && str.length() > 0 ? str.toCharArray() : EMPTY;
+ }
+
+ static char[] anyOrChars( char[] str )
+ {
+ return str.length > 1 || ( str.length == 1 && str[0] != '*' ) ? str : ANY;
+ }
+
+ static char[][] tokenizeAndSplit( String pattern )
+ {
+ String[] stokens = pattern.split( ":" );
+ char[][] tokens = new char[ stokens.length ][];
+ for ( int i = 0; i < stokens.length; i++ )
{
- return match( artifact, positivePatterns );
+ tokens[i] = emptyOrChars( stokens[i] );
}
+ return tokens;
}
- private boolean simpleMatch( final Artifact artifact, final Set<String> patterns )
+ static boolean match( char[] patArr, char[] strArr, boolean isVersion )
{
- final String shortId = ArtifactUtils.versionlessKey( artifact );
- if ( patterns.contains( shortId ) )
+ int patIdxStart = 0;
+ int patIdxEnd = patArr.length - 1;
+ int strIdxStart = 0;
+ int strIdxEnd = strArr.length - 1;
+ char ch;
+
+ boolean containsStar = false;
+ for ( char aPatArr : patArr )
{
- patternsTriggered.add( shortId );
- return true;
+ if ( aPatArr == '*' )
+ {
+ containsStar = true;
+ break;
+ }
}
- final String id = artifact.getDependencyConflictId();
- if ( patterns.contains( id ) )
+ if ( !containsStar )
{
- patternsTriggered.add( id );
- return true;
+ if ( isVersion && ( patArr[0] == '[' || patArr[0] == '(' ) )
+ {
+ return isVersionIncludedInRange( String.valueOf( strArr ), String.valueOf( patArr ) );
+ }
+ // No '*'s, so we make a shortcut
+ if ( patIdxEnd != strIdxEnd )
+ {
+ return false; // Pattern and string do not have the same size
+ }
+ for ( int i = 0; i <= patIdxEnd; i++ )
+ {
+ ch = patArr[i];
+ if ( ch != '?' && ch != strArr[i] )
+ {
+ return false; // Character mismatch
+ }
+ }
+ return true; // String matches against pattern
}
- final String wholeId = artifact.getId();
- if ( patterns.contains( wholeId ) )
+ if ( patIdxEnd == 0 )
{
- patternsTriggered.add( wholeId );
- return true;
+ return true; // Pattern contains only '*', which matches anything
}
- return false;
- }
-
- private boolean match( final Artifact artifact, final Iterable<String> patterns )
- {
- final String shortId = ArtifactUtils.versionlessKey( artifact );
- final String id = artifact.getDependencyConflictId();
- final String wholeId = artifact.getId();
-
- if ( matchAgainst( wholeId, patterns, false ) )
+ // Process characters before first star
+ while ( ( ch = patArr[patIdxStart] ) != '*' && strIdxStart <= strIdxEnd )
{
- return true;
+ if ( ch != '?' && ch != strArr[strIdxStart] )
+ {
+ return false; // Character mismatch
+ }
+ patIdxStart++;
+ strIdxStart++;
}
-
- if ( matchAgainst( id, patterns, false ) )
+ if ( strIdxStart > strIdxEnd )
{
+ // All characters in the string are used. Check if only '*'s are
+ // left in the pattern. If so, we succeeded. Otherwise failure.
+ for ( int i = patIdxStart; i <= patIdxEnd; i++ )
+ {
+ if ( patArr[i] != '*' )
+ {
+ return false;
+ }
+ }
return true;
}
- if ( matchAgainst( shortId, patterns, false ) )
+ // Process characters after last star
+ while ( ( ch = patArr[patIdxEnd] ) != '*' && strIdxStart <= strIdxEnd )
{
+ if ( ch != '?' && ch != strArr[strIdxEnd] )
+ {
+ return false; // Character mismatch
+ }
+ patIdxEnd--;
+ strIdxEnd--;
+ }
+ if ( strIdxStart > strIdxEnd )
+ {
+ // All characters in the string are used. Check if only '*'s are
+ // left in the pattern. If so, we succeeded. Otherwise failure.
+ for ( int i = patIdxStart; i <= patIdxEnd; i++ )
+ {
+ if ( patArr[i] != '*' )
+ {
+ return false;
+ }
+ }
return true;
}
- if ( actTransitively )
+ // process pattern between stars. padIdxStart and patIdxEnd point
+ // always to a '*'.
+ while ( patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd )
{
- final List<String> depTrail = artifact.getDependencyTrail();
-
- if ( depTrail != null && depTrail.size() > 1 )
+ int patIdxTmp = -1;
+ for ( int i = patIdxStart + 1; i <= patIdxEnd; i++ )
{
- for ( String trailItem : depTrail )
+ if ( patArr[i] == '*' )
{
- if ( matchAgainst( trailItem, patterns, true ) )
+ patIdxTmp = i;
+ break;
+ }
+ }
+ if ( patIdxTmp == patIdxStart + 1 )
+ {
+ // Two stars next to each other, skip the first one.
+ patIdxStart++;
+ continue;
+ }
+ // Find the pattern between padIdxStart & padIdxTmp in str between
+ // strIdxStart & strIdxEnd
+ int patLength = ( patIdxTmp - patIdxStart - 1 );
+ int strLength = ( strIdxEnd - strIdxStart + 1 );
+ int foundIdx = -1;
+ strLoop: for ( int i = 0; i <= strLength - patLength; i++ )
+ {
+ for ( int j = 0; j < patLength; j++ )
+ {
+ ch = patArr[patIdxStart + j + 1];
+ if ( ch != '?' && ch != strArr[strIdxStart + i + j] )
{
- return true;
+ continue strLoop;
}
}
+
+ foundIdx = strIdxStart + i;
+ break;
+ }
+
+ if ( foundIdx == -1 )
+ {
+ return false;
}
+
+ patIdxStart = patIdxTmp;
+ strIdxStart = foundIdx + patLength;
}
- return false;
+ // All characters in the string are used. Check if only '*'s are left
+ // in the pattern. If so, we succeeded. Otherwise failure.
+ for ( int i = patIdxStart; i <= patIdxEnd; i++ )
+ {
+ if ( patArr[i] != '*' )
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ static boolean isVersionIncludedInRange( final String version, final String range )
+ {
+ try
+ {
+ return VersionRange.createFromVersionSpec( range ).containsVersion( new DefaultArtifactVersion( version ) );
+ }
+ catch ( final InvalidVersionSpecificationException e )
+ {
+ return false;
+ }
}
- private boolean matchAgainst( final String value, final Iterable<String> patterns, final boolean regionMatch )
+ static Pattern compile( String pattern )
{
- final String[] tokens = value.split( ":" );
- for ( String pattern : patterns )
+ if ( pattern.startsWith( "!" ) )
+ {
+ return new NegativePattern( pattern, compile( pattern.substring( 1 ) ) );
+ }
+ else
{
- String[] patternTokens = pattern.split( ":" );
-
- if ( patternTokens.length == 5 && tokens.length < 5 )
+ char[][] stokens = tokenizeAndSplit( pattern );
+ char[][] tokens = new char[ stokens.length ][];
+ for ( int i = 0; i < stokens.length; i++ )
{
- // 4th element is the classifier
- if ( !"*".equals( patternTokens[3] ) )
+ tokens[i] = anyOrChars( stokens[i] );
+ }
+ if ( tokens.length > 5 )
+ {
+ throw new IllegalArgumentException( "Invalid pattern: " + pattern );
+ }
+ // we only accept 5 tokens if the classifier = '*'
+ if ( tokens.length == 5 )
+ {
+ if ( tokens[3] != ANY )
{
- // classifier required, cannot be a match
- return false;
+ throw new IllegalArgumentException( "Invalid pattern: " + pattern );
}
- patternTokens = new String[] { patternTokens[0], patternTokens[1], patternTokens[2], patternTokens[4] };
+ tokens = new char[][] { tokens[0], tokens[1], tokens[2], tokens[4] };
}
-
- // fail immediately if pattern tokens outnumber tokens to match
- boolean matched = patternTokens.length <= tokens.length;
-
- for ( int i = 0; matched && i < patternTokens.length; i++ )
+ //
+ // Check the 4 tokens and build an appropriate Pattern
+ // Special care needs to be taken if the first or the last part is '*'
+ // because this allows the '*' to match multiple tokens
+ //
+ if ( tokens.length == 1 )
{
- matched = matches( tokens[i], patternTokens[i] );
+ if ( tokens[0] == ANY )
+ {
+ // *
+ return all( pattern );
+ }
+ else
+ {
+ // [pat0]
+ return match( pattern, tokens[0], 0 );
+ }
}
-
- // case of starting '*' like '*:jar:*'
- // This really only matches from the end instead.....
- if ( !matched && patternTokens.length < tokens.length && isFirstPatternWildcard( patternTokens ) )
+ if ( tokens.length == 2 )
{
- matched = true;
- int tokenOffset = tokens.length - patternTokens.length;
- for ( int i = 0; matched && i < patternTokens.length; i++ )
+ if ( tokens[0] == ANY )
+ {
+ if ( tokens[1] == ANY )
+ {
+ // *:*
+ return all( pattern );
+ }
+ else
+ {
+ // *:[pat1]
+ return match( pattern, tokens[1], 0, 3 );
+ }
+ }
+ else
{
- matched = matches( tokens[i + tokenOffset], patternTokens[i] );
+ if ( tokens[1] == ANY )
+ {
+ // [pat0]:*
+ return match( pattern, tokens[0], 0 );
+ }
+ else
+ {
+ // [pat0]:[pat1]
+ Pattern m00 = match( tokens[0], 0 );
+ Pattern m11 = match( tokens[1], 1 );
+ return and( pattern, m00, m11 );
+ }
}
}
-
- if ( matched )
+ if ( tokens.length == 3 )
{
- patternsTriggered.add( pattern );
- return true;
+ if ( tokens[0] == ANY )
+ {
+ if ( tokens[1] == ANY )
+ {
+ if ( tokens[2] == ANY )
+ {
+ // *:*:*
+ return all( pattern );
+ }
+ else
+ {
+ // *:*:[pat2]
+ return match( pattern, tokens[2], 2, 3 );
+ }
+ }
+ else
+ {
+ if ( tokens[2] == ANY )
+ {
+ // *:[pat1]:*
+ return match( pattern, tokens[1], 1, 2 );
+ }
+ else
+ {
+ // *:[pat1]:[pat2]
+ Pattern m11 = match( tokens[1], 1 );
+ Pattern m12 = match( tokens[1], 2 );
+ Pattern m22 = match( tokens[2], 2 );
+ Pattern m23 = match( tokens[2], 3 );
+ return or( pattern, and( m11, m22 ), and( m12, m23 ) );
+ }
+ }
+ }
+ else
+ {
+ if ( tokens[1] == ANY )
+ {
+ if ( tokens[2] == ANY )
+ {
+ // [pat0]:*:*
+ return match( pattern, tokens[0], 0, 1 );
+ }
+ else
+ {
+ // [pat0]:*:[pat2]
+ Pattern m00 = match( tokens[0], 0 );
+ Pattern m223 = match( tokens[2], 2, 3 );
+ return and( pattern, m00, m223 );
+ }
+ }
+ else
+ {
+ if ( tokens[2] == ANY )
+ {
+ // [pat0]:[pat1]:*
+ Pattern m00 = match( tokens[0], 0 );
+ Pattern m11 = match( tokens[1], 1 );
+ return and( pattern, m00, m11 );
+ }
+ else
+ {
+ // [pat0]:[pat1]:[pat2]
+ Pattern m00 = match( tokens[0], 0 );
+ Pattern m11 = match( tokens[1], 1 );
+ Pattern m22 = match( tokens[2], 2 );
+ return and( pattern, m00, m11, m22 );
+ }
+ }
+ }
}
-
- if ( regionMatch && value.contains( pattern ) )
+ if ( tokens.length == 4 )
{
- patternsTriggered.add( pattern );
- return true;
+ List<Pattern> patterns = new ArrayList<>();
+ for ( int i = 0; i < 4; i++ )
+ {
+ if ( tokens[i] != ANY )
+ {
+ patterns.add( match( tokens[i], i ) );
+ }
+ }
+ return and( pattern, patterns.toArray( new Pattern[0] ) );
}
-
+ throw new IllegalStateException();
}
- return false;
-
}
- private boolean isFirstPatternWildcard( String[] patternTokens )
+ private static Pattern match( String pattern, char[] token, int posVal )
{
- return patternTokens.length > 0 && "*".equals( patternTokens[0] );
+ return match( pattern, token, posVal, posVal );
}
- /**
- * Gets whether the specified token matches the specified pattern segment.
- *
- * @param token the token to check
- * @param pattern the pattern segment to match, as defined above
- * @return <code>true</code> if the specified token is matched by the specified pattern segment
- */
- private boolean matches( final String token, final String pattern )
+ private static Pattern match( char[] token, int posVal )
{
- boolean matches;
+ return match( "", token, posVal, posVal );
+ }
- // support full wildcard and implied wildcard
- if ( "*".equals( pattern ) || pattern.length() == 0 )
+ private static Pattern match( String pattern, char[] token, int posMin, int posMax )
+ {
+ boolean hasWildcard = false;
+ for ( char ch : token )
{
- matches = true;
+ if ( ch == '*' || ch == '?' )
+ {
+ hasWildcard = true;
+ break;
+ }
}
- // support contains wildcard
- else if ( pattern.startsWith( "*" ) && pattern.endsWith( "*" ) )
+ if ( hasWildcard || posMax == 3 )
{
- final String contains = pattern.substring( 1, pattern.length() - 1 );
-
- matches = token.contains( contains );
+ return new PosPattern( pattern, token, posMin, posMax );
}
- // support leading wildcard
- else if ( pattern.startsWith( "*" ) )
+ else
{
- final String suffix = pattern.substring( 1 );
-
- matches = token.endsWith( suffix );
+ return new EqPattern( pattern, token, posMin, posMax );
}
- // support trailing wildcard
- else if ( pattern.endsWith( "*" ) )
- {
- final String prefix = pattern.substring( 0, pattern.length() - 1 );
+ }
- matches = token.startsWith( prefix );
- }
- // support wildcards in the middle of a pattern segment
- else if ( pattern.indexOf( '*' ) > -1 )
- {
- String[] parts = pattern.split( "\\*" );
- int lastPartEnd = -1;
- boolean match = true;
+ private static Pattern match( char[] token, int posMin, int posMax )
+ {
+ return new PosPattern( "", token, posMin, posMax );
+ }
- for ( String part : parts )
- {
- int idx = token.indexOf( part );
- if ( idx <= lastPartEnd )
- {
- match = false;
- break;
- }
+ private static Pattern and( String pattern, Pattern... patterns )
+ {
+ return new AndPattern( pattern, patterns );
+ }
- lastPartEnd = idx + part.length();
- }
+ private static Pattern and( Pattern... patterns )
+ {
+ return and( "", patterns );
+ }
- matches = match;
+ private static Pattern or( String pattern, Pattern... patterns )
+ {
+ return new OrPattern( pattern, patterns );
+ }
+
+ private static Pattern or( Pattern... patterns )
+ {
+ return or( "", patterns );
+ }
+
+ private static Pattern all( String pattern )
+ {
+ return new MatchAllPattern( pattern );
+ }
+
+ static abstract class Pattern
+ {
+ private final String pattern;
+
+ public Pattern( String pattern )
+ {
+ this.pattern = Objects.requireNonNull( pattern );
}
- // support versions range
- else if ( pattern.startsWith( "[" ) || pattern.startsWith( "(" ) )
+
+ public abstract boolean matches( char[][] parts );
+
+ public String translateEquals()
{
- matches = isVersionIncludedInRange( token, pattern );
+ return null;
}
- // support exact match
- else
+
+ public String translateEquals( int pos )
{
- matches = token.equals( pattern );
+ return null;
}
- return matches;
+ @Override
+ public String toString() {
+ return pattern;
+ }
}
- private boolean isVersionIncludedInRange( final String version, final String range )
+ static class AndPattern extends Pattern
{
- try
+ private final Pattern[] patterns;
+
+ public AndPattern( String pattern, Pattern[] patterns )
{
- return VersionRange.createFromVersionSpec( range ).containsVersion( new DefaultArtifactVersion( version ) );
+ super( pattern );
+ this.patterns = patterns;
}
- catch ( final InvalidVersionSpecificationException e )
+
+ @Override
+ public boolean matches( char[][] parts )
{
- return false;
+ for ( Pattern pattern : patterns )
+ {
+ if ( !pattern.matches( parts ) )
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public String translateEquals()
+ {
+ String[] strings = new String[ patterns.length ];
+ for ( int i = 0; i < patterns.length; i++ )
+ {
+ strings[i] = patterns[i].translateEquals( i );
+ if ( strings[i] == null )
+ {
+ return null;
+ }
+ }
+ StringBuilder sb = new StringBuilder();
+ for ( int i = 0; i < strings.length; i++ )
+ {
+ if ( i > 0 )
+ {
+ sb.append( ":" );
+ }
+ sb.append( strings[i] );
+ }
+ return sb.toString();
}
}
- /** {@inheritDoc} */
- public void reportMissedCriteria( final Logger logger )
+ static class OrPattern extends Pattern
{
- // if there are no patterns, there is nothing to report.
- if ( !positivePatterns.isEmpty() || !negativePatterns.isEmpty()
- || !simplePositivePatterns.isEmpty() || !simpleNegativePatterns.isEmpty() )
- {
- final List<String> missed = new ArrayList<>();
- missed.addAll( positivePatterns );
- missed.addAll( simplePositivePatterns );
- missed.addAll( negativePatterns );
- missed.addAll( simpleNegativePatterns );
+ private final Pattern[] patterns;
- missed.removeAll( patternsTriggered );
+ public OrPattern( String pattern, Pattern[] patterns )
+ {
+ super( pattern );
+ this.patterns = patterns;
+ }
- if ( !missed.isEmpty() && logger.isWarnEnabled() )
+ @Override
+ public boolean matches( char[][] parts )
+ {
+ for ( Pattern pattern : patterns )
{
- final StringBuilder buffer = new StringBuilder();
-
- buffer.append( "The following patterns were never triggered in this " );
- buffer.append( getFilterDescription() );
- buffer.append( ':' );
-
- for ( String pattern : missed )
+ if ( pattern.matches( parts ) )
{
- buffer.append( "\no '" ).append( pattern ).append( "'" );
+ return true;
}
-
- buffer.append( "\n" );
-
- logger.warn( buffer.toString() );
}
+ return false;
}
}
- @Override
- public String toString()
+ static class PosPattern extends Pattern
{
- return "Includes filter:" + getPatternsAsString();
- }
+ private final char[] token;
+ private final int posMin;
+ private final int posMax;
- /**
- * @return pattern as a string.
- */
- protected String getPatternsAsString()
- {
- final StringBuilder buffer = new StringBuilder();
- for ( String pattern : simplePositivePatterns )
+ public PosPattern( String pattern, char[] token, int posMin, int posMax )
{
- buffer.append( "\no '" ).append( pattern ).append( "'" );
+ super( pattern );
+ this.token = token;
+ this.posMin = posMin;
+ this.posMax = posMax;
}
- for ( String pattern : positivePatterns )
+
+ @Override
+ public boolean matches( char[][] parts )
{
- buffer.append( "\no '" ).append( pattern ).append( "'" );
+ for ( int i = posMin; i <= posMax; i++ )
+ {
+ if ( match( token, parts[i], i == 3 ) )
+ {
+ return true;
+ }
+ }
+ return false;
}
-
- return buffer.toString();
}
- /**
- * @return description.
- */
- protected String getFilterDescription()
+ static class EqPattern extends Pattern
{
- return "artifact inclusion filter";
- }
+ private final char[] token;
+ private final int posMin;
+ private final int posMax;
- /** {@inheritDoc} */
- public void reportFilteredArtifacts( final Logger logger )
- {
- if ( !filteredArtifactIds.isEmpty() && logger.isDebugEnabled() )
+ public EqPattern( String pattern, char[] token, int posMin, int posMax )
{
- final StringBuilder buffer =
- new StringBuilder( "The following artifacts were removed by this " + getFilterDescription() + ": " );
+ super( pattern );
+ this.token = token;
+ this.posMin = posMin;
+ this.posMax = posMax;
+ }
- for ( String artifactId : filteredArtifactIds )
+ @Override
+ public boolean matches( char[][] parts )
+ {
+ for ( int i = posMin; i <= posMax; i++ )
{
- buffer.append( '\n' ).append( artifactId );
+ if (Arrays.equals( token, parts[i] ) )
+ {
+ return true;
+ }
}
+ return false;
+ }
- logger.debug( buffer.toString() );
+ public String translateEquals( int pos )
+ {
+ return posMin == pos && posMax == pos
+ && ( pos < 3 || ( token[0] != '[' && token[0] != '(' ) )
+ ? String.valueOf( token ) : null;
}
+
}
- /** {@inheritDoc} */
- public boolean hasMissedCriteria()
+ static class MatchAllPattern extends Pattern
{
- // if there are no patterns, there is nothing to report.
- if ( !positivePatterns.isEmpty() || !negativePatterns.isEmpty() )
+ public MatchAllPattern( String pattern )
+ {
+ super( pattern );
+ }
+
+ @Override
+ public boolean matches( char[][] parts )
{
- final List<String> missed = new ArrayList<>();
- missed.addAll( positivePatterns );
- missed.addAll( negativePatterns );
+ return true;
+ }
+ }
- missed.removeAll( patternsTriggered );
+ static class NegativePattern extends Pattern
+ {
+ private final Pattern inner;
- return !missed.isEmpty();
+ NegativePattern( String pattern, Pattern inner )
+ {
+ super( pattern );
+ this.inner = inner;
}
- return false;
+ @Override
+ public boolean matches( char[][] parts )
+ {
+ return inner.matches( parts );
+ }
}
}
diff --git a/src/test/java/org/apache/maven/shared/artifact/filter/AbstractPatternArtifactFilterTest.java b/src/test/java/org/apache/maven/shared/artifact/filter/AbstractPatternArtifactFilterTest.java
index bbd46f0..cb4ad8d 100644
--- a/src/test/java/org/apache/maven/shared/artifact/filter/AbstractPatternArtifactFilterTest.java
+++ b/src/test/java/org/apache/maven/shared/artifact/filter/AbstractPatternArtifactFilterTest.java
@@ -52,16 +52,16 @@ public abstract class AbstractPatternArtifactFilterTest
final String artifactId2 = "artifact2";
Artifact artifact1 = mock( Artifact.class );
- when( artifact1.getDependencyConflictId() ).thenReturn( groupId1 + ":" + artifactId1 + ":jar" );
when( artifact1.getGroupId() ).thenReturn( groupId1 );
when( artifact1.getArtifactId() ).thenReturn( artifactId1 );
- when( artifact1.getId() ).thenReturn( groupId1 + ":" + artifactId1 + ":jar:version" );
+ when( artifact1.getType() ).thenReturn( "jar" );
+ when( artifact1.getBaseVersion() ).thenReturn( "version" );
Artifact artifact2 = mock( Artifact.class );
- when( artifact2.getDependencyConflictId() ).thenReturn( groupId2 + ":" + artifactId2 + ":jar" );
when( artifact2.getGroupId() ).thenReturn( groupId2 );
when( artifact2.getArtifactId() ).thenReturn( artifactId2 );
- when( artifact2.getId() ).thenReturn( groupId2 + ":" + artifactId2 + ":jar:version" );
+ when( artifact2.getType() ).thenReturn( "jar" );
+ when( artifact2.getBaseVersion() ).thenReturn( "version" );
final List<String> patterns = new ArrayList<>();
patterns.add( groupId1 + ":" + artifactId1 + ":*" );
@@ -91,16 +91,16 @@ public abstract class AbstractPatternArtifactFilterTest
final String artifactId2 = "artifact2";
Artifact artifact1 = mock( Artifact.class );
- when( artifact1.getDependencyConflictId() ).thenReturn( groupId1 + ":" + artifactId1 + ":jar" );
when( artifact1.getGroupId() ).thenReturn( groupId1 );
when( artifact1.getArtifactId() ).thenReturn( artifactId1 );
- when( artifact1.getId() ).thenReturn( groupId1 + ":" + artifactId1 + ":jar:version" );
+ when( artifact1.getType() ).thenReturn( "jar" );
+ when( artifact1.getBaseVersion() ).thenReturn( "version" );
Artifact artifact2 = mock( Artifact.class );
- when( artifact2.getDependencyConflictId() ).thenReturn( groupId2 + ":" + artifactId2 + ":jar" );
when( artifact2.getGroupId() ).thenReturn( groupId2 );
when( artifact2.getArtifactId() ).thenReturn( artifactId2 );
- when( artifact2.getId() ).thenReturn( groupId2 + ":" + artifactId2 + ":jar:version" );
+ when( artifact2.getType() ).thenReturn( "jar" );
+ when( artifact2.getBaseVersion() ).thenReturn( "version" );
final List<String> patterns = new ArrayList<>();
patterns.add( groupId1 + "*" );
@@ -127,10 +127,10 @@ public abstract class AbstractPatternArtifactFilterTest
final String artifactId = "artifact";
Artifact artifact = mock( Artifact.class );
- when( artifact.getDependencyConflictId() ).thenReturn( groupId + ":" + artifactId + ":jar" );
when( artifact.getGroupId() ).thenReturn( groupId );
when( artifact.getArtifactId() ).thenReturn( artifactId );
- when( artifact.getId() ).thenReturn( groupId + ":" + artifactId + ":jar:version" );
+ when( artifact.getType() ).thenReturn( "jar" );
+ when( artifact.getBaseVersion() ).thenReturn( "version" );
final ArtifactFilter filter = createFilter( Collections.singletonList( groupId + ":" + artifactId ) );
@@ -151,10 +151,10 @@ public abstract class AbstractPatternArtifactFilterTest
final String artifactId = "artifact";
Artifact artifact = mock( Artifact.class );
- when( artifact.getDependencyConflictId() ).thenReturn( groupId + ":" + artifactId + ":jar" );
when( artifact.getGroupId() ).thenReturn( groupId );
when( artifact.getArtifactId() ).thenReturn( artifactId );
- when( artifact.getId() ).thenReturn( groupId + ":" + artifactId + ":jar:version" );
+ when( artifact.getType() ).thenReturn( "jar" );
+ when( artifact.getBaseVersion() ).thenReturn( "version" );
final ArtifactFilter filter = createFilter( Collections.singletonList( groupId + ":" + artifactId + ":jar" ) );
@@ -175,10 +175,10 @@ public abstract class AbstractPatternArtifactFilterTest
final String artifactId = "artifact";
Artifact artifact = mock( Artifact.class );
- when( artifact.getDependencyConflictId() ).thenReturn( groupId + ":" + artifactId + ":jar" );
when( artifact.getGroupId() ).thenReturn( groupId );
when( artifact.getArtifactId() ).thenReturn( artifactId );
- when( artifact.getId() ).thenReturn( groupId + ":" + artifactId + ":jar:version" );
+ when( artifact.getType() ).thenReturn( "jar" );
+ when( artifact.getBaseVersion() ).thenReturn( "version" );
final List<String> patterns = new ArrayList<>();
patterns.add( "otherGroup:" + artifactId + ":jar" );
@@ -203,10 +203,10 @@ public abstract class AbstractPatternArtifactFilterTest
final String artifactId = "artifact";
Artifact artifact = mock( Artifact.class );
- when( artifact.getDependencyConflictId() ).thenReturn( groupId + ":" + artifactId + ":jar" );
when( artifact.getGroupId() ).thenReturn( groupId );
when( artifact.getArtifactId() ).thenReturn( artifactId );
- when( artifact.getId() ).thenReturn( groupId + ":" + artifactId + ":jar:version" );
+ when( artifact.getType() ).thenReturn( "jar" );
+ when( artifact.getBaseVersion() ).thenReturn( "version" );
final List<String> patterns = new ArrayList<>();
patterns.add( groupId + "otherArtifact:jar" );
@@ -231,10 +231,10 @@ public abstract class AbstractPatternArtifactFilterTest
final String artifactId = "artifact";
Artifact artifact = mock( Artifact.class );
- when( artifact.getDependencyConflictId() ).thenReturn( groupId + ":" + artifactId + ":jar" );
when( artifact.getGroupId() ).thenReturn( groupId );
when( artifact.getArtifactId() ).thenReturn( artifactId );
- when( artifact.getId() ).thenReturn( groupId + ":" + artifactId + ":jar:version" );
+ when( artifact.getType() ).thenReturn( "jar" );
+ when( artifact.getBaseVersion() ).thenReturn( "version" );
final List<String> patterns = new ArrayList<>();
patterns.add( "otherGroup:otherArtifact:jar" );
@@ -265,10 +265,10 @@ public abstract class AbstractPatternArtifactFilterTest
final List<String> patterns = Collections.singletonList( depTrailItem );
Artifact artifact = mock( Artifact.class );
- when( artifact.getDependencyConflictId() ).thenReturn( groupId + ":" + artifactId + ":jar" );
when( artifact.getGroupId() ).thenReturn( groupId );
when( artifact.getArtifactId() ).thenReturn( artifactId );
- when( artifact.getId() ).thenReturn( groupId + ":" + artifactId + ":jar:version" );
+ when( artifact.getType() ).thenReturn( "jar" );
+ when( artifact.getBaseVersion() ).thenReturn( "version" );
when( artifact.getDependencyTrail() ).thenReturn( depTrail );
final ArtifactFilter filter = createFilter( patterns, true );
@@ -296,10 +296,10 @@ public abstract class AbstractPatternArtifactFilterTest
final List<String> patterns = Collections.singletonList( "otherGroup*" );
Artifact artifact = mock( Artifact.class );
- when( artifact.getDependencyConflictId() ).thenReturn( groupId + ":" + artifactId + ":jar" );
when( artifact.getGroupId() ).thenReturn( groupId );
when( artifact.getArtifactId() ).thenReturn( artifactId );
- when( artifact.getId() ).thenReturn( groupId + ":" + artifactId + ":jar:version" );
+ when( artifact.getType() ).thenReturn( "jar" );
+ when( artifact.getBaseVersion() ).thenReturn( "version" );
when( artifact.getDependencyTrail() ).thenReturn( depTrail );
final ArtifactFilter filter = createFilter( patterns, true );
@@ -321,10 +321,10 @@ public abstract class AbstractPatternArtifactFilterTest
final String artifactId = "artifact";
Artifact artifact = mock( Artifact.class );
- when( artifact.getDependencyConflictId() ).thenReturn( groupId + ":" + artifactId + ":jar" );
when( artifact.getGroupId() ).thenReturn( groupId );
when( artifact.getArtifactId() ).thenReturn( artifactId );
- when( artifact.getId() ).thenReturn( groupId + ":" + artifactId + ":jar:version" );
+ when( artifact.getType() ).thenReturn( "jar" );
+ when( artifact.getBaseVersion() ).thenReturn( "version" );
final List<String> patterns = new ArrayList<>();
patterns.add( "!group:artifact:jar" );
@@ -348,10 +348,10 @@ public abstract class AbstractPatternArtifactFilterTest
final String artifactId = "artifact";
Artifact artifact = mock( Artifact.class );
- when( artifact.getDependencyConflictId() ).thenReturn( groupId + ":" + artifactId + ":jar" );
when( artifact.getGroupId() ).thenReturn( groupId );
when( artifact.getArtifactId() ).thenReturn( artifactId );
- when( artifact.getId() ).thenReturn( groupId + ":" + artifactId + ":jar:version" );
+ when( artifact.getType() ).thenReturn( "jar" );
+ when( artifact.getBaseVersion() ).thenReturn( "version" );
final List<String> patterns = new ArrayList<>();
patterns.add( "group:*:jar" );
@@ -376,10 +376,10 @@ public abstract class AbstractPatternArtifactFilterTest
Artifact artifact = mock( Artifact.class );
- when( artifact.getDependencyConflictId() ).thenReturn( groupId + ":" + artifactId + ":jar" );
when( artifact.getGroupId() ).thenReturn( groupId );
when( artifact.getArtifactId() ).thenReturn( artifactId );
- when( artifact.getId() ).thenReturn( groupId + ":" + artifactId + ":jar:version" );
+ when( artifact.getType() ).thenReturn( "jar" );
+ when( artifact.getBaseVersion() ).thenReturn( "version" );
final List<String> patterns = new ArrayList<>();
patterns.add( "*:artifact:*" );
@@ -404,10 +404,10 @@ public abstract class AbstractPatternArtifactFilterTest
Artifact artifact = mock( Artifact.class );
- when( artifact.getDependencyConflictId() ).thenReturn( groupId + ":" + artifactId + ":jar" );
when( artifact.getGroupId() ).thenReturn( groupId );
when( artifact.getArtifactId() ).thenReturn( artifactId );
- when( artifact.getId() ).thenReturn( groupId + ":" + artifactId + ":jar:version" );
+ when( artifact.getType() ).thenReturn( "jar" );
+ when( artifact.getBaseVersion() ).thenReturn( "version" );
final List<String> patterns = new ArrayList<>();
patterns.add( "group:some-*-id" );
@@ -432,10 +432,10 @@ public abstract class AbstractPatternArtifactFilterTest
Artifact artifact = mock( Artifact.class );
- when( artifact.getDependencyConflictId() ).thenReturn( groupId + ":" + artifactId + ":jar" );
when( artifact.getGroupId() ).thenReturn( groupId );
when( artifact.getArtifactId() ).thenReturn( artifactId );
- when( artifact.getId() ).thenReturn( groupId + ":" + artifactId + ":jar:version" );
+ when( artifact.getType() ).thenReturn( "jar" );
+ when( artifact.getBaseVersion() ).thenReturn( "version" );
final List<String> patterns = new ArrayList<>();
patterns.add( "some.group*" );
@@ -465,16 +465,16 @@ public abstract class AbstractPatternArtifactFilterTest
final List<String> patterns = Collections.singletonList( "*:jar:*" );
Artifact artifact1 = mock( Artifact.class );
- when( artifact1.getDependencyConflictId() ).thenReturn( groupId + ":" + artifactId + ":jar" );
when( artifact1.getGroupId() ).thenReturn( groupId );
when( artifact1.getArtifactId() ).thenReturn( artifactId );
- when( artifact1.getId() ).thenReturn( groupId + ":" + artifactId + ":jar:version" );
-
+ when( artifact1.getType() ).thenReturn( "jar" );
+ when( artifact1.getBaseVersion() ).thenReturn( "version" );
+
Artifact artifact2 = mock( Artifact.class );
- when( artifact2.getDependencyConflictId() ).thenReturn( otherGroup + ":" + otherArtifact + ":" + otherType );
when( artifact2.getGroupId() ).thenReturn( otherGroup );
when( artifact2.getArtifactId() ).thenReturn( otherArtifact );
- when( artifact2.getId() ).thenReturn( otherGroup + ":" + otherArtifact + ":" + otherType + ":version" );
+ when( artifact2.getType() ).thenReturn( otherType );
+ when( artifact2.getBaseVersion() ).thenReturn( "version" );
when( artifact2.getDependencyTrail() ).thenReturn( Collections.<String> emptyList() );
final ArtifactFilter filter = createFilter( patterns, true );
@@ -498,10 +498,10 @@ public abstract class AbstractPatternArtifactFilterTest
final String artifactId = "some-artifact-id";
Artifact artifact = mock( Artifact.class );
- when( artifact.getDependencyConflictId() ).thenReturn( groupId + ":" + artifactId + ":jar" );
when( artifact.getGroupId() ).thenReturn( groupId );
when( artifact.getArtifactId() ).thenReturn( artifactId );
- when( artifact.getId() ).thenReturn( groupId + ":" + artifactId + ":jar:version" );
+ when( artifact.getType() ).thenReturn( "jar" );
+ when( artifact.getBaseVersion() ).thenReturn( "version" );
final List<String> patterns = new ArrayList<>();
patterns.add( "com.mycompany.*:*:jar:*:*" );
@@ -517,4 +517,31 @@ public abstract class AbstractPatternArtifactFilterTest
assertTrue( filter.include( artifact ) );
}
}
+
+ @Test
+ public void testWithVersionRange()
+ {
+ final String groupId = "com.mycompany.myproject";
+ final String artifactId = "some-artifact-id";
+
+ Artifact artifact = mock( Artifact.class );
+ when( artifact.getGroupId() ).thenReturn( groupId );
+ when( artifact.getArtifactId() ).thenReturn( artifactId );
+ when( artifact.getType() ).thenReturn( "jar" );
+ when( artifact.getBaseVersion() ).thenReturn( "1.1" );
+
+ final List<String> patterns = new ArrayList<>();
+ patterns.add( "com.mycompany.myproject:some-artifact-id:jar:*:[1.0,2.0)" );
+
+ final ArtifactFilter filter = createFilter( patterns );
+
+ if ( isInclusionNotExpected() )
+ {
+ assertFalse( filter.include( artifact ) );
+ }
+ else
+ {
+ assertTrue( filter.include( artifact ) );
+ }
+ }
}
diff --git a/src/main/java/org/apache/maven/shared/artifact/filter/PatternIncludesArtifactFilter.java b/src/test/java/org/apache/maven/shared/artifact/filter/OldPatternIncludesArtifactFilter.java
similarity index 78%
copy from src/main/java/org/apache/maven/shared/artifact/filter/PatternIncludesArtifactFilter.java
copy to src/test/java/org/apache/maven/shared/artifact/filter/OldPatternIncludesArtifactFilter.java
index 8d01c71..df492bb 100644
--- a/src/main/java/org/apache/maven/shared/artifact/filter/PatternIncludesArtifactFilter.java
+++ b/src/test/java/org/apache/maven/shared/artifact/filter/OldPatternIncludesArtifactFilter.java
@@ -22,7 +22,6 @@ package org.apache.maven.shared.artifact.filter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
-import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
@@ -36,20 +35,16 @@ import org.codehaus.plexus.logging.Logger;
/**
* TODO: include in maven-artifact in future
- *
+ *
* @author <a href="mailto:brett@apache.org">Brett Porter</a>
* @see StrictPatternIncludesArtifactFilter
*/
-public class PatternIncludesArtifactFilter
- implements ArtifactFilter, StatisticsReportingArtifactFilter
+public class OldPatternIncludesArtifactFilter
+ implements ArtifactFilter, StatisticsReportingArtifactFilter
{
- private final Set<String> simplePositivePatterns;
-
- private final Set<String> positivePatterns;
-
- private final Set<String> simpleNegativePatterns;
+ private final List<String> positivePatterns;
- private final Set<String> negativePatterns;
+ private final List<String> negativePatterns;
private final boolean actTransitively;
@@ -60,7 +55,7 @@ public class PatternIncludesArtifactFilter
/**
* @param patterns The pattern to be used.
*/
- public PatternIncludesArtifactFilter( final Collection<String> patterns )
+ public OldPatternIncludesArtifactFilter( final Collection<String> patterns )
{
this( patterns, false );
}
@@ -69,46 +64,28 @@ public class PatternIncludesArtifactFilter
* @param patterns The pattern to be used.
* @param actTransitively transitive yes/no.
*/
- public PatternIncludesArtifactFilter( final Collection<String> patterns, final boolean actTransitively )
+ public OldPatternIncludesArtifactFilter( final Collection<String> patterns, final boolean actTransitively )
{
this.actTransitively = actTransitively;
- final Set<String> pos = new LinkedHashSet<>();
- final Set<String> spos = new LinkedHashSet<>();
- final Set<String> neg = new LinkedHashSet<>();
- final Set<String> sneg = new LinkedHashSet<>();
+ final List<String> pos = new ArrayList<>();
+ final List<String> neg = new ArrayList<>();
if ( patterns != null && !patterns.isEmpty() )
{
for ( String pattern : patterns )
{
if ( pattern.startsWith( "!" ) )
{
- if ( pattern.contains( "*" ) )
- {
- neg.add( pattern.substring( 1 ) );
- }
- else
- {
- sneg.add( pattern.substring( 1 ) );
- }
+ neg.add( pattern.substring( 1 ) );
}
else
{
- if ( pattern.contains( "*" ) )
- {
- pos.add( pattern );
- }
- else
- {
- spos.add( pattern );
- }
+ pos.add( pattern );
}
}
}
positivePatterns = pos;
- simplePositivePatterns = spos;
negativePatterns = neg;
- simpleNegativePatterns = sneg;
}
/** {@inheritDoc} */
@@ -143,13 +120,6 @@ public class PatternIncludesArtifactFilter
private Boolean negativeMatch( final Artifact artifact )
{
- if ( simpleNegativePatterns != null && !simpleNegativePatterns.isEmpty() )
- {
- if ( simpleMatch( artifact, simpleNegativePatterns ) )
- {
- return true;
- }
- }
if ( negativePatterns == null || negativePatterns.isEmpty() )
{
return null;
@@ -166,13 +136,6 @@ public class PatternIncludesArtifactFilter
*/
protected Boolean positiveMatch( final Artifact artifact )
{
- if ( simplePositivePatterns != null && !simplePositivePatterns.isEmpty() )
- {
- if ( simpleMatch( artifact, simplePositivePatterns ) )
- {
- return true;
- }
- }
if ( positivePatterns == null || positivePatterns.isEmpty() )
{
return null;
@@ -183,33 +146,7 @@ public class PatternIncludesArtifactFilter
}
}
- private boolean simpleMatch( final Artifact artifact, final Set<String> patterns )
- {
- final String shortId = ArtifactUtils.versionlessKey( artifact );
- if ( patterns.contains( shortId ) )
- {
- patternsTriggered.add( shortId );
- return true;
- }
-
- final String id = artifact.getDependencyConflictId();
- if ( patterns.contains( id ) )
- {
- patternsTriggered.add( id );
- return true;
- }
-
- final String wholeId = artifact.getId();
- if ( patterns.contains( wholeId ) )
- {
- patternsTriggered.add( wholeId );
- return true;
- }
-
- return false;
- }
-
- private boolean match( final Artifact artifact, final Iterable<String> patterns )
+ private boolean match( final Artifact artifact, final List<String> patterns )
{
final String shortId = ArtifactUtils.versionlessKey( artifact );
final String id = artifact.getDependencyConflictId();
@@ -249,13 +186,13 @@ public class PatternIncludesArtifactFilter
return false;
}
- private boolean matchAgainst( final String value, final Iterable<String> patterns, final boolean regionMatch )
+ private boolean matchAgainst( final String value, final List<String> patterns, final boolean regionMatch )
{
final String[] tokens = value.split( ":" );
for ( String pattern : patterns )
{
String[] patternTokens = pattern.split( ":" );
-
+
if ( patternTokens.length == 5 && tokens.length < 5 )
{
// 4th element is the classifier
@@ -311,7 +248,7 @@ public class PatternIncludesArtifactFilter
/**
* Gets whether the specified token matches the specified pattern segment.
- *
+ *
* @param token the token to check
* @param pattern the pattern segment to match, as defined above
* @return <code>true</code> if the specified token is matched by the specified pattern segment
@@ -397,14 +334,11 @@ public class PatternIncludesArtifactFilter
public void reportMissedCriteria( final Logger logger )
{
// if there are no patterns, there is nothing to report.
- if ( !positivePatterns.isEmpty() || !negativePatterns.isEmpty()
- || !simplePositivePatterns.isEmpty() || !simpleNegativePatterns.isEmpty() )
+ if ( !positivePatterns.isEmpty() || !negativePatterns.isEmpty() )
{
final List<String> missed = new ArrayList<>();
missed.addAll( positivePatterns );
- missed.addAll( simplePositivePatterns );
missed.addAll( negativePatterns );
- missed.addAll( simpleNegativePatterns );
missed.removeAll( patternsTriggered );
@@ -440,10 +374,6 @@ public class PatternIncludesArtifactFilter
protected String getPatternsAsString()
{
final StringBuilder buffer = new StringBuilder();
- for ( String pattern : simplePositivePatterns )
- {
- buffer.append( "\no '" ).append( pattern ).append( "'" );
- }
for ( String pattern : positivePatterns )
{
buffer.append( "\no '" ).append( pattern ).append( "'" );
@@ -466,7 +396,7 @@ public class PatternIncludesArtifactFilter
if ( !filteredArtifactIds.isEmpty() && logger.isDebugEnabled() )
{
final StringBuilder buffer =
- new StringBuilder( "The following artifacts were removed by this " + getFilterDescription() + ": " );
+ new StringBuilder( "The following artifacts were removed by this " + getFilterDescription() + ": " );
for ( String artifactId : filteredArtifactIds )
{
@@ -495,4 +425,4 @@ public class PatternIncludesArtifactFilter
return false;
}
-}
+}
\ No newline at end of file
diff --git a/src/test/java/org/apache/maven/shared/artifact/filter/PatternFilterPerfTest.java b/src/test/java/org/apache/maven/shared/artifact/filter/PatternFilterPerfTest.java
new file mode 100644
index 0000000..159d979
--- /dev/null
+++ b/src/test/java/org/apache/maven/shared/artifact/filter/PatternFilterPerfTest.java
@@ -0,0 +1,122 @@
+package org.apache.maven.shared.artifact.filter;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.DefaultArtifact;
+import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
+import org.codehaus.plexus.util.xml.Xpp3Dom;
+import org.codehaus.plexus.util.xml.Xpp3DomBuilder;
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+import org.junit.Test;
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.Level;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.OutputTimeUnit;
+import org.openjdk.jmh.annotations.Param;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.Warmup;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+import org.openjdk.jmh.runner.options.TimeValue;
+
+@BenchmarkMode(Mode.Throughput)
+@OutputTimeUnit(TimeUnit.MILLISECONDS)
+@Warmup(iterations = 3, time = 3, timeUnit = TimeUnit.SECONDS)
+public class PatternFilterPerfTest {
+
+ @State(Scope.Benchmark)
+ static public class OldPatternState {
+
+ @Param({
+ "groupId:artifact-00,groupId:artifact-01,groupId:artifact-02,groupId:artifact-03,groupId:artifact-04,groupId:artifact-05,groupId:artifact-06,groupId:artifact-07,groupId:artifact-08,groupId:artifact-09",
+ "groupId:artifact-99",
+ "groupId:artifact-*",
+ "*:artifact-99",
+ "*:artifact-*",
+ "*:artifact-*:*",
+ "*:artifact-99:*",
+ })
+ public String patterns;
+
+ ArtifactFilter filter;
+ Artifact artifact;
+
+ @Setup(Level.Invocation)
+ public void setup()
+ {
+ filter = new OldPatternIncludesArtifactFilter( Arrays.asList( patterns.split( "," ) ) );
+ artifact = new DefaultArtifact(
+ "groupId", "artifact-99", "1.0", "runtime",
+ "jar", "", null
+ );
+ }
+
+ }
+
+ @State(Scope.Benchmark)
+ static public class NewPatternState {
+
+ @Param({
+ "groupId:artifact-00,groupId:artifact-01,groupId:artifact-02,groupId:artifact-03,groupId:artifact-04,groupId:artifact-05,groupId:artifact-06,groupId:artifact-07,groupId:artifact-08,groupId:artifact-09",
+ "groupId:artifact-99",
+ "groupId:artifact-*",
+ "*:artifact-99",
+ "*:artifact-*",
+ "*:artifact-*:*",
+ "*:artifact-99:*",
+ })
+ public String patterns;
+
+ ArtifactFilter filter;
+ Artifact artifact;
+
+ @Setup(Level.Invocation)
+ public void setup()
+ {
+ filter = new PatternIncludesArtifactFilter( Arrays.asList( patterns.split( "," ) ) );
+ artifact = new DefaultArtifact(
+ "groupId", "artifact-99", "1.0", "runtime",
+ "jar", "", null
+ );
+ }
+
+ }
+
+
+ @Benchmark
+ public boolean newPatternTest(NewPatternState state )
+ {
+ return state.filter.include( state.artifact );
+ }
+
+ @Benchmark
+ public boolean oldPatternTest(OldPatternState state )
+ {
+ return state.filter.include( state.artifact );
+ }
+
+ public static void main( String... args )
+ throws RunnerException
+ {
+ Options opts = new OptionsBuilder()
+ .measurementIterations( 3 )
+ .measurementTime( TimeValue.milliseconds( 3000 ) )
+ .forks( 1 )
+ .include( "org.apache.maven.shared.artifact.filter.PatternFilterPerfTest" )
+ .build();
+ new Runner( opts ).run();
+ }
+}