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.tasks;
20  
21  import java.io.File;
22  import java.util.HashMap;
23  import java.util.Map;
24  
25  import org.apache.maven.model.Model;
26  import org.apache.maven.resolver.internal.ant.AntRepoSys;
27  import org.apache.maven.resolver.internal.ant.types.Artifact;
28  import org.apache.maven.resolver.internal.ant.types.Artifacts;
29  import org.apache.maven.resolver.internal.ant.types.Pom;
30  import org.apache.tools.ant.BuildException;
31  import org.apache.tools.ant.Project;
32  import org.apache.tools.ant.Task;
33  import org.apache.tools.ant.types.Reference;
34  
35  /**
36   * Abstract base class for Ant tasks that perform distribution-related operations,
37   * such as install or deploy. It handles the configuration and validation of POM and artifact inputs.
38   * <p>
39   * Subclasses are expected to use {@link #validate()} to ensure input consistency
40   * before proceeding with distribution logic.
41   *
42   * <p>This class ensures:
43   * <ul>
44   *   <li>Only one {@code <pom>} element is specified</li>
45   *   <li>No duplicate artifacts with the same type/classifier are declared</li>
46   *   <li>Artifact GAVs (groupId:artifactId:version) match their associated POM</li>
47   * </ul>
48   *
49   */
50  public abstract class AbstractDistTask extends Task {
51  
52      /**
53       * Default constructor for {@code AbstractDistTask}.
54       */
55      public AbstractDistTask() {
56          // Default constructor
57      }
58  
59      /**
60       * The POM metadata describing the project and its coordinates.
61       */
62      private Pom pom;
63  
64      /**
65       * The artifacts to be distributed.
66       */
67      private Artifacts artifacts;
68  
69      /**
70       * Validates the configuration of the task before execution.
71       * Ensures there are no duplicate artifacts, that the POM is defined,
72       * and that each artifact's associated POM matches the main POM.
73       *
74       * @throws BuildException if validation fails
75       */
76      protected void validate() {
77          getArtifacts().validate(this);
78  
79          final Map<String, File> duplicates = new HashMap<>();
80          for (final Artifact artifact : getArtifacts().getArtifacts()) {
81              final String key = artifact.getType() + ':' + artifact.getClassifier();
82              if ("pom:".equals(key)) {
83                  throw new BuildException(
84                          "You must not specify an <artifact> with type=pom" + ", please use the <pom> element instead.");
85              } else if (duplicates.containsKey(key)) {
86                  throw new BuildException("You must not specify two or more artifacts with the same type ("
87                          + artifact.getType() + ") and classifier (" + artifact.getClassifier() + ")");
88              } else {
89                  duplicates.put(key, artifact.getFile());
90              }
91  
92              validateArtifactGav(artifact);
93          }
94  
95          final Pom defaultPom = AntRepoSys.getInstance(getProject()).getDefaultPom();
96          if (pom == null && defaultPom != null) {
97              log("Using default POM (" + defaultPom.getCoords() + ")", Project.MSG_INFO);
98              pom = defaultPom;
99          }
100 
101         if (pom == null) {
102             throw new BuildException(
103                     "You must specify the <pom file=\"...\"> element" + " to denote the descriptor for the artifacts");
104         }
105         if (pom.getFile() == null) {
106             throw new BuildException("You must specify a <pom> element that has the 'file' attribute set");
107         }
108     }
109 
110     /**
111      * Validates that an artifact's groupId, artifactId, and version (GAV) match the main POM's GAV.
112      *
113      * @param artifact the artifact to validate
114      * @throws BuildException if the artifact's GAV does not match the main POM
115      */
116     private void validateArtifactGav(final Artifact artifact) {
117         final Pom artifactPom = artifact.getPom();
118         if (artifactPom != null) {
119             final String gid;
120             final String aid;
121             final String version;
122             if (artifactPom.getFile() != null) {
123                 final Model model = artifactPom.getModel(this);
124                 gid = model.getGroupId();
125                 aid = model.getArtifactId();
126                 version = model.getVersion();
127             } else {
128                 gid = artifactPom.getGroupId();
129                 aid = artifactPom.getArtifactId();
130                 version = artifactPom.getVersion();
131             }
132 
133             final Model model = getPom().getModel(this);
134 
135             if (!(model.getGroupId().equals(gid)
136                     && model.getArtifactId().equals(aid)
137                     && model.getVersion().equals(version))) {
138                 throw new BuildException(
139                         "Artifact references different pom than it would be installed with: " + artifact.toString());
140             }
141         }
142     }
143 
144     /**
145      * Returns the {@link Artifacts} container, lazily instantiating if necessary.
146      *
147      * @return the artifact container
148      */
149     protected Artifacts getArtifacts() {
150         if (artifacts == null) {
151             artifacts = new Artifacts();
152             artifacts.setProject(getProject());
153         }
154         return artifacts;
155     }
156 
157     /**
158      * Adds a single {@link Artifact} to the task.
159      *
160      * @param artifact the artifact to add
161      */
162     public void addArtifact(final Artifact artifact) {
163         getArtifacts().addArtifact(artifact);
164     }
165 
166     /**
167      * Adds multiple {@link Artifacts} to the task.
168      *
169      * @param artifacts the artifacts to add
170      */
171     public void addArtifacts(final Artifacts artifacts) {
172         getArtifacts().addArtifacts(artifacts);
173     }
174 
175     /**
176      * Adds a reference to an existing {@link Artifacts} instance.
177      *
178      * @param ref the reference to use
179      */
180     public void setArtifactsRef(final Reference ref) {
181         final Artifacts artifacts = new Artifacts();
182         artifacts.setProject(getProject());
183         artifacts.setRefid(ref);
184         getArtifacts().addArtifacts(artifacts);
185     }
186 
187     /**
188      * Returns the current POM, falling back to the default POM if none has been explicitly set.
189      *
190      * @return the resolved {@link Pom}
191      */
192     protected Pom getPom() {
193         if (pom == null) {
194             return AntRepoSys.getInstance(getProject()).getDefaultPom();
195         }
196 
197         return pom;
198     }
199 
200     /**
201      * Add the POM to use for artifact deployment or installation.
202      *
203      * @param pom the POM to use
204      * @throws BuildException if multiple {@code <pom>} elements are specified
205      */
206     public void addPom(final Pom pom) {
207         if (this.pom != null) {
208             throw new BuildException("You must not specify multiple <pom> elements");
209         }
210         this.pom = pom;
211     }
212 
213     /**
214      * Sets a reference to an existing {@link Pom}.
215      *
216      * @param ref the reference to set
217      * @throws BuildException if multiple {@code <pom>} elements are specified
218      */
219     public void setPomRef(final Reference ref) {
220         if (this.pom != null) {
221             throw new BuildException("You must not specify multiple <pom> elements");
222         }
223         pom = new Pom();
224         pom.setProject(getProject());
225         pom.setRefid(ref);
226     }
227 }