This is an automated email from the ASF dual-hosted git repository.

slachiewicz pushed a commit to branch MSHARED-975-speed
in repository 
https://gitbox.apache.org/repos/asf/maven-common-artifact-filters.git

commit 3272baaaed449f6cda94f8a9ee52291c289549c6
Author: Guillaume Nodet <gno...@gmail.com>
AuthorDate: Wed Nov 18 20:52:42 2020 +0100

    [MSHARED-975] Big speed improvements for patterns that do not contain any 
wildcard
    
    This can be a huge boost for dependency sets that contains lots of artifact 
ids like in Apache Camel project
    
    Closes #15
---
 pom.xml                                            |  12 +
 .../filter/PatternExcludesArtifactFilter.java      |   2 +-
 .../filter/PatternIncludesArtifactFilter.java      | 947 ++++++++++++++++-----
 .../filter/AbstractPatternArtifactFilterTest.java  | 105 ++-
 .../filter/OldPatternIncludesArtifactFilter.java}  |  18 +-
 .../artifact/filter/PatternFilterPerfTest.java     | 131 +++
 6 files changed, 967 insertions(+), 248 deletions(-)

diff --git a/pom.xml b/pom.xml
index 6a40045..4350b2a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -157,5 +157,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..a55cb2a 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() );
+            addFilteredArtifact( 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 c9aad45..6cfb68f 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,13 +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;
@@ -42,15 +47,20 @@ import org.codehaus.plexus.logging.Logger;
 public class PatternIncludesArtifactFilter
     implements ArtifactFilter, StatisticsReportingArtifactFilter
 {
-    private final List<String> positivePatterns;
+    /** Holds the set of compiled patterns */
+    private final Set<Pattern> patterns;
 
-    private final List<String> negativePatterns;
+    /** Holds simple patterns: those that can use direct matching */
+    private final Map<Integer, Map<String, Pattern>> simplePatterns;
 
+    /** Whether 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.
@@ -67,25 +77,55 @@ public class PatternIncludesArtifactFilter
     public PatternIncludesArtifactFilter( final Collection<String> patterns, 
final boolean actTransitively )
     {
         this.actTransitively = actTransitively;
-        final List<String> pos = new ArrayList<>();
-        final List<String> neg = new ArrayList<>();
+        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( "!" ) )
-                {
-                    neg.add( pattern.substring( 1 ) );
-                }
-                else
+
+                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 )
                 {
-                    pos.add( pattern );
+                    int nb = 0;
+                    for ( char ch : peq.toCharArray() )
+                    {
+                        if ( ch == ':' )
+                        {
+                            nb++;
+                        }
+                    }
+                    if ( simplePat == null )
+                    {
+                        simplePat = new HashMap<>();
+                    }
+                    Map<String, Pattern> peqm = simplePat.get( nb );
+                    if ( peqm == null )
+                    {
+                        peqm = new HashMap<>();
+                        simplePat.put( nb, peqm );
+                    }
+                    peqm.put( peq, p );
+                    it.remove();
                 }
             }
         }
-
-        positivePatterns = pos;
-        negativePatterns = neg;
+        this.simplePatterns = simplePat;
+        this.patterns = pat;
     }
 
     /** {@inheritDoc} */
@@ -95,7 +135,7 @@ public class PatternIncludesArtifactFilter
 
         if ( !shouldInclude )
         {
-            addFilteredArtifactId( artifact.getId() );
+            addFilteredArtifact( artifact );
         }
 
         return shouldInclude;
@@ -107,322 +147,831 @@ 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[][] artifactGatvCharArray = new char[][] {
+                            emptyOrChars( artifact.getGroupId() ),
+                            emptyOrChars( artifact.getArtifactId() ),
+                            emptyOrChars( artifact.getType() ),
+                            emptyOrChars( artifact.getBaseVersion() )
+                    };
+        Boolean match = match( artifactGatvCharArray );
+        if ( match != null )
+        {
+            return match;
+        }
+
+        if ( actTransitively )
+        {
+            final List<String> depTrail = artifact.getDependencyTrail();
+
+            if ( depTrail != null && depTrail.size() > 1 )
+            {
+                for ( String trailItem : depTrail )
+                {
+                    char[][] depGatvCharArray = tokenizeAndSplit( trailItem );
+                    match = match( depGatvCharArray );
+                    if ( match != null )
+                    {
+                        return match;
+                    }
+                }
+            }
+        }
+
+        return false;
+    }
+
+    private Boolean match( char[][] gatvCharArray )
+    {
+        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( gatvCharArray[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( gatvCharArray ) )
+            {
+                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 addFilteredArtifact( final Artifact artifact )
     {
-        filteredArtifactIds.add( artifactId );
+        filteredArtifact.add( artifact );
     }
 
-    private Boolean negativeMatch( final Artifact artifact )
+    /** {@inheritDoc} */
+    public void reportMissedCriteria( final Logger logger )
     {
-        if ( negativePatterns == null || negativePatterns.isEmpty() )
+        // 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 );
+
+            if ( !missed.isEmpty() && logger.isWarnEnabled() )
+            {
+                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() );
+            }
         }
-        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()
+    {
+        return "artifact inclusion filter";
+    }
+
+    /** {@inheritDoc} */
+    public void reportFilteredArtifacts( final Logger logger )
     {
-        if ( positivePatterns == null || positivePatterns.isEmpty() )
+        if ( !filteredArtifact.isEmpty() && logger.isDebugEnabled() )
         {
-            return null;
+            final StringBuilder buffer =
+                new StringBuilder( "The following artifacts were removed by 
this " + getFilterDescription() + ": " );
+
+            for ( Artifact artifactId : filteredArtifact )
+            {
+                buffer.append( '\n' ).append( artifactId.getId() );
+            }
+
+            logger.debug( buffer.toString() );
         }
-        else
+    }
+
+    /** {@inheritDoc} */
+    public boolean hasMissedCriteria()
+    {
+        // if there are no patterns, there is nothing to report.
+        if ( !patterns.isEmpty() )
         {
-            return match( artifact, positivePatterns );
+            final List<Pattern> missed = new ArrayList<>( patterns );
+            missed.removeAll( patternsTriggered );
+
+            return !missed.isEmpty();
         }
+
+        return false;
     }
 
-    private boolean match( final Artifact artifact, final List<String> 
patterns )
+    private static final char[] EMPTY = new char[0];
+
+    private static final char[] ANY = new char[] { '*' };
+
+    static char[] emptyOrChars( String str )
     {
-        final String shortId = ArtifactUtils.versionlessKey( artifact );
-        final String id = artifact.getDependencyConflictId();
-        final String wholeId = artifact.getId();
+        return str != null && str.length() > 0 ? str.toCharArray() : EMPTY;
+    }
 
-        if ( matchAgainst( wholeId, patterns, false ) )
-        {
-            return true;
-        }
+    static char[] anyOrChars( char[] str )
+    {
+        return str.length > 1 || ( str.length == 1 && str[0] != '*' ) ? str : 
ANY;
+    }
 
-        if ( matchAgainst( id, patterns, false ) )
+    static char[][] tokenizeAndSplit( String pattern )
+    {
+        String[] stokens = pattern.split( ":" );
+        char[][] tokens = new char[ stokens.length ][];
+        for ( int i = 0; i < stokens.length; i++ )
         {
-            return true;
+            tokens[i] = emptyOrChars( stokens[i] );
         }
+        return tokens;
+    }
 
-        if ( matchAgainst( shortId, patterns, false ) )
+    @SuppressWarnings( "InnerAssignment" )
+    static boolean match( char[] patArr, char[] strArr, boolean isVersion )
+    {
+        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 )
         {
-            return true;
+            if ( aPatArr == '*' )
+            {
+                containsStar = true;
+                break;
+            }
         }
 
-        if ( actTransitively )
+        if ( !containsStar )
         {
-            final List<String> depTrail = artifact.getDependencyTrail();
-
-            if ( depTrail != null && depTrail.size() > 1 )
+            if ( isVersion && ( patArr[0] == '[' || patArr[0] == '(' ) )
             {
-                for ( String trailItem : depTrail )
+                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] )
                 {
-                    if ( matchAgainst( trailItem, patterns, true ) )
-                    {
-                        return true;
-                    }
+                    return false; // Character mismatch
                 }
             }
+            return true; // String matches against pattern
         }
 
-        return false;
-    }
+        if ( patIdxEnd == 0 )
+        {
+            return true; // Pattern contains only '*', which matches anything
+        }
 
-    private boolean matchAgainst( final String value, final List<String> 
patterns, final boolean regionMatch )
-    {
-        final String[] tokens = value.split( ":" );
-        for ( String pattern : patterns )
+        // Process characters before first star
+        while ( ( ch = patArr[patIdxStart] ) != '*' && strIdxStart <= 
strIdxEnd )
         {
-            String[] patternTokens = pattern.split( ":" );
-            
-            if ( patternTokens.length == 5 && tokens.length < 5 )
+            if ( ch != '?' && ch != strArr[strIdxStart] )
             {
-                // 4th element is the classifier
-                if ( !"*".equals( patternTokens[3] ) )
+                return false; // Character mismatch
+            }
+            patIdxStart++;
+            strIdxStart++;
+        }
+        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] != '*' )
                 {
-                    // classifier required, cannot be a match
                     return false;
                 }
