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

cstamas pushed a commit to branch master
in repository 
https://gitbox.apache.org/repos/asf/maven-common-artifact-filters.git


The following commit(s) were added to refs/heads/master by this push:
     new 0c6674f  [MSHARED-1077] Bugfix for classifier in pattern (#26)
0c6674f is described below

commit 0c6674fae7cf110c4a12d0f0f80e93d61f0be391
Author: Tamas Cservenak <ta...@cservenak.net>
AuthorDate: Sat Jun 11 15:23:25 2022 +0200

    [MSHARED-1077] Bugfix for classifier in pattern (#26)
    
    Parsing of pattern with classifier was busted, that
    prevented use cases like before 
[rewrite](https://github.com/apache/maven-common-artifact-filters/commit/4a6f6d6241626ff1f8bce09e9d393126019219f9),
 that was again
    busted due early return (not happening since rewrite, but since rewrite
    we do no support classifiers in patterns).
    
    So, here is yet another rewrite, that not only fixes old use cases (w/ 
classifier)
    but also makes it even more faster. Last, but not least, new code is
    now in high level Java, instead of `char[][]` and is self documenting.
---
 .../filter/PatternExcludesArtifactFilter.java      |   14 +-
 .../filter/PatternIncludesArtifactFilter.java      | 1014 ++++++++------------
 .../filter/AbstractPatternArtifactFilterTest.java  |   35 +
 .../filter/GNPatternIncludesArtifactFilter.java}   |   95 +-
 .../artifact/filter/PatternFilterPerfTest.java     |   35 +
 5 files changed, 487 insertions(+), 706 deletions(-)

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 a78469a..c975886 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
@@ -53,7 +53,7 @@ public class PatternExcludesArtifactFilter
         super( patterns, actTransitively );
     }
 
-    /** {@inheritDoc} */
+    @Override
     public boolean include( Artifact artifact )
     {
         boolean shouldInclude = !patternMatches( artifact );
@@ -66,21 +66,13 @@ public class PatternExcludesArtifactFilter
         return shouldInclude;
     }
 
-    /**
-     * {@inheritDoc}
-     *
-     * @return a {@link java.lang.String} object.
-     */
+    @Override
     protected String getFilterDescription()
     {
         return "artifact exclusion filter";
     }
 
-    /**
-     * {@inheritDoc}
-     *
-     * @return a {@link java.lang.String} object.
-     */
+    @Override
     public String toString()
     {
         return "Excludes filter:" + getPatternsAsString();
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 02e4d1b..b44e6c3 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,15 +20,12 @@ package org.apache.maven.shared.artifact.filter;
  */
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
+import java.util.EnumSet;
 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;
@@ -38,28 +35,36 @@ import 
org.apache.maven.artifact.versioning.InvalidVersionSpecificationException
 import org.apache.maven.artifact.versioning.VersionRange;
 import org.slf4j.Logger;
 
+import static java.util.Objects.requireNonNull;
+
 /**
  * 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 PatternIncludesArtifactFilter implements ArtifactFilter, 
StatisticsReportingArtifactFilter
 {
-    /** Holds the set of compiled patterns */
-    private final Set<Pattern> patterns;
+    private static final String SEP = System.lineSeparator();
 
-    /** Holds simple patterns: those that can use direct matching */
-    private final Map<Integer, Map<String, Pattern>> simplePatterns;
+    /**
+     * Holds the set of compiled patterns
+     */
+    private final Set<Pattern> patterns;
 
-    /** Whether the dependency trail should be checked */
+    /**
+     * Whether the dependency trail should be checked
+     */
     private final boolean actTransitively;
 
-    /** Set of patterns that have been triggered */
+    /**
+     * Set of patterns that have been triggered
+     */
     private final Set<Pattern> patternsTriggered = new HashSet<>();
 
-    /** Set of artifacts that have been filtered out */
+    /**
+     * Set of artifacts that have been filtered out
+     */
     private final List<Artifact> filteredArtifact = new ArrayList<>();
 
     /**
@@ -75,64 +80,25 @@ public class PatternIncludesArtifactFilter
     /**
      * <p>Constructor for PatternIncludesArtifactFilter.</p>
      *
-     * @param patterns The pattern to be used.
+     * @param patterns        The pattern to be used.
      * @param actTransitively transitive yes/no.
      */
     public PatternIncludesArtifactFilter( final Collection<String> patterns, 
final boolean actTransitively )
     {
         this.actTransitively = actTransitively;
         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 )
             {
-
                 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 )
-                {
-                    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();
-                }
-            }
-        }
-        this.simplePatterns = simplePat;
         this.patterns = pat;
     }
 
-    /** {@inheritDoc} */
+    @Override
     public boolean include( final Artifact artifact )
     {
         final boolean shouldInclude = patternMatches( artifact );
@@ -145,22 +111,9 @@ public class PatternIncludesArtifactFilter
         return shouldInclude;
     }
 
