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 }