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 org.apache.maven.resolver.internal.ant.AntRepoSys;
22  import org.apache.tools.ant.BuildException;
23  import org.apache.tools.ant.Project;
24  import org.apache.tools.ant.types.DataType;
25  import org.apache.tools.ant.types.Reference;
26  
27  /**
28   * Defines a mirror repository configuration for use in Maven Ant tasks.
29   * <p>
30   * A mirror allows you to redirect requests for one or more remote repositories
31   * to a different repository URL. This is useful for using internal repositories,
32   * caching proxies (e.g., Nexus, Artifactory), or selectively replacing external repositories.
33   * </p>
34   *
35   * <p>
36   * This type can be used inline or as a referenced {@code <mirror>} data type
37   * elsewhere in the build. When included in an Ant project, the mirror will
38   * be registered with the {@link org.apache.maven.resolver.internal.ant.AntRepoSys}
39   * instance associated with the current project.
40   * </p>
41   *
42   * <h2>Attributes:</h2>
43   * <ul>
44   *   <li><strong>id</strong> — unique identifier for the mirror (optional)</li>
45   *   <li><strong>url</strong> — base URL of the mirror (required)</li>
46   *   <li><strong>mirrorOf</strong> — pattern matching the repositories to be mirrored (required)</li>
47   *   <li><strong>type</strong> — optional repository layout type (defaults to {@code "default"})</li>
48   * </ul>
49   *
50   * <h2>Nested Elements:</h2>
51   * <ul>
52   *   <li><strong>{@code <authentication>}</strong> — optional credentials for accessing the mirror</li>
53   * </ul>
54   *
55   * <h2>Usage Example:</h2>
56   * <pre>{@code
57   * <mirror id="company-mirror" url="https://repo.mycompany.com/maven2" mirrorOf="*" />
58   * }</pre>
59   *
60   * <h2>Notes:</h2>
61   * <ul>
62   *   <li>Only one {@code <authentication>} element is allowed per mirror</li>
63   *   <li>If this element is a reference ({@code refid}), attributes and nested elements are disallowed</li>
64   *   <li>This mirror will automatically be added to the {@code AntRepoSys} upon being assigned a project</li>
65   * </ul>
66   *
67   * @see #setProject(org.apache.tools.ant.Project)
68   * @see #setRefid(org.apache.tools.ant.types.Reference)
69   * @see #addAuthentication(Authentication)
70   * @see org.apache.maven.resolver.internal.ant.AntRepoSys
71   */
72  public class Mirror extends DataType {
73  
74      private String id;
75  
76      private String url;
77  
78      private String type;
79  
80      private String mirrorOf;
81  
82      private Authentication authentication;
83  
84      /**
85       * Default constructor used by Ant to create a {@code Mirror} instance.
86       * <p>
87       * This constructor is required for Ant to instantiate this type when defined inline
88       * or referenced in an Ant build script.
89       * </p>
90       */
91      public Mirror() {
92          // Default constructor for Ant task
93      }
94  
95      /**
96       * Sets the Ant project associated with this mirror.
97       * <p>
98       * In addition to associating the mirror with the current build context,
99       * this method registers the mirror with the {@link org.apache.maven.resolver.internal.ant.AntRepoSys}
100      * instance for the project. This allows the mirror to influence repository resolution globally.
101      * </p>
102      *
103      * @param project the Ant project
104      *
105      * @see org.apache.maven.resolver.internal.ant.AntRepoSys#addMirror(Mirror)
106      */
107     @Override
108     public void setProject(Project project) {
109         super.setProject(project);
110 
111         AntRepoSys.getInstance(project).addMirror(this);
112     }
113 
114     /**
115      * Resolves this object if defined as a reference and verifies that it is a
116      * {@code Mirror} instance.
117      *
118      * @return the referenced {@code Mirror} instance
119      * @throws org.apache.tools.ant.BuildException if the reference is invalid
120      *
121      * @see #setRefid(org.apache.tools.ant.types.Reference)
122      * @see #isReference()
123      */
124     protected Mirror getRef() {
125         return getCheckedRef(Mirror.class);
126     }
127 
128     @Override
129     public void setRefid(Reference ref) {
130         if (id != null || url != null || mirrorOf != null || type != null) {
131             throw tooManyAttributes();
132         }
133         super.setRefid(ref);
134     }
135 
136     /**
137      * Returns the identifier of this mirror.
138      * <p>
139      * The ID is typically used for identification and logging purposes. It does not affect
140      * repository resolution but may appear in debug output or reports to help distinguish mirrors.
141      * </p>
142      *
143      * <p>
144      * If this mirror is defined as a reference ({@code refid}), the ID is retrieved from
145      * the referenced {@code Mirror} instance.
146      * </p>
147      *
148      * @return the mirror ID, or {@code null} if not set
149      *
150      * @see #setId(String)
151      * @see #isReference()
152      */
153     public String getId() {
154         if (isReference()) {
155             return getRef().getId();
156         }
157         return id;
158     }
159 
160     /**
161      * Sets the identifier of the mirror.
162      * <p>
163      * The ID is optional and is primarily used for identification and logging purposes.
164      * It does not affect resolution behavior but can help distinguish multiple mirrors.
165      * </p>
166      *
167      * <p>
168      * This method must not be used if the mirror is defined via {@code refid}.
169      * </p>
170      *
171      * @param id the identifier for this mirror
172      *
173      * @see #getId()
174      */
175     public void setId(String id) {
176         this.id = id;
177     }
178 
179     /**
180      * Returns the URL of the mirror repository.
181      * <p>
182      * This is the base URL where artifacts will be downloaded from when a matched repository
183      * is redirected to this mirror. For example: {@code https://repo.example.org/mirror}.
184      * </p>
185      *
186      * <p>
187      * If this {@code Mirror} is defined as a reference ({@code refid}), the URL is resolved
188      * from the referenced {@code Mirror} instance.
189      * </p>
190      *
191      * @return the mirror repository URL, or {@code null} if not set
192      *
193      * @see #setUrl(String)
194      * @see #isReference()
195      */
196     public String getUrl() {
197         if (isReference()) {
198             return getRef().getUrl();
199         }
200         return url;
201     }
202 
203     /**
204      * Sets the base URL of the mirror repository.
205      * <p>
206      * This URL must be a valid repository root (e.g., {@code https://repo.example.com/maven2}).
207      * It is used to redirect requests from repositories matched by {@link #setMirrorOf(String)}.
208      * </p>
209      *
210      * <p>
211      * This method must not be used if the mirror is defined via {@code refid}.
212      * </p>
213      *
214      * @param url the URL of the mirror repository
215      *
216      * @throws org.apache.tools.ant.BuildException if this instance is a reference
217      *
218      * @see #getUrl()
219      */
220     public void setUrl(String url) {
221         checkAttributesAllowed();
222         this.url = url;
223     }
224 
225     /**
226      * Returns the layout type of the mirror repository.
227      * <p>
228      * If no type is explicitly set, this method returns {@code "default"},
229      * which is the standard Maven 2 layout.
230      * </p>
231      *
232      * <p>
233      * If this mirror is defined as a reference, the type is resolved from the referenced instance.
234      * </p>
235      *
236      * @return the repository layout type, or {@code "default"} if not specified
237      *
238      * @see #setType(String)
239      */
240     public String getType() {
241         if (isReference()) {
242             return getRef().getType();
243         }
244         return (type != null) ? type : "default";
245     }
246 
247     /**
248      * Sets the layout type of the mirror repository.
249      * <p>
250      * The default value is {@code "default"}, which corresponds to the standard Maven 2 layout.
251      * Other values are rarely used and typically not necessary unless working with
252      * custom or legacy repository formats.
253      * </p>
254      *
255      * <p>
256      * This method must not be called if this mirror is defined via {@code refid}.
257      * </p>
258      *
259      * @param type the layout type of the mirror repository
260      *
261      * @throws org.apache.tools.ant.BuildException if this instance is a reference
262      *
263      * @see #getType()
264      */
265     public void setType(String type) {
266         checkAttributesAllowed();
267         this.type = type;
268     }
269 
270     /**
271      * Returns the repository pattern that this mirror applies to.
272      * <p>
273      * The value is typically a pattern or comma-separated list of repository IDs,
274      * such as {@code *}, {@code external:*}, or {@code central,!snapshots}.
275      * It determines which repositories should be redirected to this mirror.
276      * </p>
277      *
278      * <p>
279      * If this {@code Mirror} is defined as a reference ({@code refid}),
280      * the value is retrieved from the referenced instance.
281      * </p>
282      *
283      * @return the {@code mirrorOf} pattern, or {@code null} if not set
284      *
285      * @see #setMirrorOf(String)
286      * @see #isReference()
287      */
288     public String getMirrorOf() {
289         if (isReference()) {
290             return getRef().getMirrorOf();
291         }
292         return mirrorOf;
293     }
294 
295     /**
296      * Specifies the repository IDs that this mirror should apply to.
297      * <p>
298      * The value can be a single repository ID, a comma-separated list,
299      * or a pattern (e.g., {@code *}, {@code external:*}, {@code central,!snapshots}).
300      * </p>
301      *
302      * <p>
303      * This value is required unless set via a reference. If this {@code Mirror}
304      * is defined as a reference, this method must not be called.
305      * </p>
306      *
307      * @param mirrorOf a pattern or list of repository IDs to be mirrored
308      *
309      * @throws org.apache.tools.ant.BuildException if this instance is a reference
310      *
311      * @see #getMirrorOf()
312      */
313     public void setMirrorOf(String mirrorOf) {
314         checkAttributesAllowed();
315         this.mirrorOf = mirrorOf;
316     }
317 
318     /**
319      * Adds an {@code <authentication>} element to the mirror.
320      * <p>
321      * This is used to configure credentials for accessing the mirrored repository.
322      * Only one {@code <authentication>} child is allowed. Attempting to add multiple
323      * will result in a {@link BuildException}.
324      * </p>
325      *
326      * <p>
327      * This method must not be used if the mirror is defined via {@code refid}.
328      * </p>
329      *
330      * @param authentication the {@link Authentication} object to associate with this mirror
331      *
332      * @throws org.apache.tools.ant.BuildException if an authentication has already been set,
333      *         or if this instance is a reference
334      *
335      * @see #getAuthentication()
336      */
337     public void addAuthentication(Authentication authentication) {
338         checkChildrenAllowed();
339         if (this.authentication != null) {
340             throw new BuildException("You must not specify multiple <authentication> elements");
341         }
342         this.authentication = authentication;
343     }
344 
345     /**
346      * Returns the authentication configuration for this mirror, if any.
347      * <p>
348      * If this {@code Mirror} is defined as a reference, the authentication
349      * is resolved from the referenced instance.
350      * </p>
351      *
352      * @return the associated {@link Authentication} or {@code null} if none
353      */
354     public Authentication getAuthentication() {
355         if (isReference()) {
356             return getRef().getAuthentication();
357         }
358         return authentication;
359     }
360 
361     /**
362      * Sets a reference to a previously defined {@code <authentication>} element.
363      * <p>
364      * This allows the mirror to reuse shared credentials declared elsewhere in the build script.
365      * If no authentication object exists yet, one is created automatically.
366      * </p>
367      *
368      * @param ref a reference to an {@link Authentication} instance
369      */
370     public void setAuthRef(Reference ref) {
371         if (authentication == null) {
372             authentication = new Authentication();
373             authentication.setProject(getProject());
374         }
375         authentication.setRefid(ref);
376     }
377 }