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