-                patternTokens = new String[] { patternTokens[0], 
patternTokens[1], patternTokens[2], patternTokens[4] };
             }
+            return true;
+        }
 
-            // fail immediately if pattern tokens outnumber tokens to match
-            boolean matched = patternTokens.length <= tokens.length;
-
-            for ( int i = 0; matched && i < patternTokens.length; i++ )
+        // Process characters after last star
+        while ( ( ch = patArr[patIdxEnd] ) != '*' && strIdxStart <= strIdxEnd )
+        {
+            if ( ch != '?' && ch != strArr[strIdxEnd] )
             {
-                matched = matches( tokens[i], patternTokens[i] );
+                return false; // Character mismatch
             }
-
-            // case of starting '*' like '*:jar:*'
-            // This really only matches from the end instead.....
-            if ( !matched && patternTokens.length < tokens.length && 
isFirstPatternWildcard( patternTokens ) )
+            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++ )
             {
-                matched = true;
-                int tokenOffset = tokens.length - patternTokens.length;
-                for ( int i = 0; matched && i < patternTokens.length; i++ )
+                if ( patArr[i] != '*' )
                 {
-                    matched = matches( tokens[i + tokenOffset], 
patternTokens[i] );
+                    return false;
                 }
             }
+            return true;
+        }
 
