001 package org.apache.maven.plugin.prefix.internal;
002
003 /*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements. See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership. The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License. You may obtain a copy of the License at
011 *
012 * http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied. See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022 import java.io.IOException;
023 import java.util.ArrayList;
024 import java.util.Collections;
025 import java.util.List;
026 import java.util.Map;
027
028 import org.apache.maven.artifact.repository.metadata.Metadata;
029 import org.apache.maven.artifact.repository.metadata.io.MetadataReader;
030 import org.apache.maven.model.Build;
031 import org.apache.maven.model.Plugin;
032 import org.apache.maven.plugin.BuildPluginManager;
033 import org.apache.maven.plugin.descriptor.PluginDescriptor;
034 import org.apache.maven.plugin.prefix.NoPluginFoundForPrefixException;
035 import org.apache.maven.plugin.prefix.PluginPrefixRequest;
036 import org.apache.maven.plugin.prefix.PluginPrefixResolver;
037 import org.apache.maven.plugin.prefix.PluginPrefixResult;
038 import org.codehaus.plexus.component.annotations.Component;
039 import org.codehaus.plexus.component.annotations.Requirement;
040 import org.codehaus.plexus.logging.Logger;
041 import org.sonatype.aether.RepositoryEvent.EventType;
042 import org.sonatype.aether.RepositoryListener;
043 import org.sonatype.aether.RepositorySystem;
044 import org.sonatype.aether.RepositorySystemSession;
045 import org.sonatype.aether.RequestTrace;
046 import org.sonatype.aether.repository.ArtifactRepository;
047 import org.sonatype.aether.repository.RemoteRepository;
048 import org.sonatype.aether.repository.RepositoryPolicy;
049 import org.sonatype.aether.resolution.MetadataRequest;
050 import org.sonatype.aether.resolution.MetadataResult;
051 import org.sonatype.aether.util.DefaultRepositorySystemSession;
052 import org.sonatype.aether.util.DefaultRequestTrace;
053 import org.sonatype.aether.util.listener.DefaultRepositoryEvent;
054 import org.sonatype.aether.util.metadata.DefaultMetadata;
055
056 /**
057 * Resolves a plugin prefix.
058 *
059 * @since 3.0
060 * @author Benjamin Bentmann
061 */
062 @Component( role = PluginPrefixResolver.class )
063 public class DefaultPluginPrefixResolver
064 implements PluginPrefixResolver
065 {
066
067 private static final String REPOSITORY_CONTEXT = "plugin";
068
069 @Requirement
070 private Logger logger;
071
072 @Requirement
073 private BuildPluginManager pluginManager;
074
075 @Requirement
076 private RepositorySystem repositorySystem;
077
078 @Requirement
079 private MetadataReader metadataReader;
080
081 public PluginPrefixResult resolve( PluginPrefixRequest request )
082 throws NoPluginFoundForPrefixException
083 {
084 logger.debug( "Resolving plugin prefix " + request.getPrefix() + " from " + request.getPluginGroups() );
085
086 PluginPrefixResult result = resolveFromProject( request );
087
088 if ( result == null )
089 {
090 result = resolveFromRepository( request );
091
092 if ( result == null )
093 {
094 throw new NoPluginFoundForPrefixException( request.getPrefix(), request.getPluginGroups(),
095 request.getRepositorySession().getLocalRepository(),
096 request.getRepositories() );
097 }
098 else if ( logger.isDebugEnabled() )
099 {
100 logger.debug( "Resolved plugin prefix " + request.getPrefix() + " to " + result.getGroupId() + ":"
101 + result.getArtifactId() + " from repository "
102 + ( result.getRepository() != null ? result.getRepository().getId() : "null" ) );
103 }
104 }
105 else if ( logger.isDebugEnabled() )
106 {
107 logger.debug( "Resolved plugin prefix " + request.getPrefix() + " to " + result.getGroupId() + ":"
108 + result.getArtifactId() + " from POM " + request.getPom() );
109 }
110
111 return result;
112 }
113
114 private PluginPrefixResult resolveFromProject( PluginPrefixRequest request )
115 {
116 PluginPrefixResult result = null;
117
118 if ( request.getPom() != null && request.getPom().getBuild() != null )
119 {
120 Build build = request.getPom().getBuild();
121
122 result = resolveFromProject( request, build.getPlugins() );
123
124 if ( result == null && build.getPluginManagement() != null )
125 {
126 result = resolveFromProject( request, build.getPluginManagement().getPlugins() );
127 }
128 }
129
130 return result;
131 }
132
133 private PluginPrefixResult resolveFromProject( PluginPrefixRequest request, List<Plugin> plugins )
134 {
135 for ( Plugin plugin : plugins )
136 {
137 try
138 {
139 PluginDescriptor pluginDescriptor =
140 pluginManager.loadPlugin( plugin, request.getRepositories(), request.getRepositorySession() );
141
142 if ( request.getPrefix().equals( pluginDescriptor.getGoalPrefix() ) )
143 {
144 return new DefaultPluginPrefixResult( plugin );
145 }
146 }
147 catch ( Exception e )
148 {
149 if ( logger.isDebugEnabled() )
150 {
151 logger.warn( "Failed to retrieve plugin descriptor for " + plugin.getId() + ": " + e.getMessage(),
152 e );
153 }
154 else
155 {
156 logger.warn( "Failed to retrieve plugin descriptor for " + plugin.getId() + ": " + e.getMessage() );
157 }
158 }
159 }
160
161 return null;
162 }
163
164 private PluginPrefixResult resolveFromRepository( PluginPrefixRequest request )
165 {
166 RequestTrace trace = DefaultRequestTrace.newChild( null, request );
167
168 List<MetadataRequest> requests = new ArrayList<MetadataRequest>();
169
170 for ( String pluginGroup : request.getPluginGroups() )
171 {
172 org.sonatype.aether.metadata.Metadata metadata =
173 new DefaultMetadata( pluginGroup, "maven-metadata.xml", DefaultMetadata.Nature.RELEASE_OR_SNAPSHOT );
174
175 requests.add( new MetadataRequest( metadata, null, REPOSITORY_CONTEXT ).setTrace( trace ) );
176
177 for ( RemoteRepository repository : request.getRepositories() )
178 {
179 requests.add( new MetadataRequest( metadata, repository, REPOSITORY_CONTEXT ).setTrace( trace ) );
180 }
181 }
182
183 // initial try, use locally cached metadata
184
185 List<MetadataResult> results = repositorySystem.resolveMetadata( request.getRepositorySession(), requests );
186 requests.clear();
187
188 PluginPrefixResult result = processResults( request, trace, results, requests );
189
190 if ( result != null )
191 {
192 return result;
193 }
194
195 // second try, refetch all (possibly outdated) metadata that wasn't updated in the first attempt
196
197 if ( !request.getRepositorySession().isOffline() && !requests.isEmpty() )
198 {
199 DefaultRepositorySystemSession session =
200 new DefaultRepositorySystemSession( request.getRepositorySession() );
201 session.setUpdatePolicy( RepositoryPolicy.UPDATE_POLICY_ALWAYS );
202
203 results = repositorySystem.resolveMetadata( session, requests );
204
205 return processResults( request, trace, results, null );
206 }
207
208 return null;
209 }
210
211 private PluginPrefixResult processResults( PluginPrefixRequest request, RequestTrace trace,
212 List<MetadataResult> results, List<MetadataRequest> requests )
213 {
214 for ( MetadataResult res : results )
215 {
216 org.sonatype.aether.metadata.Metadata metadata = res.getMetadata();
217
218 if ( metadata != null )
219 {
220 ArtifactRepository repository = res.getRequest().getRepository();
221 if ( repository == null )
222 {
223 repository = request.getRepositorySession().getLocalRepository();
224 }
225
226 PluginPrefixResult result =
227 resolveFromRepository( request, trace, metadata.getGroupId(), metadata, repository );
228
229 if ( result != null )
230 {
231 return result;
232 }
233 }
234
235 if ( requests != null && !res.isUpdated() )
236 {
237 requests.add( res.getRequest() );
238 }
239 }
240
241 return null;
242 }
243
244 private PluginPrefixResult resolveFromRepository( PluginPrefixRequest request, RequestTrace trace,
245 String pluginGroup,
246 org.sonatype.aether.metadata.Metadata metadata,
247 ArtifactRepository repository )
248 {
249 if ( metadata != null && metadata.getFile() != null && metadata.getFile().isFile() )
250 {
251 try
252 {
253 Map<String, ?> options = Collections.singletonMap( MetadataReader.IS_STRICT, Boolean.FALSE );
254
255 Metadata pluginGroupMetadata = metadataReader.read( metadata.getFile(), options );
256
257 List<org.apache.maven.artifact.repository.metadata.Plugin> plugins = pluginGroupMetadata.getPlugins();
258
259 if ( plugins != null )
260 {
261 for ( org.apache.maven.artifact.repository.metadata.Plugin plugin : plugins )
262 {
263 if ( request.getPrefix().equals( plugin.getPrefix() ) )
264 {
265 return new DefaultPluginPrefixResult( pluginGroup, plugin.getArtifactId(), repository );
266 }
267 }
268 }
269 }
270 catch ( IOException e )
271 {
272 invalidMetadata( request.getRepositorySession(), trace, metadata, repository, e );
273 }
274 }
275
276 return null;
277 }
278
279 private void invalidMetadata( RepositorySystemSession session, RequestTrace trace,
280 org.sonatype.aether.metadata.Metadata metadata, ArtifactRepository repository,
281 Exception exception )
282 {
283 RepositoryListener listener = session.getRepositoryListener();
284 if ( listener != null )
285 {
286 DefaultRepositoryEvent event = new DefaultRepositoryEvent( EventType.METADATA_INVALID, session, trace );
287 event.setMetadata( metadata );
288 event.setException( exception );
289 event.setRepository( repository );
290 listener.metadataInvalid( event );
291 }
292 }
293
294 }