-    /**
-     * <p>patternMatches.</p>
-     *
-     * @param artifact to check for.
-     * @return true if the match is true false otherwise.
-     */
     protected boolean patternMatches( final Artifact artifact )
     {
-        // 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 );
+        Boolean match = match( adapt( artifact ) );
         if ( match != null )
         {
             return match;
@@ -174,8 +127,8 @@ public class PatternIncludesArtifactFilter
             {
                 for ( String trailItem : depTrail )
                 {
-                    char[][] depGatvCharArray = tokenizeAndSplit( trailItem );
-                    match = match( depGatvCharArray );
+                    Artifactoid artifactoid = adapt( trailItem );
+                    match = match( artifactoid );
                     if ( match != null )
                     {
                         return match;
@@ -187,36 +140,11 @@ public class PatternIncludesArtifactFilter
         return false;
     }
 
-    private Boolean match( char[][] gatvCharArray )
+    private Boolean match( Artifactoid artifactoid )
     {
-        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 ) )
+            if ( pattern.matches( artifactoid ) )
             {
                 patternsTriggered.add( pattern );
                 return !( pattern instanceof NegativePattern );
@@ -236,7 +164,7 @@ public class PatternIncludesArtifactFilter
         filteredArtifact.add( artifact );
     }
 
-    /** {@inheritDoc} */
+    @Override
     public void reportMissedCriteria( final Logger logger )
     {
         // if there are no patterns, there is nothing to report.
@@ -255,71 +183,56 @@ public class PatternIncludesArtifactFilter
 
                 for ( Pattern pattern : missed )
                 {
-                    buffer.append( "\no  '" ).append( pattern ).append( "'" );
+                    buffer.append( SEP ) .append( "o  '" ).append( pattern 
).append( "'" );
                 }
 
-                buffer.append( "\n" );
+                buffer.append( SEP );
 
                 logger.warn( buffer.toString() );
             }
         }
     }
 
-    /** {@inheritDoc} */
     @Override
     public String toString()
     {
         return "Includes filter:" + getPatternsAsString();
     }
 
-    /**
-     * <p>getPatternsAsString.</p>
-     *
-     * @return pattern as a string.
-     */
     protected String getPatternsAsString()
     {
         final StringBuilder buffer = new StringBuilder();
         for ( Pattern pattern : patterns )
         {
-            buffer.append( "\no '" ).append( pattern ).append( "'" );
+            buffer.append( SEP ).append( "o '" ).append( pattern ).append( "'" 
);
         }
 
         return buffer.toString();
     }
 
-    /**
-     * <p>getFilterDescription.</p>
-     *
-     * @return description.
-     */
     protected String getFilterDescription()
     {
         return "artifact inclusion filter";
     }
 
-    /** {@inheritDoc} */
+    @Override
     public void reportFilteredArtifacts( final Logger logger )
     {
         if ( !filteredArtifact.isEmpty() && logger.isDebugEnabled() )
         {
-            final StringBuilder buffer =
-                new StringBuilder( "The following artifacts were removed by 
this " + getFilterDescription() + ": " );
+            final StringBuilder buffer = new StringBuilder(
+                    "The following artifacts were removed by this " + 
getFilterDescription() + ": " );
 
             for ( Artifact artifactId : filteredArtifact )
             {
-                buffer.append( '\n' ).append( artifactId.getId() );
+                buffer.append( SEP ).append( artifactId.getId() );
             }
 
             logger.debug( buffer.toString() );
         }
     }
 
-    /**
-     * {@inheritDoc}
-     *
-     * @return a boolean.
-     */
+    @Override
     public boolean hasMissedCriteria()
     {
         // if there are no patterns, there is nothing to report.
@@ -327,205 +240,104 @@ public class PatternIncludesArtifactFilter
         {
             final List<Pattern> missed = new ArrayList<>( patterns );
             missed.removeAll( patternsTriggered );
-
             return !missed.isEmpty();
         }
 
         return false;
     }
 
-    private static final char[] EMPTY = new char[0];
-
-    private static final char[] ANY = new char[] { '*' };
-
-    static char[] emptyOrChars( String str )
+    private enum Coordinate
     {
-        return str != null && str.length() > 0 ? str.toCharArray() : EMPTY;
+        GROUP_ID, ARTIFACT_ID, TYPE, CLASSIFIER, BASE_VERSION
     }
 
-    static char[] anyOrChars( char[] str )
+    private interface Artifactoid
     {
-        return str.length > 1 || ( str.length == 1 && str[0] != '*' ) ? str : 
ANY;
+        String getCoordinate( Coordinate coordinate );
     }
 
-    static char[][] tokenizeAndSplit( String pattern )
+    private static Artifactoid adapt( final Artifact artifact )
     {
-        String[] stokens = pattern.split( ":" );
-        char[][] tokens = new char[ stokens.length ][];
-        for ( int i = 0; i < stokens.length; i++ )
+        requireNonNull( artifact );
+        return coordinate ->
         {
-            tokens[i] = emptyOrChars( stokens[i] );
-        }
-        return tokens;
-    }
-
-    @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 )
-        {
-            if ( aPatArr == '*' )
-            {
-                containsStar = true;
-                break;
-            }
-        }
-
-        if ( !containsStar )
-        {
-            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
-        }
-
-        if ( patIdxEnd == 0 )
-        {
-            return true; // Pattern contains only '*', which matches anything
-        }
-
-        // Process characters before first star
-        while ( ( ch = patArr[patIdxStart] ) != '*' && strIdxStart <= 
strIdxEnd )
-        {
-            if ( ch != '?' && ch != strArr[strIdxStart] )
-            {
-                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++ )
+            requireNonNull( coordinate );
+            switch ( coordinate )
             {
-                if ( patArr[i] != '*' )
-                {
-                    return false;
-                }
+                case GROUP_ID:
+                    return artifact.getGroupId();
+                case ARTIFACT_ID:
+                    return artifact.getArtifactId();
+                case BASE_VERSION:
+                    return artifact.getBaseVersion();
+                case CLASSIFIER:
+                    return artifact.hasClassifier() ? artifact.getClassifier() 
: null;
+                case TYPE:
+                    return artifact.getType();
+                default:
             }
-            return true;
-        }
+            throw new IllegalArgumentException( "unknown coordinate: " + 
coordinate );
+        };
+    }
 
