1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.plugin.prefix.internal;
20
21 import java.io.IOException;
22 import java.util.ArrayList;
23 import java.util.Collection;
24 import java.util.Collections;
25 import java.util.LinkedHashMap;
26 import java.util.LinkedHashSet;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Set;
30 import java.util.stream.Collectors;
31 import java.util.stream.Stream;
32
33 import org.apache.maven.artifact.repository.metadata.Metadata;
34 import org.apache.maven.artifact.repository.metadata.io.MetadataReader;
35 import org.apache.maven.model.Build;
36 import org.apache.maven.model.Model;
37 import org.apache.maven.model.Plugin;
38 import org.apache.maven.model.PluginManagement;
39 import org.apache.maven.plugin.BuildPluginManager;
40 import org.apache.maven.plugin.descriptor.PluginDescriptor;
41 import org.apache.maven.plugin.prefix.NoPluginFoundForPrefixException;
42 import org.apache.maven.plugin.prefix.PluginPrefixRequest;
43 import org.apache.maven.plugin.prefix.PluginPrefixResolver;
44 import org.apache.maven.plugin.prefix.PluginPrefixResult;
45 import org.codehaus.plexus.component.annotations.Component;
46 import org.codehaus.plexus.component.annotations.Requirement;
47 import org.codehaus.plexus.logging.Logger;
48 import org.eclipse.aether.DefaultRepositorySystemSession;
49 import org.eclipse.aether.RepositoryEvent;
50 import org.eclipse.aether.RepositoryEvent.EventType;
51 import org.eclipse.aether.RepositoryListener;
52 import org.eclipse.aether.RepositorySystem;
53 import org.eclipse.aether.RepositorySystemSession;
54 import org.eclipse.aether.RequestTrace;
55 import org.eclipse.aether.metadata.DefaultMetadata;
56 import org.eclipse.aether.repository.ArtifactRepository;
57 import org.eclipse.aether.repository.RemoteRepository;
58 import org.eclipse.aether.repository.RepositoryPolicy;
59 import org.eclipse.aether.resolution.MetadataRequest;
60 import org.eclipse.aether.resolution.MetadataResult;
61
62
63
64
65
66
67
68 @Component(role = PluginPrefixResolver.class)
69 public class DefaultPluginPrefixResolver implements PluginPrefixResolver {
70
71 private static final String REPOSITORY_CONTEXT = "plugin";
72
73 @Requirement
74 private Logger logger;
75
76 @Requirement
77 private BuildPluginManager pluginManager;
78
79 @Requirement
80 private RepositorySystem repositorySystem;
81
82 @Requirement
83 private MetadataReader metadataReader;
84
85 public PluginPrefixResult resolve(PluginPrefixRequest request) throws NoPluginFoundForPrefixException {
86 logger.debug("Resolving plugin prefix " + request.getPrefix() + " from " + request.getPluginGroups());
87
88 Model pom = request.getPom();
89 Build build = pom != null ? pom.getBuild() : null;
90 PluginManagement management = build != null ? build.getPluginManagement() : null;
91
92
93
94
95
96
97
98
99 LinkedHashMap<String, Set<String>> candidates = Stream.of(build, management)
100 .flatMap(container -> container != null ? container.getPlugins().stream() : Stream.empty())
101 .filter(p -> !request.getPluginGroups().contains(p.getGroupId()))
102 .collect(Collectors.groupingBy(
103 Plugin::getGroupId,
104 LinkedHashMap::new,
105 Collectors.mapping(Plugin::getArtifactId, Collectors.toSet())));
106 request.getPluginGroups().forEach(g -> candidates.put(g, null));
107 PluginPrefixResult result = null;
108
109
110 if (build != null) {
111 result = resolveFromProject(
112 request,
113 build.getPlugins(),
114 management != null ? management.getPlugins() : Collections.emptyList());
115 }
116
117
118
119 if (result == null) {
120 result = resolveFromRepository(request, candidates);
121 }
122
123 if (result == null) {
124 throw new NoPluginFoundForPrefixException(
125 request.getPrefix(),
126 new ArrayList<>(candidates.keySet()),
127 request.getRepositorySession().getLocalRepository(),
128 request.getRepositories());
129 } else {
130 logger.debug("Resolved plugin prefix " + request.getPrefix() + " to " + result.getGroupId() + ":"
131 + result.getArtifactId() + " from repository "
132 + (result.getRepository() != null ? result.getRepository().getId() : "null"));
133 }
134
135 return result;
136 }
137
138 private PluginPrefixResult resolveFromProject(
139 PluginPrefixRequest request, List<Plugin> plugins, List<Plugin> pluginMgmt) {
140 if (plugins.isEmpty() && pluginMgmt.isEmpty()) {
141 return null;
142 }
143 PluginPrefixResult result = null;
144
145 Set<Plugin> candidates = new LinkedHashSet<>();
146 Stream.concat(plugins.stream(), pluginMgmt.stream())
147 .filter(p -> p.getArtifactId().contains(request.getPrefix()))
148 .forEach(candidates::add);
149 if (!candidates.isEmpty()) {
150 result = doResolveFromProject(request, candidates);
151 }
152
153 if (result == null) {
154 Set<Plugin> remainder = new LinkedHashSet<>(plugins);
155 remainder.removeAll(candidates);
156 result = doResolveFromProject(request, remainder);
157 }
158 return result;
159 }
160
161 private PluginPrefixResult doResolveFromProject(PluginPrefixRequest request, Collection<Plugin> plugins) {
162 for (Plugin plugin : plugins) {
163 try {
164 PluginDescriptor pluginDescriptor =
165 pluginManager.loadPlugin(plugin, request.getRepositories(), request.getRepositorySession());
166
167 if (request.getPrefix().equals(pluginDescriptor.getGoalPrefix())) {
168 return new DefaultPluginPrefixResult(plugin);
169 }
170 } catch (Exception e) {
171 if (logger.isDebugEnabled()) {
172 logger.warn(
173 "Failed to retrieve plugin descriptor for " + plugin.getId() + ": " + e.getMessage(), e);
174 } else {
175 logger.warn("Failed to retrieve plugin descriptor for " + plugin.getId() + ": " + e.getMessage());
176 }
177 }
178 }
179
180 return null;
181 }
182
183 private PluginPrefixResult resolveFromRepository(
184 PluginPrefixRequest request, LinkedHashMap<String, Set<String>> candidates) {
185 RequestTrace trace = RequestTrace.newChild(null, request);
186
187 List<MetadataRequest> requests = new ArrayList<>();
188
189 for (String pluginGroup : candidates.keySet()) {
190 org.eclipse.aether.metadata.Metadata metadata =
191 new DefaultMetadata(pluginGroup, "maven-metadata.xml", DefaultMetadata.Nature.RELEASE_OR_SNAPSHOT);
192
193 requests.add(new MetadataRequest(metadata, null, REPOSITORY_CONTEXT).setTrace(trace));
194
195 for (RemoteRepository repository : request.getRepositories()) {
196 requests.add(new MetadataRequest(metadata, repository, REPOSITORY_CONTEXT).setTrace(trace));
197 }
198 }
199
200
201
202 List<MetadataResult> results = repositorySystem.resolveMetadata(request.getRepositorySession(), requests);
203 requests.clear();
204
205 PluginPrefixResult result = processResults(request, trace, results, requests, candidates);
206
207 if (result != null) {
208 return result;
209 }
210
211
212
213 if (!request.getRepositorySession().isOffline() && !requests.isEmpty()) {
214 DefaultRepositorySystemSession session = new DefaultRepositorySystemSession(request.getRepositorySession());
215 session.setUpdatePolicy(RepositoryPolicy.UPDATE_POLICY_ALWAYS);
216
217 results = repositorySystem.resolveMetadata(session, requests);
218
219 return processResults(request, trace, results, null, candidates);
220 }
221
222 return null;
223 }
224
225 private PluginPrefixResult processResults(
226 PluginPrefixRequest request,
227 RequestTrace trace,
228 List<MetadataResult> results,
229 List<MetadataRequest> requests,
230 LinkedHashMap<String, Set<String>> candidates) {
231 for (MetadataResult res : results) {
232 org.eclipse.aether.metadata.Metadata metadata = res.getMetadata();
233
234 if (metadata != null) {
235 ArtifactRepository repository = res.getRequest().getRepository();
236 if (repository == null) {
237 repository = request.getRepositorySession().getLocalRepository();
238 }
239
240 PluginPrefixResult result =
241 resolveFromRepository(request, trace, metadata.getGroupId(), metadata, repository, candidates);
242
243 if (result != null) {
244 return result;
245 }
246 }
247
248 if (requests != null && !res.isUpdated()) {
249 requests.add(res.getRequest());
250 }
251 }
252
253 return null;
254 }
255
256 private PluginPrefixResult resolveFromRepository(
257 PluginPrefixRequest request,
258 RequestTrace trace,
259 String pluginGroup,
260 org.eclipse.aether.metadata.Metadata metadata,
261 ArtifactRepository repository,
262 LinkedHashMap<String, Set<String>> candidates) {
263 if (metadata != null && metadata.getFile() != null && metadata.getFile().isFile()) {
264 try {
265 Map<String, ?> options = Collections.singletonMap(MetadataReader.IS_STRICT, Boolean.FALSE);
266
267 Metadata pluginGroupMetadata = metadataReader.read(metadata.getFile(), options);
268
269 List<org.apache.maven.artifact.repository.metadata.Plugin> plugins = pluginGroupMetadata.getPlugins();
270
271 if (plugins != null) {
272 for (org.apache.maven.artifact.repository.metadata.Plugin plugin : plugins) {
273 if (request.getPrefix().equals(plugin.getPrefix())
274 && (candidates.get(pluginGroup) == null
275 || candidates.get(pluginGroup).contains(plugin.getArtifactId()))) {
276 return new DefaultPluginPrefixResult(pluginGroup, plugin.getArtifactId(), repository);
277 }
278 }
279 }
280 } catch (IOException e) {
281 invalidMetadata(request.getRepositorySession(), trace, metadata, repository, e);
282 }
283 }
284
285 return null;
286 }
287
288 private void invalidMetadata(
289 RepositorySystemSession session,
290 RequestTrace trace,
291 org.eclipse.aether.metadata.Metadata metadata,
292 ArtifactRepository repository,
293 Exception exception) {
294 RepositoryListener listener = session.getRepositoryListener();
295 if (listener != null) {
296 RepositoryEvent.Builder event = new RepositoryEvent.Builder(session, EventType.METADATA_INVALID);
297 event.setTrace(trace);
298 event.setMetadata(metadata);
299 event.setException(exception);
300 event.setRepository(repository);
301 listener.metadataInvalid(event.build());
302 }
303 }
304 }