-            if ( matched )
+        // process pattern between stars. padIdxStart and patIdxEnd point
+        // always to a '*'.
+        while ( patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd )
+        {
+            int patIdxTmp = -1;
+            for ( int i = patIdxStart + 1; i <= patIdxEnd; i++ )
             {
-                patternsTriggered.add( pattern );
-                return true;
+                if ( patArr[i] == '*' )
+                {
+                    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] )
+                    {
+                        continue strLoop;
+                    }
+                }
+
+                foundIdx = strIdxStart + i;
+                break;
             }
 
-            if ( regionMatch && value.contains( pattern ) )
+            if ( foundIdx == -1 )
             {
-                patternsTriggered.add( pattern );
-                return true;
+                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;
     }
 
-    private boolean isFirstPatternWildcard( String[] patternTokens )
+    static boolean isVersionIncludedInRange( final String version, final 
String range )
     {
-        return patternTokens.length > 0 && "*".equals( patternTokens[0] );
-    }
-
-    /**
-     * 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 )
-    {
-        boolean matches;
-
-        // support full wildcard and implied wildcard
-        if ( "*".equals( pattern ) || pattern.length() == 0 )
+        try
         {
-            matches = true;
+            return VersionRange.createFromVersionSpec( range 
).containsVersion( new DefaultArtifactVersion( version ) );
         }
-        // support contains wildcard
-        else if ( pattern.startsWith( "*" ) && pattern.endsWith( "*" ) )
+        catch ( final InvalidVersionSpecificationException e )
         {
-            final String contains = pattern.substring( 1, pattern.length() - 1 
);
-
-            matches = token.contains( contains );
+            return false;
         }
-        // support leading wildcard
-        else if ( pattern.startsWith( "*" ) )
-        {
-            final String suffix = pattern.substring( 1 );
+    }
 
-            matches = token.endsWith( suffix );
-        }
-        // support trailing wildcard
-        else if ( pattern.endsWith( "*" ) )
+    static Pattern compile( String pattern )
+    {
+        if ( pattern.startsWith( "!" ) )
         {
-            final String prefix = pattern.substring( 0, pattern.length() - 1 );
-
-            matches = token.startsWith( prefix );
+            return new NegativePattern( pattern, compile( pattern.substring( 1 
) ) );
         }
-        // support wildcards in the middle of a pattern segment
-        else if ( pattern.indexOf( '*' ) > -1 )
+        else
         {
-            String[] parts = pattern.split( "\\*" );
-            int lastPartEnd = -1;
-            boolean match = true;
-
-            for ( String part : parts )
+            char[][] stokens = tokenizeAndSplit( pattern );
+            char[][] tokens = new char[ stokens.length ][];
+            for ( int i = 0; i < stokens.length; i++ )
+            {
+                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 )
             {
-                int idx = token.indexOf( part );
-                if ( idx <= lastPartEnd )
+                if ( tokens[3] != ANY )
                 {
-                    match = false;
-                    break;
+                    throw new IllegalArgumentException( "Invalid pattern: " + 
pattern );
+                }
+                tokens = new char[][] { tokens[0], tokens[1], tokens[2], 
tokens[4] };
+            }
+            //
+            // 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 )
+            {
+                if ( tokens[0] == ANY )
+                {
+                    // *
+                    return all( pattern );
+                }
+                else
+                {
+                    // [pat0]
+                    return match( pattern, tokens[0], 0 );
                 }
-
-                lastPartEnd = idx + part.length();
             }
+            if ( tokens.length == 2 )
+            {
+                if ( tokens[0] == ANY )
+                {
+                    if ( tokens[1] == ANY )
+                    {
+                        // *:*
+                        return all( pattern );
+                    }
+                    else
+                    {
+                        // *:[pat1]
+                        return match( pattern, tokens[1], 0, 3 );
+                    }
+                }
+                else
+                {
+                    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 ( tokens.length == 3 )
+            {
+                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 ( tokens.length == 4 )
+            {
+                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();
+        }
+    }
 
-            matches = match;
+    /** Creates a positional matching pattern */
+    private static Pattern match( String pattern, char[] token, int posVal )
+    {
+        return match( pattern, token, posVal, posVal );
+    }
+
+    /** Creates a positional matching pattern */
+    private static Pattern match( char[] token, int posVal )
+    {
+        return match( "", token, posVal, posVal );
+    }
+
+    /** Creates a positional matching pattern */
+    private static Pattern match( String pattern, char[] token, int posMin, 
int posMax )
+    {
+        boolean hasWildcard = false;
+        for ( char ch : token )
+        {
+            if ( ch == '*' || ch == '?' )
+            {
+                hasWildcard = true;
+                break;
+            }
         }
-        // support versions range
-        else if ( pattern.startsWith( "[" ) || pattern.startsWith( "(" ) )
+        if ( hasWildcard || posMax == 3 )
         {
-            matches = isVersionIncludedInRange( token, pattern );
+            return new PosPattern( pattern, token, posMin, posMax );
         }
-        // support exact match
         else
         {
-            matches = token.equals( pattern );
+            return new EqPattern( pattern, token, posMin, posMax );
         }
+    }
 