-        // Process characters after last star
-        while ( ( ch = patArr[patIdxEnd] ) != '*' && strIdxStart <= strIdxEnd )
+    /**
+     * Parses elements of {@link Artifact#getDependencyTrail()} list, they are 
either {@code G:A:T:V} or if artifact
+     * has classifier {@code G:A:T:C:V}, so strictly 4 or 5 segments only.
+     */
+    private static Artifactoid adapt( final String depTrailString )
+    {
+        requireNonNull( depTrailString );
+        String[] coordinates = depTrailString.split( ":" );
+        if ( coordinates.length != 4 && coordinates.length != 5 )
         {
-            if ( ch != '?' && ch != strArr[strIdxEnd] )
-            {
-                return false; // Character mismatch
-            }
-            patIdxEnd--;
-            strIdxEnd--;
+            throw new IllegalArgumentException( "Bad dep trail string: " + 
depTrailString );
         }
-        if ( strIdxStart > strIdxEnd )
+        final HashMap<Coordinate, String> map = new HashMap<>();
+        map.put( Coordinate.GROUP_ID, coordinates[0] );
+        map.put( Coordinate.ARTIFACT_ID, coordinates[1] );
+        map.put( Coordinate.TYPE, coordinates[2] );
+        if ( coordinates.length == 5 )
         {
-            // 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;
+            map.put( Coordinate.CLASSIFIER, coordinates[3] );
+            map.put( Coordinate.BASE_VERSION, coordinates[4] );
         }
-
-        // process pattern between stars. padIdxStart and patIdxEnd point
-        // always to a '*'.
-        while ( patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd )
+        else
         {
-            int patIdxTmp = -1;
-            for ( int i = patIdxStart + 1; i <= patIdxEnd; i++ )
-            {
-                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 ( foundIdx == -1 )
-            {
-                return false;
-            }
-
-            patIdxStart = patIdxTmp;
-            strIdxStart = foundIdx + patLength;
+            map.put( Coordinate.BASE_VERSION, coordinates[3] );
         }
 
-        // 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++ )
+        return coordinate ->
         {
-            if ( patArr[i] != '*' )
-            {
-                return false;
-            }
-        }
-        return true;
+            requireNonNull( coordinate );
+            return map.get( coordinate );
+        };
     }
 
-    static boolean isVersionIncludedInRange( final String version, final 
String range )
+    private static final String ANY = "*";
+
+    /**
+     * Splits the pattern string into tokens, replacing empty tokens with 
{@link #ANY} for patterns like {@code ::val}
+     * so it retains the position of token.
+     */
+    private static String[] splitAndTokenize( String pattern )
     {
-        try
-        {
-            return VersionRange.createFromVersionSpec( range 
).containsVersion( new DefaultArtifactVersion( version ) );
-        }
-        catch ( final InvalidVersionSpecificationException e )
+        String[] stokens = pattern.split( ":" );
+        String[] tokens = new String[stokens.length];
+        for ( int i = 0; i < stokens.length; i++ )
         {
-            return false;
+            String str = stokens[i];
+            tokens[i] = str != null && !str.isEmpty() ? str : ANY;
         }
+        return tokens;
     }
 
