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