-        return matches;
+    /** Creates a positional matching pattern */
+    private static Pattern match( char[] token, int posMin, int posMax )
+    {
+        return new PosPattern( "", token, posMin, posMax );
     }
 
-    private boolean isVersionIncludedInRange( final String version, final 
String range )
+    /** Creates an AND pattern */
+    private static Pattern and( String pattern, Pattern... patterns )
     {
-        try
+        return new AndPattern( pattern, patterns );
+    }
+
+    /** Creates an AND pattern */
+    private static Pattern and( Pattern... patterns )
+    {
+        return and( "", patterns );
+    }
+
+    /** Creates an OR pattern */
+    private static Pattern or( String pattern, Pattern... patterns )
+    {
+        return new OrPattern( pattern, patterns );
+    }
+
+    /** Creates an OR pattern */
+    private static Pattern or( Pattern... patterns )
+    {
+        return or( "", patterns );
+    }
+
+    /** Creates a match-all pattern */
+    private static Pattern all( String pattern )
+    {
+        return new MatchAllPattern( pattern );
+    }
+
+    /**
+     * Abstract class for patterns
+     */
+    abstract static class Pattern
+    {
+        private final String pattern;
+
+        Pattern( String pattern )
         {
-            return VersionRange.createFromVersionSpec( range 
).containsVersion( new DefaultArtifactVersion( version ) );
+            this.pattern = Objects.requireNonNull( pattern );
         }
-        catch ( final InvalidVersionSpecificationException e )
+
+        public abstract boolean matches( char[][] parts );
+
+        /**
+         * Returns a string containing a fixed artifact gatv coordinates
+         * or null if the pattern can not be translated.
+         */
+        public String translateEquals()
         {
-            return false;
+            return null;
         }
-    }
 
