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