-    static Pattern compile( String pattern )
+    /**
+     * Compiles pattern string into {@link Pattern}.
+     *
+     * TODO: patterns seems NOT documented anywhere, so best we have is source 
below.
+     * TODO: patterns in some cases (3, 2 tokens) seems ambiguous, we may need 
to clean up the specs
+     */
+    private static Pattern compile( String pattern )
     {
         if ( pattern.startsWith( "!" ) )
         {
@@ -533,262 +345,166 @@ public class PatternIncludesArtifactFilter
         }
         else
         {
-            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 )
+            String[] tokens = splitAndTokenize( pattern );
+            if ( tokens.length < 1 || tokens.length > 5 )
             {
                 throw new IllegalArgumentException( "Invalid pattern: " + 
pattern );
             }
-            // we only accept 5 tokens if the classifier = '*'
+
+            ArrayList<Pattern> patterns = new ArrayList<>( 5 );
+
             if ( tokens.length == 5 )
             {
-                if ( tokens[3] != ANY )
+                // trivial, full pattern w/ classifier: G:A:T:C:V
+                patterns.add( toPattern( tokens[0], Coordinate.GROUP_ID ) );
+                patterns.add( toPattern( tokens[1], Coordinate.ARTIFACT_ID ) );
+                patterns.add( toPattern( tokens[2], Coordinate.TYPE ) );
+                patterns.add( toPattern( tokens[3], Coordinate.CLASSIFIER ) );
+                patterns.add( toPattern( tokens[4], Coordinate.BASE_VERSION ) 
);
+            }
+            else if ( tokens.length == 4 )
+            {
+                // trivial, full pattern w/o classifier: G:A:T:V
+                patterns.add( toPattern( tokens[0], Coordinate.GROUP_ID ) );
+                patterns.add( toPattern( tokens[1], Coordinate.ARTIFACT_ID ) );
+                patterns.add( toPattern( tokens[2], Coordinate.TYPE ) );
+                patterns.add( toPattern( tokens[3], Coordinate.BASE_VERSION ) 
);
+            }
+            else if ( tokens.length == 3 )
+            {
+                // tricky: may be "*:artifact:*" but also "*:war:*"
+
+                // *:*:* -> ALL
+                // *:*:xxx -> TC(xxx)
+                // *:xxx:* -> AT(xxx)
+                // *:xxx:yyy -> GA(xxx) + TC(XXX)
+                // xxx:*:* -> GA(xxx)
+                // xxx:*:yyy -> G(xxx) + TC(yyy)
+                // xxx:yyy:* -> G(xxx)+A(yyy)
+                // xxx:yyy:zzz -> G(xxx)+A(yyy)+T(zzz)
+                if ( ANY.equals( tokens[0] ) && ANY.equals( tokens[1] ) && 
ANY.equals( tokens[2] ) )
                 {
-                    throw new IllegalArgumentException( "Invalid pattern: " + 
pattern );
+                    patterns.add( MATCH_ALL_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 )
+                else if ( ANY.equals( tokens[0] ) && ANY.equals( tokens[1] ) )
+                {
+                    patterns.add( new CoordinateMatchingPattern( pattern, 
tokens[2],
+                            EnumSet.of( Coordinate.TYPE, Coordinate.CLASSIFIER 
) ) );
+                }
+                else if ( ANY.equals( tokens[0] ) && ANY.equals( tokens[2] ) )
+                {
+                    patterns.add( new CoordinateMatchingPattern( pattern, 
tokens[1],
+                            EnumSet.of( Coordinate.ARTIFACT_ID, 
Coordinate.TYPE ) ) );
+                }
+                else if ( ANY.equals( tokens[0] ) )
+                {
+                    patterns.add( new CoordinateMatchingPattern( pattern, 
tokens[1],
+                            EnumSet.of( Coordinate.GROUP_ID, 
Coordinate.ARTIFACT_ID ) ) );
+                    patterns.add( new CoordinateMatchingPattern( pattern, 
tokens[2],
+                            EnumSet.of( Coordinate.TYPE, Coordinate.CLASSIFIER 
) ) );
+                }
+                else if ( ANY.equals( tokens[1] ) && ANY.equals( tokens[2] ) )
+                {
+                    patterns.add( new CoordinateMatchingPattern( pattern, 
tokens[0],
+                            EnumSet.of( Coordinate.GROUP_ID, 
Coordinate.ARTIFACT_ID ) ) );
+                }
+                else if ( ANY.equals( tokens[1] ) )
+                {
+                    patterns.add( toPattern( tokens[0], Coordinate.GROUP_ID ) 
);
+                    patterns.add( new CoordinateMatchingPattern( pattern, 
tokens[2],
+                            EnumSet.of( Coordinate.TYPE, Coordinate.CLASSIFIER 
) ) );
+                }
+                else if ( ANY.equals( tokens[2] ) )
                 {
-                    // *
-                    return all( pattern );
+                    patterns.add( toPattern( tokens[0], Coordinate.GROUP_ID ) 
);
+                    patterns.add( toPattern( tokens[1], Coordinate.ARTIFACT_ID 
) );
                 }
                 else
                 {
-                    // [pat0]
-                    return match( pattern, tokens[0], 0 );
+                    patterns.add( toPattern( tokens[0], Coordinate.GROUP_ID ) 
);
+                    patterns.add( toPattern( tokens[1], Coordinate.ARTIFACT_ID 
) );
+                    patterns.add( toPattern( tokens[2], Coordinate.TYPE ) );
                 }
+
             }
-            if ( tokens.length == 2 )
+            else if ( tokens.length == 2 )
             {
-                if ( tokens[0] == ANY )
+                // tricky: may be "*:artifact" but also "*:war"
+                // *:* -> ALL
+                // *:xxx -> GATV(xxx)
+                // xxx:* -> G(xxx)
+                // xxx:yyy -> G(xxx)+A(yyy)
+
+                if ( ANY.equals( tokens[0] ) && ANY.equals( tokens[1] ) )
                 {
-                    if ( tokens[1] == ANY )
-                    {
-                        // *:*
-                        return all( pattern );
-                    }
-                    else
-                    {
-                        // *:[pat1]
-                        return match( pattern, tokens[1], 0, 3 );
-                    }
+                    patterns.add( MATCH_ALL_PATTERN );
+                }
+                else if ( ANY.equals( tokens[0] ) )
+                {
+                    patterns.add( new CoordinateMatchingPattern( pattern, 
tokens[1],
+                            EnumSet.of( Coordinate.GROUP_ID, 
Coordinate.ARTIFACT_ID, Coordinate.TYPE,
+                                    Coordinate.BASE_VERSION ) ) );
+                }
+                else if ( ANY.equals( tokens[1] ) )
+                {
+                    patterns.add( toPattern( tokens[0], Coordinate.GROUP_ID ) 
);
                 }
                 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 );
-                    }
+                    patterns.add( toPattern( tokens[0], Coordinate.GROUP_ID ) 
);
+                    patterns.add( toPattern( tokens[1], Coordinate.ARTIFACT_ID 
) );
                 }
             }