-    /** {@inheritDoc} */
-    public void reportMissedCriteria( final Logger logger )
-    {
-        // if there are no patterns, there is nothing to report.
-        if ( !positivePatterns.isEmpty() || !negativePatterns.isEmpty() )
+        /**
+         * Check if the this pattern is a fixed pattern on the specified pos.
+         */
+        protected String translateEquals( int pos )
         {
-            final List<String> missed = new ArrayList<>();
-            missed.addAll( positivePatterns );
-            missed.addAll( negativePatterns );
+            return null;
+        }
 
-            missed.removeAll( patternsTriggered );
+        @Override
+        public String toString()
+        {
+            return pattern;
+        }
+    }
 
-            if ( !missed.isEmpty() && logger.isWarnEnabled() )
-            {
-                final StringBuilder buffer = new StringBuilder();
+    /**
+     * Simple pattern which performs a logical AND between one or more 
patterns.
+     */
+    static class AndPattern extends Pattern
+    {
+        private final Pattern[] patterns;
 
-                buffer.append( "The following patterns were never triggered in 
this " );
-                buffer.append( getFilterDescription() );
-                buffer.append( ':' );
+        AndPattern( String pattern, Pattern[] patterns )
+        {
+            super( pattern );
+            this.patterns = patterns;
+        }
 
-                for ( String pattern : missed )
+        @Override
+        public boolean matches( char[][] parts )
+        {
+            for ( Pattern pattern : patterns )
+            {
+                if ( !pattern.matches( parts ) )
                 {
-                    buffer.append( "\no  '" ).append( pattern ).append( "'" );
+                    return false;
                 }
+            }
+            return true;
+        }
 
-                buffer.append( "\n" );
-
-                logger.warn( buffer.toString() );
+        @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();
         }
     }
 
-    @Override
-    public String toString()
+    /**
+     * Simple pattern which performs a logical OR between one or more patterns.
+     */
+    static class OrPattern extends Pattern
     {
-        return "Includes filter:" + getPatternsAsString();
+        private final Pattern[] patterns;
+
+        OrPattern( String pattern, Pattern[] patterns )
+        {
+            super( pattern );
+            this.patterns = patterns;
+        }
+
+        @Override
+        public boolean matches( char[][] parts )
+        {
+            for ( Pattern pattern : patterns )
+            {
+                if ( pattern.matches( parts ) )
+                {
+                    return true;
+                }
+            }
+            return false;
+        }
     }
 
     /**
-     * @return pattern as a string.
+     * A positional matching pattern, to check if a token in the gatv 
coordinates
+     * having a position between posMin and posMax (both inclusives) can match
+     * the pattern.
      */
-    protected String getPatternsAsString()
+    static class PosPattern extends Pattern
     {
-        final StringBuilder buffer = new StringBuilder();
-        for ( String pattern : positivePatterns )
+        private final char[] patternCharArray;
+        private final int posMin;
+        private final int posMax;
+
+        PosPattern( String pattern, char[] patternCharArray, int posMin, int 
posMax )
         {
-            buffer.append( "\no '" ).append( pattern ).append( "'" );
+            super( pattern );
+            this.patternCharArray = patternCharArray;
+            this.posMin = posMin;
+            this.posMax = posMax;
         }
 
-        return buffer.toString();
+        @Override
+        public boolean matches( char[][] parts )
+        {
+            for ( int i = posMin; i <= posMax; i++ )
+            {
+                if ( match( patternCharArray, parts[i], i == 3 ) )
+                {
+                    return true;
+                }
+            }
+            return false;
+        }
     }
 
     /**
-     * @return description.
+     * Looks for an exact match in the gatv coordinates between
+     * posMin and posMax (both inclusives)
      */
-    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() )
+        EqPattern( String pattern, char[] patternCharArray, int posMin, int 
posMax )
         {
-            final StringBuilder buffer =
-                new StringBuilder( "The following artifacts were removed by 
this " + getFilterDescription() + ": " );
+            super( pattern );
+            this.token = patternCharArray;
+            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() );
+        @Override
+        public String translateEquals()
+        {
+            return translateEquals( 0 );
+        }
+
+        public String translateEquals( int pos )
+        {
+            return posMin == pos && posMax == pos
+                && ( pos < 3 || ( token[0] != '[' && token[0] != '(' ) )
+                    ? String.valueOf( token ) : null;
         }
+
     }
 
