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 }