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  
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 }