-    /** {@inheritDoc} */
-    public boolean hasMissedCriteria()
+    /**
+     * Matches all input
+     */
+    static class MatchAllPattern extends Pattern
     {
-        // if there are no patterns, there is nothing to report.
-        if ( !positivePatterns.isEmpty() || !negativePatterns.isEmpty() )
+        MatchAllPattern( String pattern )
         {
-            final List<String> missed = new ArrayList<>();
-            missed.addAll( positivePatterns );
-            missed.addAll( negativePatterns );
+            super( pattern );
+        }
 
-            missed.removeAll( patternsTriggered );
+        @Override
+        public boolean matches( char[][] parts )
+        {
+            return true;
+        }
+    }
 
-            return !missed.isEmpty();
+    /**
+     * Negative pattern
+     */
+    static class NegativePattern extends Pattern
+    {
+        private final Pattern inner;
+
+        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 96%
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 c9aad45..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
@@ -35,12 +35,12 @@ import org.codehaus.plexus.logging.Logger;
 
 /**
  * TODO: include in maven-artifact in future
- * 
+ *
  * @author <a href="mailto:br...@apache.org";>Brett Porter</a>
  * @see StrictPatternIncludesArtifactFilter
  */
-public class PatternIncludesArtifactFilter
-    implements ArtifactFilter, StatisticsReportingArtifactFilter
+public class OldPatternIncludesArtifactFilter
+        implements ArtifactFilter, StatisticsReportingArtifactFilter
 {
     private final List<String> positivePatterns;
 
@@ -55,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 );
     }
@@ -64,7 +64,7 @@ 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 List<String> pos = new ArrayList<>();
@@ -192,7 +192,7 @@ public class PatternIncludesArtifactFilter
         for ( String pattern : patterns )
         {
             String[] patternTokens = pattern.split( ":" );
-            
+
             if ( patternTokens.length == 5 && tokens.length < 5 )
             {
                 // 4th element is the classifier
@@ -248,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
@@ -396,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 )
             {
@@ -425,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..6cbe7a5
--- /dev/null
+++ 
b/src/test/java/org/apache/maven/shared/artifact/filter/PatternFilterPerfTest.java
@@ -0,0 +1,131 @@
+package org.apache.maven.shared.artifact.filter;
+
+/*
+ * 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.
+ */
+
+import java.util.Arrays;
+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.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();
+    }
+}

Reply via email to