-            if ( tokens.length == 3 )
+            else
+            {
+                // trivial: G
+                patterns.add( toPattern( tokens[0], Coordinate.GROUP_ID ) );
+            }
+
+            // build result if needed and retains pattern string
+            if ( patterns.size() == 1 )
             {
-                if ( tokens[0] == ANY )
+                Pattern pat = patterns.get( 0 );
+                if ( pat == MATCH_ALL_PATTERN )
                 {
-                    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 
) );
-                        }
-                    }
+                    return new MatchAllPattern( pattern );
                 }
                 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 );
-                        }
-                    }
+                    return pat;
                 }
             }
-            if ( tokens.length == 4 )
+            else
             {
-                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] ) );
+                return new AndPattern( pattern, patterns.toArray( new 
Pattern[0] ) );
             }
-            throw new IllegalStateException();
         }
     }
 
-    /** Creates a positional matching pattern */
-    private static Pattern match( String pattern, char[] token, int posVal )
+    private static Pattern toPattern( final String token, final Coordinate 
coordinate )
     {
-        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 ( ANY.equals( token ) )
         {
-            if ( ch == '*' || ch == '?' )
-            {
-                hasWildcard = true;
-                break;
-            }
-        }
-        if ( hasWildcard || posMax == 3 )
-        {
-            return new PosPattern( pattern, token, posMin, posMax );
+            return MATCH_ALL_PATTERN;
         }
         else
         {
-            return new EqPattern( pattern, token, posMin, posMax );
+            return new CoordinateMatchingPattern( token, token, EnumSet.of( 
coordinate ) );
         }
     }
 
-    /** Creates a positional matching pattern */
-    private static Pattern match( char[] token, int posMin, int posMax )
-    {
-        return new PosPattern( "", token, posMin, posMax );
-    }
+    private static final Pattern MATCH_ALL_PATTERN = new MatchAllPattern( ANY 
);
 
-    /** Creates an AND pattern */
-    private static Pattern and( String pattern, Pattern... patterns )
+    private abstract static class Pattern
     {
-        return new AndPattern( pattern, patterns );
-    }
-
-    /** Creates an AND pattern */
-    private static Pattern and( Pattern... patterns )
-    {
-        return and( "", patterns );
-    }
+        protected final String pattern;
 
-    /** 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 )
-        {
-            this.pattern = Objects.requireNonNull( pattern );
-        }
-
-        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()
+        private Pattern( String pattern )
         {
-            return null;
+            this.pattern = requireNonNull( pattern );
         }
 
-        /**
-         * Check if the this pattern is a fixed pattern on the specified pos.
-         */
-        protected String translateEquals( int pos )
-        {
-            return null;
-        }
+        public abstract boolean matches( Artifactoid artifact );
 
         @Override
         public String toString()
@@ -797,78 +513,93 @@ public class PatternIncludesArtifactFilter
         }
     }
 
-    /**
-     * Simple pattern which performs a logical AND between one or more 
patterns.
-     */
-    static class AndPattern extends Pattern
+    private static class AndPattern extends Pattern
     {
         private final Pattern[] patterns;
 
-        AndPattern( String pattern, Pattern[] patterns )
+        private AndPattern( String pattern, Pattern[] patterns )
         {
             super( pattern );
             this.patterns = patterns;
         }
 
         @Override
-        public boolean matches( char[][] parts )
+        public boolean matches( Artifactoid artifactoid )
         {
             for ( Pattern pattern : patterns )
             {
-                if ( !pattern.matches( parts ) )
+                if ( !pattern.matches( artifactoid ) )
                 {
                     return false;
                 }
             }
             return true;
         }
+    }
 
