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 }