1 package org.eclipse.aether.artifact; 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 java.io.File; 23 import java.util.Collections; 24 import java.util.HashMap; 25 import java.util.Map; 26 import java.util.regex.Matcher; 27 import java.util.regex.Pattern; 28 29 /** 30 * A simple artifact. <em>Note:</em> Instances of this class are immutable and the exposed mutators return new objects 31 * rather than changing the current instance. 32 */ 33 public final class DefaultArtifact 34 extends AbstractArtifact 35 { 36 37 private final String groupId; 38 39 private final String artifactId; 40 41 private final String version; 42 43 private final String classifier; 44 45 private final String extension; 46 47 private final File file; 48 49 private final Map<String, String> properties; 50 51 /** 52 * Creates a new artifact with the specified coordinates. If not specified in the artifact coordinates, the 53 * artifact's extension defaults to {@code jar} and classifier to an empty string. 54 * 55 * @param coords The artifact coordinates in the format 56 * {@code <groupId>:<artifactId>[:<extension>[:<classifier>]]:<version>}, must not be {@code null}. 57 */ 58 public DefaultArtifact( String coords ) 59 { 60 this( coords, Collections.<String, String>emptyMap() ); 61 } 62 63 /** 64 * Creates a new artifact with the specified coordinates and properties. If not specified in the artifact 65 * coordinates, the artifact's extension defaults to {@code jar} and classifier to an empty string. 66 * 67 * @param coords The artifact coordinates in the format 68 * {@code <groupId>:<artifactId>[:<extension>[:<classifier>]]:<version>}, must not be {@code null}. 69 * @param properties The artifact properties, may be {@code null}. 70 */ 71 public DefaultArtifact( String coords, Map<String, String> properties ) 72 { 73 Pattern p = Pattern.compile( "([^: ]+):([^: ]+)(:([^: ]*)(:([^: ]+))?)?:([^: ]+)" ); 74 Matcher m = p.matcher( coords ); 75 if ( !m.matches() ) 76 { 77 throw new IllegalArgumentException( "Bad artifact coordinates " + coords 78 + ", expected format is <groupId>:<artifactId>[:<extension>[:<classifier>]]:<version>" ); 79 } 80 groupId = m.group( 1 ); 81 artifactId = m.group( 2 ); 82 extension = get( m.group( 4 ), "jar" ); 83 classifier = get( m.group( 6 ), "" ); 84 version = m.group( 7 ); 85 file = null; 86 this.properties = copyProperties( properties ); 87 } 88 89 private static String get( String value, String defaultValue ) 90 { 91 return ( value == null || value.length() <= 0 ) ? defaultValue : value; 92 } 93 94 /** 95 * Creates a new artifact with the specified coordinates and no classifier. Passing {@code null} for any of the 96 * coordinates is equivalent to specifying an empty string. 97 * 98 * @param groupId The group identifier of the artifact, may be {@code null}. 99 * @param artifactId The artifact identifier of the artifact, may be {@code null}. 100 * @param extension The file extension of the artifact, may be {@code null}. 101 * @param version The version of the artifact, may be {@code null}. 102 */ 103 public DefaultArtifact( String groupId, String artifactId, String extension, String version ) 104 { 105 this( groupId, artifactId, "", extension, version ); 106 } 107 108 /** 109 * Creates a new artifact with the specified coordinates. Passing {@code null} for any of the coordinates is 110 * equivalent to specifying an empty string. 111 * 112 * @param groupId The group identifier of the artifact, may be {@code null}. 113 * @param artifactId The artifact identifier of the artifact, may be {@code null}. 114 * @param classifier The classifier of the artifact, may be {@code null}. 115 * @param extension The file extension of the artifact, may be {@code null}. 116 * @param version The version of the artifact, may be {@code null}. 117 */ 118 public DefaultArtifact( String groupId, String artifactId, String classifier, String extension, String version ) 119 { 120 this( groupId, artifactId, classifier, extension, version, null, (File) null ); 121 } 122 123 /** 124 * Creates a new artifact with the specified coordinates. Passing {@code null} for any of the coordinates is 125 * equivalent to specifying an empty string. The optional artifact type provided to this constructor will be used to 126 * determine the artifact's classifier and file extension if the corresponding arguments for this constructor are 127 * {@code null}. 128 * 129 * @param groupId The group identifier of the artifact, may be {@code null}. 130 * @param artifactId The artifact identifier of the artifact, may be {@code null}. 131 * @param classifier The classifier of the artifact, may be {@code null}. 132 * @param extension The file extension of the artifact, may be {@code null}. 133 * @param version The version of the artifact, may be {@code null}. 134 * @param type The artifact type from which to query classifier, file extension and properties, may be {@code null}. 135 */ 136 public DefaultArtifact( String groupId, String artifactId, String classifier, String extension, String version, 137 ArtifactType type ) 138 { 139 this( groupId, artifactId, classifier, extension, version, null, type ); 140 } 141 142 /** 143 * Creates a new artifact with the specified coordinates and properties. Passing {@code null} for any of the 144 * coordinates is equivalent to specifying an empty string. The optional artifact type provided to this constructor 145 * will be used to determine the artifact's classifier and file extension if the corresponding arguments for this 146 * constructor are {@code null}. If the artifact type specifies properties, those will get merged with the 147 * properties passed directly into the constructor, with the latter properties taking precedence. 148 * 149 * @param groupId The group identifier of the artifact, may be {@code null}. 150 * @param artifactId The artifact identifier of the artifact, may be {@code null}. 151 * @param classifier The classifier of the artifact, may be {@code null}. 152 * @param extension The file extension of the artifact, may be {@code null}. 153 * @param version The version of the artifact, may be {@code null}. 154 * @param properties The properties of the artifact, may be {@code null} if none. 155 * @param type The artifact type from which to query classifier, file extension and properties, may be {@code null}. 156 */ 157 public DefaultArtifact( String groupId, String artifactId, String classifier, String extension, String version, 158 Map<String, String> properties, ArtifactType type ) 159 { 160 this.groupId = emptify( groupId ); 161 this.artifactId = emptify( artifactId ); 162 if ( classifier != null || type == null ) 163 { 164 this.classifier = emptify( classifier ); 165 } 166 else 167 { 168 this.classifier = emptify( type.getClassifier() ); 169 } 170 if ( extension != null || type == null ) 171 { 172 this.extension = emptify( extension ); 173 } 174 else 175 { 176 this.extension = emptify( type.getExtension() ); 177 } 178 this.version = emptify( version ); 179 this.file = null; 180 this.properties = merge( properties, ( type != null ) ? type.getProperties() : null ); 181 } 182 183 private static Map<String, String> merge( Map<String, String> dominant, Map<String, String> recessive ) 184 { 185 Map<String, String> properties; 186 187 if ( ( dominant == null || dominant.isEmpty() ) && ( recessive == null || recessive.isEmpty() ) ) 188 { 189 properties = Collections.emptyMap(); 190 } 191 else 192 { 193 properties = new HashMap<String, String>(); 194 if ( recessive != null ) 195 { 196 properties.putAll( recessive ); 197 } 198 if ( dominant != null ) 199 { 200 properties.putAll( dominant ); 201 } 202 properties = Collections.unmodifiableMap( properties ); 203 } 204 205 return properties; 206 } 207 208 /** 209 * Creates a new artifact with the specified coordinates, properties and file. Passing {@code null} for any of the 210 * coordinates is equivalent to specifying an empty string. 211 * 212 * @param groupId The group identifier of the artifact, may be {@code null}. 213 * @param artifactId The artifact identifier of the artifact, may be {@code null}. 214 * @param classifier The classifier of the artifact, may be {@code null}. 215 * @param extension The file extension of the artifact, may be {@code null}. 216 * @param version The version of the artifact, may be {@code null}. 217 * @param properties The properties of the artifact, may be {@code null} if none. 218 * @param file The resolved file of the artifact, may be {@code null}. 219 */ 220 public DefaultArtifact( String groupId, String artifactId, String classifier, String extension, String version, 221 Map<String, String> properties, File file ) 222 { 223 this.groupId = emptify( groupId ); 224 this.artifactId = emptify( artifactId ); 225 this.classifier = emptify( classifier ); 226 this.extension = emptify( extension ); 227 this.version = emptify( version ); 228 this.file = file; 229 this.properties = copyProperties( properties ); 230 } 231 232 DefaultArtifact( String groupId, String artifactId, String classifier, String extension, String version, File file, 233 Map<String, String> properties ) 234 { 235 // NOTE: This constructor assumes immutability of the provided properties, for internal use only 236 this.groupId = emptify( groupId ); 237 this.artifactId = emptify( artifactId ); 238 this.classifier = emptify( classifier ); 239 this.extension = emptify( extension ); 240 this.version = emptify( version ); 241 this.file = file; 242 this.properties = properties; 243 } 244 245 private static String emptify( String str ) 246 { 247 return ( str == null ) ? "" : str; 248 } 249 250 public String getGroupId() 251 { 252 return groupId; 253 } 254 255 public String getArtifactId() 256 { 257 return artifactId; 258 } 259 260 public String getVersion() 261 { 262 return version; 263 } 264 265 public String getClassifier() 266 { 267 return classifier; 268 } 269 270 public String getExtension() 271 { 272 return extension; 273 } 274 275 public File getFile() 276 { 277 return file; 278 } 279 280 public Map<String, String> getProperties() 281 { 282 return properties; 283 } 284 285 }