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.api.services;
20
21 import java.util.HashSet;
22 import java.util.List;
23 import java.util.Objects;
24
25 import org.apache.maven.api.RemoteRepository;
26 import org.apache.maven.api.Session;
27 import org.apache.maven.api.annotations.Experimental;
28 import org.apache.maven.api.annotations.Immutable;
29 import org.apache.maven.api.annotations.Nullable;
30
31 /**
32 * Base interface for service requests that involve remote repository operations.
33 * This interface provides common functionality for requests that need to specify
34 * and validate remote repositories for artifact resolution, dependency collection,
35 * model building, and other Maven operations.
36 *
37 * <p>Implementations of this interface can specify a list of remote repositories
38 * to be used during the operation. If no repositories are specified (null),
39 * the session's default remote repositories will be used. The repositories
40 * are validated to ensure they don't contain duplicates or null entries.
41 *
42 * <p>Remote repositories are used for:
43 * <ul>
44 * <li>Resolving artifacts and their metadata</li>
45 * <li>Downloading parent POMs and dependency POMs</li>
46 * <li>Retrieving version information and ranges</li>
47 * <li>Accessing plugin artifacts and their dependencies</li>
48 * </ul>
49 *
50 * <p>Repository validation ensures data integrity by:
51 * <ul>
52 * <li>Preventing duplicate repositories that could cause confusion</li>
53 * <li>Rejecting null repository entries that would cause failures</li>
54 * <li>Maintaining consistent repository ordering for reproducible builds</li>
55 * </ul>
56 *
57 * @since 4.0.0
58 * @see RemoteRepository
59 * @see Session#getRemoteRepositories()
60 */
61 @Experimental
62 @Immutable
63 public interface RepositoryAwareRequest extends Request<Session> {
64
65 /**
66 * Returns the list of remote repositories to be used for this request.
67 *
68 * <p>If this method returns {@code null}, the session's default remote repositories
69 * will be used. If a non-null list is returned, it will be used instead of the
70 * session's repositories, allowing for request-specific repository configuration.
71 *
72 * <p>The returned list should not contain duplicate repositories (based on their
73 * equality) or null entries, as these will cause validation failures when the
74 * request is processed.
75 *
76 * @return the list of remote repositories to use, or {@code null} to use session defaults
77 * @see Session#getRemoteRepositories()
78 */
79 @Nullable
80 List<RemoteRepository> getRepositories();
81
82 /**
83 * Validates a list of remote repositories to ensure data integrity.
84 *
85 * <p>This method performs the following validations:
86 * <ul>
87 * <li>Allows null input (returns null)</li>
88 * <li>Ensures no duplicate repositories exist in the list</li>
89 * <li>Ensures no null repository entries exist in the list</li>
90 * </ul>
91 *
92 * <p>Duplicate detection is based on the {@code RemoteRepository#equals(Object)}
93 * method, which typically compares repository IDs and URLs.
94 *
95 * @param repositories the list of repositories to validate, may be {@code null}
96 * @return the same list if validation passes, or {@code null} if input was {@code null}
97 * @throws IllegalArgumentException if the list contains duplicate repositories
98 * @throws IllegalArgumentException if the list contains null repository entries
99 */
100 default List<RemoteRepository> validate(List<RemoteRepository> repositories) {
101 if (repositories == null) {
102 return null;
103 }
104 HashSet<RemoteRepository> set = new HashSet<>(repositories);
105 if (repositories.size() != set.size()) {
106 throw new IllegalArgumentException(
107 "Repository list contains duplicate entries. Each repository must be unique based on its ID and URL. "
108 + "Found " + repositories.size() + " repositories but only " + set.size()
109 + " unique entries.");
110 }
111 if (repositories.stream().anyMatch(Objects::isNull)) {
112 throw new IllegalArgumentException(
113 "Repository list contains null entries. All repository entries must be non-null RemoteRepository instances.");
114 }
115 return repositories;
116 }
117 }