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.plugin.prefix.internal;
20  
21  import java.io.IOException;
22  import java.util.ArrayList;
23  import java.util.Collections;
24  import java.util.List;
25  import java.util.Map;
26  
27  import org.apache.maven.artifact.repository.metadata.Metadata;
28  import org.apache.maven.artifact.repository.metadata.io.MetadataReader;
29  import org.apache.maven.model.Build;
30  import org.apache.maven.model.Plugin;
31  import org.apache.maven.plugin.BuildPluginManager;
32  import org.apache.maven.plugin.descriptor.PluginDescriptor;
33  import org.apache.maven.plugin.prefix.NoPluginFoundForPrefixException;
34  import org.apache.maven.plugin.prefix.PluginPrefixRequest;
35  import org.apache.maven.plugin.prefix.PluginPrefixResolver;
36  import org.apache.maven.plugin.prefix.PluginPrefixResult;
37  import org.codehaus.plexus.component.annotations.Component;
38  import org.codehaus.plexus.component.annotations.Requirement;
39  import org.codehaus.plexus.logging.Logger;
40  import org.eclipse.aether.DefaultRepositorySystemSession;
41  import org.eclipse.aether.RepositoryEvent;
42  import org.eclipse.aether.RepositoryEvent.EventType;
43  import org.eclipse.aether.RepositoryListener;
44  import org.eclipse.aether.RepositorySystem;
45  import org.eclipse.aether.RepositorySystemSession;
46  import org.eclipse.aether.RequestTrace;
47  import org.eclipse.aether.metadata.DefaultMetadata;
48  import org.eclipse.aether.repository.ArtifactRepository;
49  import org.eclipse.aether.repository.RemoteRepository;
50  import org.eclipse.aether.repository.RepositoryPolicy;
51  import org.eclipse.aether.resolution.MetadataRequest;
52  import org.eclipse.aether.resolution.MetadataResult;
53  
54  /**
55   * Resolves a plugin prefix.
56   *
57   * @since 3.0
58   * @author Benjamin Bentmann
59   */
60  @Component(role = PluginPrefixResolver.class)
61  public class DefaultPluginPrefixResolver implements PluginPrefixResolver {
62  
63      private static final String REPOSITORY_CONTEXT = "plugin";
64  
65      @Requirement
66      private Logger logger;
67  
68      @Requirement
69      private BuildPluginManager pluginManager;
70  
71      @Requirement
72      private RepositorySystem repositorySystem;
73  
74      @Requirement
75      private MetadataReader metadataReader;
76  
77      public PluginPrefixResult resolve(PluginPrefixRequest request) throws NoPluginFoundForPrefixException {
78          logger.debug("Resolving plugin prefix " + request.getPrefix() + " from " + request.getPluginGroups());
79  
80          PluginPrefixResult result = resolveFromProject(request);
81  
82          if (result == null) {
83              result = resolveFromRepository(request);
84  
85              if (result == null) {
86                  throw new NoPluginFoundForPrefixException(
87                          request.getPrefix(),
88                          request.getPluginGroups(),
89                          request.getRepositorySession().getLocalRepository(),
90                          request.getRepositories());
91              } else if (logger.isDebugEnabled()) {
92                  logger.debug("Resolved plugin prefix " + request.getPrefix() + " to " + result.getGroupId() + ":"
93                          + result.getArtifactId() + " from repository "
94                          + (result.getRepository() != null
95                                  ? result.getRepository().getId()
96                                  : "null"));
97              }
98          } else if (logger.isDebugEnabled()) {
99              logger.debug("Resolved plugin prefix " + request.getPrefix() + " to " + result.getGroupId() + ":"
100                     + result.getArtifactId() + " from POM " + request.getPom());
101         }
102 
103         return result;
104     }
105 
106     private PluginPrefixResult resolveFromProject(PluginPrefixRequest request) {
107         PluginPrefixResult result = null;
108 
109         if (request.getPom() != null && request.getPom().getBuild() != null) {
110             Build build = request.getPom().getBuild();
111 
112             result = resolveFromProject(request, build.getPlugins());
113 
114             if (result == null && build.getPluginManagement() != null) {
115                 result = resolveFromProject(request, build.getPluginManagement().getPlugins());
116             }
117         }
118 
119         return result;
120     }
121 
122     private PluginPrefixResult resolveFromProject(PluginPrefixRequest request, List<Plugin> plugins) {
123         for (Plugin plugin : plugins) {
124             try {
125                 PluginDescriptor pluginDescriptor =
126                         pluginManager.loadPlugin(plugin, request.getRepositories(), request.getRepositorySession());
127 
128                 if (request.getPrefix().equals(pluginDescriptor.getGoalPrefix())) {
129                     return new DefaultPluginPrefixResult(plugin);
130                 }
131             } catch (Exception e) {
132                 if (logger.isDebugEnabled()) {
133                     logger.warn(
134                             "Failed to retrieve plugin descriptor for " + plugin.getId() + ": " + e.getMessage(), e);
135                 } else {
136                     logger.warn("Failed to retrieve plugin descriptor for " + plugin.getId() + ": " + e.getMessage());
137                 }
138             }
139         }
140 
141         return null;
142     }
143 
144     private PluginPrefixResult resolveFromRepository(PluginPrefixRequest request) {
145         RequestTrace trace = RequestTrace.newChild(null, request);
146 
147         List<MetadataRequest> requests = new ArrayList<>();
148 
149         for (String pluginGroup : request.getPluginGroups()) {
150             org.eclipse.aether.metadata.Metadata metadata =
151                     new DefaultMetadata(pluginGroup, "maven-metadata.xml", DefaultMetadata.Nature.RELEASE_OR_SNAPSHOT);
152 
153             requests.add(new MetadataRequest(metadata, null, REPOSITORY_CONTEXT).setTrace(trace));
154 
155             for (RemoteRepository repository : request.getRepositories()) {
156                 requests.add(new MetadataRequest(metadata, repository, REPOSITORY_CONTEXT).setTrace(trace));
157             }
158         }
159 
160         // initial try, use locally cached metadata
161 
162         List<MetadataResult> results = repositorySystem.resolveMetadata(request.getRepositorySession(), requests);
163         requests.clear();
164 
165         PluginPrefixResult result = processResults(request, trace, results, requests);
166 
167         if (result != null) {
168             return result;
169         }
170 
171         // second try, refetch all (possibly outdated) metadata that wasn't updated in the first attempt
172 
173         if (!request.getRepositorySession().isOffline() && !requests.isEmpty()) {
174             DefaultRepositorySystemSession session = new DefaultRepositorySystemSession(request.getRepositorySession());
175             session.setUpdatePolicy(RepositoryPolicy.UPDATE_POLICY_ALWAYS);
176 
177             results = repositorySystem.resolveMetadata(session, requests);
178 
179             return processResults(request, trace, results, null);
180         }
181 
182         return null;
183     }
184 
185     private PluginPrefixResult processResults(
186             PluginPrefixRequest request,
187             RequestTrace trace,
188             List<MetadataResult> results,
189             List<MetadataRequest> requests) {
190         for (MetadataResult res : results) {
191             org.eclipse.aether.metadata.Metadata metadata = res.getMetadata();
192 
193             if (metadata != null) {
194                 ArtifactRepository repository = res.getRequest().getRepository();
195                 if (repository == null) {
196                     repository = request.getRepositorySession().getLocalRepository();
197                 }
198 
199                 PluginPrefixResult result =
200                         resolveFromRepository(request, trace, metadata.getGroupId(), metadata, repository);
201 
202                 if (result != null) {
203                     return result;
204                 }
205             }
206 
207             if (requests != null && !res.isUpdated()) {
208                 requests.add(res.getRequest());
209             }
210         }
211 
212         return null;
213     }
214 
215     private PluginPrefixResult resolveFromRepository(
216             PluginPrefixRequest request,
217             RequestTrace trace,
218             String pluginGroup,
219             org.eclipse.aether.metadata.Metadata metadata,
220             ArtifactRepository repository) {
221         if (metadata != null && metadata.getFile() != null && metadata.getFile().isFile()) {
222             try {
223                 Map<String, ?> options = Collections.singletonMap(MetadataReader.IS_STRICT, Boolean.FALSE);
224 
225                 Metadata pluginGroupMetadata = metadataReader.read(metadata.getFile(), options);
226 
227                 List<org.apache.maven.artifact.repository.metadata.Plugin> plugins = pluginGroupMetadata.getPlugins();
228 
229                 if (plugins != null) {
230                     for (org.apache.maven.artifact.repository.metadata.Plugin plugin : plugins) {
231                         if (request.getPrefix().equals(plugin.getPrefix())) {
232                             return new DefaultPluginPrefixResult(pluginGroup, plugin.getArtifactId(), repository);
233                         }
234                     }
235                 }
236             } catch (IOException e) {
237                 invalidMetadata(request.getRepositorySession(), trace, metadata, repository, e);
238             }
239         }
240 
241         return null;
242     }
243 
244     private void invalidMetadata(
245             RepositorySystemSession session,
246             RequestTrace trace,
247             org.eclipse.aether.metadata.Metadata metadata,
248             ArtifactRepository repository,
249             Exception exception) {
250         RepositoryListener listener = session.getRepositoryListener();
251         if (listener != null) {
252             RepositoryEvent.Builder event = new RepositoryEvent.Builder(session, EventType.METADATA_INVALID);
253             event.setTrace(trace);
254             event.setMetadata(metadata);
255             event.setException(exception);
256             event.setRepository(repository);
257             listener.metadataInvalid(event.build());
258         }
259     }
260 }