1 package org.apache.maven.shared.artifact.filter; 2 3 /* 4 * Licensed to the Apache Software Foundation (ASF) under one 5 * or more contributor license agreements. See the NOTICE file 6 * distributed with this work for additional information 7 * regarding copyright ownership. The ASF licenses this file 8 * to you under the Apache License, Version 2.0 (the 9 * "License"); you may not use this file except in compliance 10 * with the License. You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, 15 * software distributed under the License is distributed on an 16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 * KIND, either express or implied. See the License for the 18 * specific language governing permissions and limitations 19 * under the License. 20 */ 21 22 import org.apache.maven.artifact.Artifact; 23 import org.apache.maven.artifact.resolver.filter.ArtifactFilter; 24 import org.apache.maven.artifact.versioning.DefaultArtifactVersion; 25 import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException; 26 import org.apache.maven.artifact.versioning.VersionRange; 27 28 import java.util.Iterator; 29 import java.util.List; 30 31 /** 32 * Filter to include or exclude artifacts from a list of patterns. The artifact pattern syntax is of the form: 33 * 34 * <pre> 35 * [groupId]:[artifactId]:[type]:[version] 36 * </pre> 37 * 38 * <p> 39 * Where each pattern segment is optional and supports full and partial <code>*</code> wildcards. An empty pattern 40 * segment is treated as an implicit wildcard. 41 * </p> 42 * 43 * <p> 44 * For example, <code>org.apache.*</code> would match all artifacts whose group id started with 45 * <code>org.apache.</code>, and <code>:::*-SNAPSHOT</code> would match all snapshot artifacts. 46 * </p> 47 * 48 * @author <a href="mailto:markhobson@gmail.com">Mark Hobson</a> 49 * @version $Id: AbstractStrictPatternArtifactFilter.java 803321 2009-08-11 23:09:24Z aheritier $ 50 */ 51 public abstract class AbstractStrictPatternArtifactFilter implements ArtifactFilter 52 { 53 // fields ----------------------------------------------------------------- 54 55 /** 56 * The list of artifact patterns to match, as described above. 57 */ 58 private final List patterns; 59 60 /** 61 * Whether this filter should include or exclude artifacts that match the patterns. 62 */ 63 private final boolean include; 64 65 // constructors ----------------------------------------------------------- 66 67 /** 68 * Creates a new filter that matches the specified artifact patterns and includes or excludes them according to the 69 * specified flag. 70 * 71 * @param patterns 72 * the list of artifact patterns to match, as described above 73 * @param include 74 * <code>true</code> to include artifacts that match the patterns, or <code>false</code> to exclude 75 * them 76 */ 77 public AbstractStrictPatternArtifactFilter( List patterns, boolean include ) 78 { 79 this.patterns = patterns; 80 this.include = include; 81 } 82 83 // ArtifactFilter methods ------------------------------------------------- 84 85 /* 86 * @see org.apache.maven.artifact.resolver.filter.ArtifactFilter#include(org.apache.maven.artifact.Artifact) 87 */ 88 public boolean include( Artifact artifact ) 89 { 90 boolean matched = false; 91 92 for ( Iterator i = patterns.iterator(); i.hasNext() & !matched; ) 93 { 94 String pattern = (String) i.next(); 95 96 if ( include( artifact, pattern ) ) 97 { 98 matched = true; 99 } 100 } 101 102 return include ? matched : !matched; 103 } 104 105 // private methods -------------------------------------------------------- 106 107 /** 108 * Gets whether the specified artifact matches the specified pattern. 109 * 110 * @param artifact 111 * the artifact to check 112 * @param pattern 113 * the pattern to match, as defined above 114 * @return <code>true</code> if the specified artifact is matched by the specified pattern 115 */ 116 private boolean include( Artifact artifact, String pattern ) 117 { 118 String[] tokens = new String[] { 119 artifact.getGroupId(), 120 artifact.getArtifactId(), 121 artifact.getType(), 122 artifact.getBaseVersion() 123 }; 124 125 String[] patternTokens = pattern.split( ":" ); 126 127 // fail immediately if pattern tokens outnumber tokens to match 128 boolean matched = ( patternTokens.length <= tokens.length ); 129 130 for ( int i = 0; matched && i < patternTokens.length; i++ ) 131 { 132 matched = matches( tokens[i], patternTokens[i] ); 133 } 134 135 return matched; 136 } 137 138 /** 139 * Gets whether the specified token matches the specified pattern segment. 140 * 141 * @param token 142 * the token to check 143 * @param pattern 144 * the pattern segment to match, as defined above 145 * @return <code>true</code> if the specified token is matched by the specified pattern segment 146 */ 147 private boolean matches( String token, String pattern ) 148 { 149 boolean matches; 150 151 // support full wildcard and implied wildcard 152 if ( "*".equals( pattern ) || pattern.length() == 0 ) 153 { 154 matches = true; 155 } 156 // support contains wildcard 157 else if ( pattern.startsWith( "*" ) && pattern.endsWith( "*" ) ) 158 { 159 String contains = pattern.substring( 1, pattern.length() - 1 ); 160 161 matches = ( token.indexOf( contains ) != -1 ); 162 } 163 // support leading wildcard 164 else if ( pattern.startsWith( "*" ) ) 165 { 166 String suffix = pattern.substring( 1, pattern.length() ); 167 168 matches = token.endsWith( suffix ); 169 } 170 // support trailing wildcard 171 else if ( pattern.endsWith( "*" ) ) 172 { 173 String prefix = pattern.substring( 0, pattern.length() - 1 ); 174 175 matches = token.startsWith( prefix ); 176 } 177 // support versions range 178 else if ( pattern.startsWith( "[" ) || pattern.startsWith( "(" )) 179 { 180 matches = isVersionIncludedInRange(token, pattern); 181 } 182 // support exact match 183 else 184 { 185 matches = token.equals( pattern ); 186 } 187 188 return matches; 189 } 190 191 private boolean isVersionIncludedInRange(final String version, final String range) { 192 try { 193 return VersionRange.createFromVersionSpec(range).containsVersion(new DefaultArtifactVersion(version)); 194 } catch (InvalidVersionSpecificationException e) { 195 return false; 196 } 197 } 198 199 }