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