-        @Override
-        public String translateEquals()
+    private static class CoordinateMatchingPattern extends Pattern
+    {
+        private final String token;
+
+        private final EnumSet<Coordinate> coordinates;
+
+        private final boolean containsWildcard;
+
+        private final boolean containsAsterisk;
+
+        private final VersionRange optionalVersionRange;
+
+        private CoordinateMatchingPattern( String pattern, String token, 
EnumSet<Coordinate> coordinates )
         {
-            String[] strings = new String[ patterns.length ];
-            for ( int i = 0; i < patterns.length; i++ )
-            {
-                strings[i] = patterns[i].translateEquals( i );
-                if ( strings[i] == null )
+            super( pattern );
+            this.token = token;
+            this.coordinates = coordinates;
+            this.containsAsterisk = token.contains( "*" );
+            this.containsWildcard = this.containsAsterisk || token.contains( 
"?" );
+            if ( !this.containsWildcard && coordinates.equals( EnumSet.of( 
Coordinate.BASE_VERSION ) ) && (
+                    token.startsWith( "[" ) || token.startsWith( "(" ) ) )
+            {
+                try
                 {
-                    return null;
+                    this.optionalVersionRange = 
VersionRange.createFromVersionSpec( token );
                 }
-            }
-            StringBuilder sb = new StringBuilder();
-            for ( int i = 0; i < strings.length; i++ )
-            {
-                if ( i > 0 )
+                catch ( InvalidVersionSpecificationException e )
                 {
-                    sb.append( ":" );
+                    throw new IllegalArgumentException( "Wrong version spec: " 
+ token, e );
                 }
-                sb.append( strings[i] );
             }
-            return sb.toString();
-        }
-    }
-
-    /**
-     * Simple pattern which performs a logical OR between one or more patterns.
-     */
-    static class OrPattern extends Pattern
-    {
-        private final Pattern[] patterns;
-
-        OrPattern( String pattern, Pattern[] patterns )
-        {
-            super( pattern );
-            this.patterns = patterns;
+            else
+            {
+                this.optionalVersionRange = null;
+            }
         }
 
         @Override
-        public boolean matches( char[][] parts )
+        public boolean matches( Artifactoid artifactoid )
         {
-            for ( Pattern pattern : patterns )
+            for ( Coordinate coordinate : coordinates )
             {
-                if ( pattern.matches( parts ) )
+                String value = artifactoid.getCoordinate( coordinate );
+                if ( Coordinate.BASE_VERSION == coordinate && 
optionalVersionRange != null )
+                {
+                    if ( optionalVersionRange.containsVersion( new 
DefaultArtifactVersion( value ) ) )
+                    {
+                        return true;
+                    }
+                }
+                else if ( containsWildcard )
                 {
-                    return true;
+                    if ( match( token, containsAsterisk, value ) )
+                    {
+                        return true;
+                    }
+                }
+                else
+                {
+                    if ( token.equals( value ) )
+                    {
+                        return true;
+                    }
                 }
             }
             return false;
@@ -876,119 +607,184 @@ public class PatternIncludesArtifactFilter
     }
 
     /**
-     * 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.
+     * Matches all input
      */
-    static class PosPattern extends Pattern
+    private static class MatchAllPattern extends Pattern
     {
-        private final char[] patternCharArray;
-        private final int posMin;
-        private final int posMax;
-
-        PosPattern( String pattern, char[] patternCharArray, int posMin, int 
posMax )
+        private MatchAllPattern( String pattern )
         {
             super( pattern );
-            this.patternCharArray = patternCharArray;
-            this.posMin = posMin;
-            this.posMax = posMax;
         }
 
         @Override
-        public boolean matches( char[][] parts )
+        public boolean matches( Artifactoid artifactoid )
         {
-            for ( int i = posMin; i <= posMax; i++ )
-            {
-                if ( match( patternCharArray, parts[i], i == 3 ) )
-                {
-                    return true;
-                }
-            }
-            return false;
+            return true;
         }
     }
 
     /**
-     * Looks for an exact match in the gatv coordinates between
-     * posMin and posMax (both inclusives)
+     * Negative pattern
      */
-    static class EqPattern extends Pattern
+    private static class NegativePattern extends Pattern
     {
-        private final char[] token;
-        private final int posMin;
-        private final int posMax;
+        private final Pattern inner;
 
-        EqPattern( String pattern, char[] patternCharArray, int posMin, int 
posMax )
+        private NegativePattern( String pattern, Pattern inner )
         {
             super( pattern );
-            this.token = patternCharArray;
-            this.posMin = posMin;
-            this.posMax = posMax;
+            this.inner = inner;
         }
 
         @Override
-        public boolean matches( char[][] parts )
+        public boolean matches( Artifactoid artifactoid )
+        {
+            return inner.matches( artifactoid );
+        }
+    }
+
+    // this beauty below must be salvaged
+
+    @SuppressWarnings( "InnerAssignment" )
+    private static boolean match( final String pattern, final boolean 
containsAsterisk, final String value )
+    {
+        char[] patArr = pattern.toCharArray();
+        char[] strArr = value.toCharArray();
+        int patIdxStart = 0;
+        int patIdxEnd = patArr.length - 1;
+        int strIdxStart = 0;
+        int strIdxEnd = strArr.length - 1;
+        char ch;
+
+        if ( !containsAsterisk )
         {
-            for ( int i = posMin; i <= posMax; i++ )
+            // No '*'s, so we make a shortcut
+            if ( patIdxEnd != strIdxEnd )
             {
-                if ( Arrays.equals( token, parts[i] ) )
+                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 true;
+                    return false; // Character mismatch
                 }
             }
-            return false;
+            return true; // String matches against pattern
         }
 
-        @Override
-        public String translateEquals()
+        if ( patIdxEnd == 0 )
         {
-            return translateEquals( 0 );
+            return true; // Pattern contains only '*', which matches anything
         }
 
-        public String translateEquals( int pos )
+        // Process characters before first star
+        while ( ( ch = patArr[patIdxStart] ) != '*' && strIdxStart <= 
strIdxEnd )
         {
-            return posMin == pos && posMax == pos
-                && ( pos < 3 || ( token[0] != '[' && token[0] != '(' ) )
-                    ? String.valueOf( token ) : null;
+            if ( ch != '?' && ch != strArr[strIdxStart] )
+            {
+                return false; // Character mismatch
+            }
+            patIdxStart++;
+            strIdxStart++;
         }
-
-    }
-
-    /**
-     * Matches all input
-     */
-    static class MatchAllPattern extends Pattern
-    {
-        MatchAllPattern( String pattern )
+        if ( strIdxStart > strIdxEnd )
         {
-            super( pattern );
+            // 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;
         }
 
-        @Override
-        public boolean matches( char[][] parts )
+        // 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;
         }
-    }
-
-    /**
-     * Negative pattern
-     */
-    static class NegativePattern extends Pattern
-    {
-        private final Pattern inner;
 
-        NegativePattern( String pattern, Pattern inner )
+        // process pattern between stars. padIdxStart and patIdxEnd point
+        // always to a '*'.
+        while ( patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd )
         {
-            super( pattern );
-            this.inner = inner;
+            int patIdxTmp = -1;
+            for ( int i = patIdxStart + 1; i <= patIdxEnd; i++ )
+            {
+                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 ( foundIdx == -1 )
+            {
+                return false;
+            }
+
+            patIdxStart = patIdxTmp;
+            strIdxStart = foundIdx + patLength;
         }
 
-        @Override
-        public boolean matches( char[][] parts )
+        // 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++ )
         {
-            return inner.matches( parts );
+            if ( patArr[i] != '*' )
+            {
+                return false;
+            }
         }
+        return true;
     }
-
 }
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 cb4ad8d..2a6d914 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
@@ -544,4 +544,39 @@ public abstract class AbstractPatternArtifactFilterTest
             assertTrue( filter.include( artifact ) );
         }
     }
