001package org.apache.maven.plugins.enforcer.utils;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 *  http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import java.util.Collection;
023import java.util.LinkedList;
024
025import org.apache.maven.artifact.Artifact;
026import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
027import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
028import org.apache.maven.artifact.versioning.VersionRange;
029import org.apache.maven.plugins.enforcer.AbstractVersionEnforcer;
030
031/**
032 * This class is used for matching Artifacts against a list of patterns.
033 * 
034 * @author Jakub Senko
035 * @see org.apache.maven.plugins.enforcer.BanTransitiveDependencies
036 */
037public final class ArtifactMatcher
038{
039
040    public static class Pattern
041    {
042        private String pattern;
043
044        private String[] parts;
045
046        public Pattern( String pattern )
047        {
048            if ( pattern == null )
049            {
050                throw new NullPointerException( "pattern" );
051            }
052
053            this.pattern = pattern;
054
055            parts = pattern.split( ":", 7 );
056
057            if ( parts.length == 7 )
058            {
059                throw new IllegalArgumentException( "Pattern contains too many delimiters." );
060            }
061
062            for ( String part : parts )
063            {
064                if ( "".equals( part ) )
065                {
066                    throw new IllegalArgumentException( "Pattern or its part is empty." );
067                }
068            }
069        }
070
071        public boolean match( Artifact artifact )
072            throws InvalidVersionSpecificationException
073        {
074            if ( artifact == null )
075            {
076                throw new NullPointerException( "artifact" );
077            }
078
079            switch ( parts.length )
080            {
081                case 6:
082                    String classifier = artifact.getClassifier();
083                    if ( !matches( parts[5], classifier ) )
084                    {
085                        return false;
086                    }
087                case 5:
088                    String scope = artifact.getScope();
089                    if ( scope == null || scope.equals( "" ) )
090                    {
091                        scope = "compile";
092                    }
093
094                    if ( !matches( parts[4], scope ) )
095                    {
096                        return false;
097                    }
098                case 4:
099                    String type = artifact.getType();
100                    if ( type == null || type.equals( "" ) )
101                    {
102                        type = "jar";
103                    }
104
105                    if ( !matches( parts[3], type ) )
106                    {
107                        return false;
108                    }
109
110                case 3:
111                    if ( !matches( parts[2], artifact.getVersion() ) )
112                    {
113                        if ( !AbstractVersionEnforcer.containsVersion( VersionRange.createFromVersionSpec( parts[2] ),
114                                                                       new DefaultArtifactVersion(
115                                                                                                   artifact.getVersion() ) ) )
116                        {
117                            return false;
118                        }
119                    }
120
121                case 2:
122                    if ( !matches( parts[1], artifact.getArtifactId() ) )
123                    {
124                        return false;
125                    }
126                case 1:
127                    if ( !matches( parts[0], artifact.getGroupId() ) )
128                    {
129                        return false;
130                    }
131                    else
132                    {
133                        return true;
134                    }
135                default:
136                    throw new AssertionError();
137            }
138        }
139        
140        private boolean matches( String expression, String input )
141        {
142            String regex = expression.replace( ".", "\\." ).replace( "*", ".*" ).replace( ":", "\\:" ).replace( '?', '.' );
143
144            return java.util.regex.Pattern.matches( regex , input );
145        }
146
147        @Override
148        public String toString()
149        {
150            return pattern;
151        }
152    }
153
154    private Collection<Pattern> patterns = new LinkedList<Pattern>();
155
156    private Collection<Pattern> ignorePatterns = new LinkedList<Pattern>();
157
158    /**
159     * Construct class by providing patterns as strings. Empty strings are ignored.
160     * 
161     * @throws NullPointerException if any of the arguments is null
162     */
163    public ArtifactMatcher( final Collection<String> patterns, final Collection<String> ignorePatterns )
164    {
165        if ( patterns == null )
166        {
167            throw new NullPointerException( "patterns" );
168        }
169        if ( ignorePatterns == null )
170        {
171            throw new NullPointerException( "ignorePatterns" );
172        }
173        for ( String pattern : patterns )
174        {
175            if ( pattern != null && !"".equals( pattern ) )
176            {
177                this.patterns.add( new Pattern( pattern ) );
178            }
179        }
180
181        for ( String ignorePattern : ignorePatterns )
182        {
183            if ( ignorePattern != null && !"".equals( ignorePattern ) )
184            {
185                this.ignorePatterns.add( new Pattern( ignorePattern ) );
186            }
187        }
188    }
189
190    /**
191     * Check if artifact matches patterns.
192     * 
193     * @throws InvalidVersionSpecificationException
194     */
195    public boolean match( Artifact artifact )
196        throws InvalidVersionSpecificationException
197    {
198        for ( Pattern pattern : patterns )
199        {
200            if ( pattern.match( artifact ) )
201            {
202                for ( Pattern ignorePattern : ignorePatterns )
203                {
204                    if ( ignorePattern.match( artifact ) )
205                    {
206                        return false;
207                    }
208                }
209                return true;
210            }
211        }
212        return false;
213    }
214}