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