+
+    @Test
+    public void testmassembly955()
+    {
+        Artifact artifact1 = mock( Artifact.class );
+        when( artifact1.getGroupId() ).thenReturn( "org.python" );
+        when( artifact1.getArtifactId() ).thenReturn( "jython-standalone" );
+        when( artifact1.getType() ).thenReturn( "jar" );
+        when( artifact1.getBaseVersion() ).thenReturn( "1.0" );
+
+        Artifact artifact2 = mock( Artifact.class );
+        when( artifact2.getGroupId() ).thenReturn( "org.teiid" );
+        when( artifact2.getArtifactId() ).thenReturn( "teiid" );
+        when( artifact2.getType() ).thenReturn( "jar" );
+        when( artifact2.hasClassifier() ).thenReturn( true );
+        when( artifact2.getClassifier() ).thenReturn( "jdbc" );
+        when( artifact2.getBaseVersion() ).thenReturn( "1.0" );
+
+        final List<String> patterns = new ArrayList<>();
+        patterns.add( "org.teiid:teiid:*:jdbc:*" );
+        patterns.add( "org.python:jython-standalone" );
+
+        final ArtifactFilter filter = createFilter( patterns );
+
+        if ( isInclusionNotExpected() )
+        {
+            assertFalse( filter.include( artifact1 ) );
+            assertFalse( filter.include( artifact2 ) );
+        }
+        else
+        {
+            assertTrue( filter.include( artifact1 ) );
+            assertTrue( filter.include( artifact2 ) );
+        }
+    }
 }
diff --git 
a/src/main/java/org/apache/maven/shared/artifact/filter/PatternIncludesArtifactFilter.java
 
