1 package org.eclipse.aether.util.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.Map;
24 import java.util.Objects;
25
26 import static java.util.Objects.requireNonNull;
27
28 import org.eclipse.aether.artifact.AbstractArtifact;
29 import org.eclipse.aether.artifact.Artifact;
30
31 /**
32 * An artifact whose identity is derived from another artifact. <em>Note:</em> Instances of this class are immutable and
33 * the exposed mutators return new objects rather than changing the current instance.
34 */
35 public final class SubArtifact
36 extends AbstractArtifact
37 {
38
39 private final Artifact mainArtifact;
40
41 private final String classifier;
42
43 private final String extension;
44
45 private final File file;
46
47 private final Map<String, String> properties;
48
49 /**
50 * Creates a new sub artifact. The classifier and extension specified for this artifact may use the asterisk
51 * character "*" to refer to the corresponding property of the main artifact. For instance, the classifier
52 * "*-sources" can be used to refer to the source attachment of an artifact. Likewise, the extension "*.asc" can be
53 * used to refer to the GPG signature of an artifact.
54 *
55 * @param mainArtifact The artifact from which to derive the identity, must not be {@code null}.
56 * @param classifier The classifier for this artifact, may be {@code null} if none.
57 * @param extension The extension for this artifact, may be {@code null} if none.
58 */
59 public SubArtifact( Artifact mainArtifact, String classifier, String extension )
60 {
61 this( mainArtifact, classifier, extension, (File) null );
62 }
63
64 /**
65 * Creates a new sub artifact. The classifier and extension specified for this artifact may use the asterisk
66 * character "*" to refer to the corresponding property of the main artifact. For instance, the classifier
67 * "*-sources" can be used to refer to the source attachment of an artifact. Likewise, the extension "*.asc" can be
68 * used to refer to the GPG signature of an artifact.
69 *
70 * @param mainArtifact The artifact from which to derive the identity, must not be {@code null}.
71 * @param classifier The classifier for this artifact, may be {@code null} if none.
72 * @param extension The extension for this artifact, may be {@code null} if none.
73 * @param file The file for this artifact, may be {@code null} if unresolved.
74 */
75 public SubArtifact( Artifact mainArtifact, String classifier, String extension, File file )
76 {
77 this( mainArtifact, classifier, extension, null, file );
78 }
79
80 /**
81 * Creates a new sub artifact. The classifier and extension specified for this artifact may use the asterisk
82 * character "*" to refer to the corresponding property of the main artifact. For instance, the classifier
83 * "*-sources" can be used to refer to the source attachment of an artifact. Likewise, the extension "*.asc" can be
84 * used to refer to the GPG signature of an artifact.
85 *
86 * @param mainArtifact The artifact from which to derive the identity, must not be {@code null}.
87 * @param classifier The classifier for this artifact, may be {@code null} if none.
88 * @param extension The extension for this artifact, may be {@code null} if none.
89 * @param properties The properties of the artifact, may be {@code null}.
90 */
91 public SubArtifact( Artifact mainArtifact, String classifier, String extension, Map<String, String> properties )
92 {
93 this( mainArtifact, classifier, extension, properties, null );
94 }
95
96 /**
97 * Creates a new sub artifact. The classifier and extension specified for this artifact may use the asterisk
98 * character "*" to refer to the corresponding property of the main artifact. For instance, the classifier
99 * "*-sources" can be used to refer to the source attachment of an artifact. Likewise, the extension "*.asc" can be
100 * used to refer to the GPG signature of an artifact.
101 *
102 * @param mainArtifact The artifact from which to derive the identity, must not be {@code null}.
103 * @param classifier The classifier for this artifact, may be {@code null} if none.
104 * @param extension The extension for this artifact, may be {@code null} if none.
105 * @param properties The properties of the artifact, may be {@code null}.
106 * @param file The file for this artifact, may be {@code null} if unresolved.
107 */
108 public SubArtifact( Artifact mainArtifact, String classifier, String extension, Map<String, String> properties,
109 File file )
110 {
111 this.mainArtifact = requireNonNull( mainArtifact, "main artifact cannot be null" );
112 this.classifier = classifier;
113 this.extension = extension;
114 this.file = file;
115 this.properties = copyProperties( properties );
116 }
117
118 private SubArtifact( Artifact mainArtifact, String classifier, String extension, File file,
119 Map<String, String> properties )
120 {
121 // NOTE: This constructor assumes immutability of the provided properties, for internal use only
122 this.mainArtifact = mainArtifact;
123 this.classifier = classifier;
124 this.extension = extension;
125 this.file = file;
126 this.properties = properties;
127 }
128
129 public String getGroupId()
130 {
131 return mainArtifact.getGroupId();
132 }
133
134 public String getArtifactId()
135 {
136 return mainArtifact.getArtifactId();
137 }
138
139 public String getVersion()
140 {
141 return mainArtifact.getVersion();
142 }
143
144 public String getBaseVersion()
145 {
146 return mainArtifact.getBaseVersion();
147 }
148
149 public boolean isSnapshot()
150 {
151 return mainArtifact.isSnapshot();
152 }
153
154 public String getClassifier()
155 {
156 return expand( classifier, mainArtifact.getClassifier() );
157 }
158
159 public String getExtension()
160 {
161 return expand( extension, mainArtifact.getExtension() );
162 }
163
164 public File getFile()
165 {
166 return file;
167 }
168
169 public Artifact setFile( File file )
170 {
171 if ( Objects.equals( this.file, file ) )
172 {
173 return this;
174 }
175 return new SubArtifact( mainArtifact, classifier, extension, file, properties );
176 }
177
178 public Map<String, String> getProperties()
179 {
180 return properties;
181 }
182
183 public Artifact setProperties( Map<String, String> properties )
184 {
185 if ( this.properties.equals( properties ) || ( properties == null && this.properties.isEmpty() ) )
186 {
187 return this;
188 }
189 return new SubArtifact( mainArtifact, classifier, extension, properties, file );
190 }
191
192 private static String expand( String pattern, String replacement )
193 {
194 String result = "";
195 if ( pattern != null )
196 {
197 result = pattern.replace( "*", replacement );
198
199 if ( replacement.isEmpty() )
200 {
201 if ( pattern.startsWith( "*" ) )
202 {
203 int i = 0;
204 for ( ; i < result.length(); i++ )
205 {
206 char c = result.charAt( i );
207 if ( c != '-' && c != '.' )
208 {
209 break;
210 }
211 }
212 result = result.substring( i );
213 }
214 if ( pattern.endsWith( "*" ) )
215 {
216 int i = result.length() - 1;
217 for ( ; i >= 0; i-- )
218 {
219 char c = result.charAt( i );
220 if ( c != '-' && c != '.' )
221 {
222 break;
223 }
224 }
225 result = result.substring( 0, i + 1 );
226 }
227 }
228 }
229 return result;
230 }
231
232 }