1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19 package org.apache.maven.resolver.internal.ant.types;
20
21 import java.io.File;
22 import java.util.Collections;
23 import java.util.List;
24
25 import org.apache.maven.resolver.internal.ant.ProjectWorkspaceReader;
26 import org.apache.maven.resolver.internal.ant.tasks.RefTask;
27 import org.apache.tools.ant.BuildException;
28 import org.apache.tools.ant.Task;
29 import org.apache.tools.ant.types.Reference;
30
31 /**
32 * Represents a Maven artifact in an Ant build script.
33 * <p>
34 * This type encapsulates the essential coordinates of a Maven artifact — such as
35 * {@code groupId}, {@code artifactId}, {@code version}, {@code packaging}, and optional {@code classifier} —
36 * along with the actual artifact file to be installed or deployed.
37 * </p>
38 *
39 * <p>
40 * {@code <artifact>} elements are typically used as nested elements inside
41 * {@link org.apache.maven.resolver.internal.ant.tasks.Install Install} or
42 * {@link org.apache.maven.resolver.internal.ant.tasks.Deploy Deploy} tasks.
43 * </p>
44 *
45 * <h2>Usage Example:</h2>
46 * <pre>{@code
47 * <repo:install>
48 * <repo:artifact
49 * file="build/libs/my-lib-1.0.0.jar"
50 * groupId="com.example"
51 * artifactId="my-lib"
52 * version="1.0.0"
53 * packaging="jar"/>
54 * </repo:install>
55 * }</pre>
56 * Alternatively, you can register the artifact after it is created by the jar task and then
57 * just refer to it, e.g.:
58 * <pre>{@code
59 * <target name='jar' depends='compile'>
60 * <property name='jarFile' value='${targetDir}/${artifactId}-${version}.jar'/>
61 * <jar destfile='${jarFile}'>
62 * <fileset dir='${mainBuildDir}'/>
63 * </jar>
64 * <repo:artifact file='${jarFile}' type='jar' id='mainJar'/>
65 * </target>
66 *
67 * <target name='install' depends='jar'>
68 * <repo:artifacts id='localArtifacts'>
69 * <repo:artifact refid='mainJar'/>
70 * </repo:artifacts>
71 * <repo:install artifactsref='localArtifacts'/>
72 * </target>
73 * }</pre>
74 * <h2>Attributes:</h2>
75 * <ul>
76 * <li><strong>id</strong> — the refId to use when referring to it, e.g., when combining several <code>artifact</code> with the <code>artifacts</code> tag
77 * <li><strong>file</strong> — the actual artifact file to install or deploy (required)</li>
78 * <li><strong>groupId</strong> — the Maven groupId of the artifact</li>
79 * <li><strong>artifactId</strong> — the Maven artifactId</li>
80 * <li><strong>version</strong> — the artifact version</li>
81 * <li><strong>packaging</strong> — the type/extension of the artifact (e.g., {@code jar}, {@code pom}) (required)</li>
82 * <li><strong>classifier</strong> — optional classifier (e.g., {@code sources}, {@code javadoc})</li>
83 * </ul>
84 *
85 * <h2>Typical Use Cases:</h2>
86 * <ul>
87 * <li>Publishing pre-built artifacts from Ant to a Maven repository</li>
88 * <li>Installing locally built binaries into the local Maven repository</li>
89 * <li>Providing coordinates for deployment without a POM</li>
90 * </ul>
91 *
92 * @see org.apache.maven.resolver.internal.ant.tasks.Install
93 * @see org.apache.maven.resolver.internal.ant.tasks.Deploy
94 */
95 public class Artifact extends RefTask implements ArtifactContainer {
96
97 private File file;
98
99 private String type;
100
101 private String classifier;
102
103 private Pom pom;
104
105 /**
106 * Default constructor for the {@code Artifact} data type.
107 */
108 public Artifact() {
109 // Default constructor
110 }
111
112 /**
113 * Resolves this object if defined as a reference and verifies that it is a
114 * {@code Artifact} instance.
115 *
116 * @return the referenced {@code Artifact} instance
117 * @throws org.apache.tools.ant.BuildException if the reference is invalid
118 */
119 protected Artifact getRef() {
120 return (Artifact) getCheckedRef();
121 }
122
123 /**
124 * Validates that all required attributes are present and that the file exists.
125 *
126 * @param task the Ant task that owns this data type (used for context in error messages)
127 * @throws BuildException if required attributes are missing or invalid
128 */
129 @Override
130 public void validate(final Task task) {
131 if (isReference()) {
132 getRef().validate(task);
133 } else {
134 if (file == null) {
135 throw new BuildException("You must specify the 'file' for the artifact");
136 } else if (!file.isFile()) {
137 throw new BuildException("The artifact file " + file + " does not exist");
138 }
139 if (type == null || type.length() <= 0) {
140 throw new BuildException("You must specify the 'type' for the artifact");
141 }
142 }
143 }
144
145 /**
146 * Sets a reference to another {@code Artifact} instance.
147 *
148 * @param ref the reference ID
149 * @throws BuildException if conflicting attributes are already set
150 */
151 @Override
152 public void setRefid(final Reference ref) {
153 if (file != null || type != null || classifier != null) {
154 throw tooManyAttributes();
155 }
156 super.setRefid(ref);
157 }
158
159 /**
160 * Returns the artifact file.
161 *
162 * @return the artifact file
163 */
164 public File getFile() {
165 if (isReference()) {
166 return getRef().getFile();
167 }
168 return file;
169 }
170
171 /**
172 * Sets the artifact file to be deployed or installed.
173 *
174 * @param file the artifact file
175 */
176 public void setFile(final File file) {
177 checkAttributesAllowed();
178 this.file = file;
179
180 if (file != null && type == null) {
181 final String name = file.getName();
182 final int period = name.lastIndexOf('.');
183 if (period >= 0) {
184 type = name.substring(period + 1);
185 }
186 }
187 }
188
189 /**
190 * Returns the type/packaging of the artifact (e.g., {@code jar}, {@code pom}).
191 *
192 * @return the artifact type
193 */
194 public String getType() {
195 if (isReference()) {
196 return getRef().getType();
197 }
198 return (type != null) ? type : "jar";
199 }
200
201 /**
202 * Sets the artifact's packaging or type (e.g., {@code jar}, {@code pom}).
203 *
204 * @param type the artifact type
205 */
206 public void setType(final String type) {
207 checkAttributesAllowed();
208 this.type = type;
209 }
210
211 /**
212 * Returns the optional classifier of the artifact (e.g., {@code sources}, {@code javadoc}).
213 *
214 * @return the classifier or an empty string if not set
215 */
216 public String getClassifier() {
217 if (isReference()) {
218 return getRef().getClassifier();
219 }
220 return (classifier != null) ? classifier : "";
221 }
222
223 /**
224 * Sets the optional classifier for the artifact.
225 *
226 * @param classifier the classifier
227 */
228 public void setClassifier(final String classifier) {
229 checkAttributesAllowed();
230 this.classifier = classifier;
231 }
232
233 /**
234 * Sets a reference to a {@link Pom} element to associate with this artifact.
235 *
236 * @param ref the reference to the POM
237 */
238 public void setPomRef(final Reference ref) {
239 checkAttributesAllowed();
240 final Pom pom = new Pom();
241 pom.setProject(getProject());
242 pom.setRefid(ref);
243 this.pom = pom;
244 }
245
246 /**
247 * Adds a nested {@link Pom} element to associate with this artifact.
248 *
249 * @param pom the POM object
250 */
251 public void addPom(final Pom pom) {
252 checkChildrenAllowed();
253 this.pom = pom;
254 }
255
256 /**
257 * Returns the associated POM for this artifact, if any.
258 *
259 * @return the POM object, or {@code null} if none is set
260 */
261 public Pom getPom() {
262 if (isReference()) {
263 return getRef().getPom();
264 }
265 return pom;
266 }
267
268 /**
269 * Returns a list containing this single artifact.
270 *
271 * @return a singleton list with this artifact
272 */
273 @Override
274 public List<Artifact> getArtifacts() {
275 return Collections.singletonList(this);
276 }
277
278 /**
279 * Registers this artifact in the {@link ProjectWorkspaceReader} for internal resolution.
280 */
281 @Override
282 public void execute() throws BuildException {
283 ProjectWorkspaceReader.getInstance().addArtifact(this);
284 }
285
286 /**
287 * Returns a string representation of the artifact, showing its type and classifier.
288 *
289 * @return a human-readable string describing the artifact
290 */
291 @Override
292 public String toString() {
293 final String pomRepr = getPom() != null ? "(" + getPom().toString() + ":)" : "";
294 return String.format(pomRepr + "%s:%s", getType(), getClassifier());
295 }
296 }