b/src/test/java/org/apache/maven/shared/artifact/filter/GNPatternIncludesArtifactFilter.java
similarity index 88%
copy from 
src/main/java/org/apache/maven/shared/artifact/filter/PatternIncludesArtifactFilter.java
copy to 
src/test/java/org/apache/maven/shared/artifact/filter/GNPatternIncludesArtifactFilter.java
index 02e4d1b..669a60a 100644
--- 
a/src/main/java/org/apache/maven/shared/artifact/filter/PatternIncludesArtifactFilter.java
+++ 
b/src/test/java/org/apache/maven/shared/artifact/filter/GNPatternIncludesArtifactFilter.java
@@ -22,12 +22,9 @@ 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;
 
@@ -44,15 +41,12 @@ import org.slf4j.Logger;
  * @author <a href="mailto:br...@apache.org";>Brett Porter</a>
  * @see StrictPatternIncludesArtifactFilter
  */
-public class PatternIncludesArtifactFilter
+public class GNPatternIncludesArtifactFilter
     implements ArtifactFilter, StatisticsReportingArtifactFilter
 {
     /** Holds the set of compiled patterns */
     private final Set<Pattern> patterns;
 
-    /** 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;
 
@@ -67,7 +61,7 @@ public class PatternIncludesArtifactFilter
      *
      * @param patterns The pattern to be used.
      */
-    public PatternIncludesArtifactFilter( final Collection<String> patterns )
+    public GNPatternIncludesArtifactFilter( final Collection<String> patterns )
     {
         this( patterns, false );
     }
@@ -78,57 +72,19 @@ 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 GNPatternIncludesArtifactFilter( final Collection<String> patterns, 
final boolean actTransitively )
     {
         this.actTransitively = actTransitively;
         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 )
             {
 
                 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 )
-                {
-                    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();
-                }
-            }
-        }
-        this.simplePatterns = simplePat;
         this.patterns = pat;
     }
 
@@ -158,6 +114,7 @@ public class PatternIncludesArtifactFilter
                             emptyOrChars( artifact.getGroupId() ),
                             emptyOrChars( artifact.getArtifactId() ),
                             emptyOrChars( artifact.getType() ),
+                            emptyOrChars( artifact.getClassifier() ),
                             emptyOrChars( artifact.getBaseVersion() )
                     };
         Boolean match = match( artifactGatvCharArray );
@@ -189,31 +146,6 @@ public class PatternIncludesArtifactFilter
 
     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 ) )
@@ -543,17 +475,8 @@ public class PatternIncludesArtifactFilter
             {
                 throw new IllegalArgumentException( "Invalid pattern: " + 
pattern );
             }
-            // we only accept 5 tokens if the classifier = '*'
-            if ( tokens.length == 5 )
-            {
-                if ( tokens[3] != ANY )
-                {
-                    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
+            // Check the 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
             //
@@ -673,10 +596,10 @@ public class PatternIncludesArtifactFilter
                     }
                 }
             }
-            if ( tokens.length == 4 )
+            if ( tokens.length >= 4 )
             {
                 List<Pattern> patterns = new ArrayList<>();
-                for ( int i = 0; i < 4; i++ )
+                for ( int i = 0; i < tokens.length; i++ )
                 {
                     if ( tokens[i] != ANY )
                     {
@@ -713,7 +636,7 @@ public class PatternIncludesArtifactFilter
                 break;
             }
         }
-        if ( hasWildcard || posMax == 3 )
+        if ( hasWildcard || posMax == 4 )
         {
             return new PosPattern( pattern, token, posMin, posMax );
         }
@@ -899,7 +822,7 @@ public class PatternIncludesArtifactFilter
         {
             for ( int i = posMin; i <= posMax; i++ )
             {
-                if ( match( patternCharArray, parts[i], i == 3 ) )
+                if ( match( patternCharArray, parts[i], i == 4 ) )
                 {
                     return true;
                 }
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
index 6cbe7a5..7ee0013 100644
--- 
a/src/test/java/org/apache/maven/shared/artifact/filter/PatternFilterPerfTest.java
+++ 
b/src/test/java/org/apache/maven/shared/artifact/filter/PatternFilterPerfTest.java
@@ -75,6 +75,35 @@ public class PatternFilterPerfTest {
 
     }
 
+    @State(Scope.Benchmark)
+    static public class GNPatternState {
+
+        @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 GNPatternIncludesArtifactFilter( Arrays.asList( 
patterns.split( "," ) ) );
+            artifact = new DefaultArtifact(
+                    "groupId", "artifact-99", "1.0", "runtime",
+                    "jar", "", null
+            );
+        }
+
+    }
+
     @State(Scope.Benchmark)
     static public class NewPatternState {
 
@@ -111,6 +140,12 @@ public class PatternFilterPerfTest {
         return state.filter.include( state.artifact );
     }
 
+    @Benchmark
+    public boolean gnPatternTest(GNPatternState state )
+    {
+        return state.filter.include( state.artifact );
+    }
+
     @Benchmark
     public boolean oldPatternTest(OldPatternState state )
     {

Reply via email to