View Javadoc

1   package org.apache.maven.report.projectinfo.dependencies;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.net.UnknownHostException;
23  import java.util.ArrayList;
24  import java.util.List;
25  
26  import org.apache.maven.artifact.Artifact;
27  import org.apache.maven.artifact.ArtifactUtils;
28  import org.apache.maven.artifact.factory.ArtifactFactory;
29  import org.apache.maven.artifact.manager.WagonConfigurationException;
30  import org.apache.maven.artifact.manager.WagonManager;
31  import org.apache.maven.artifact.metadata.ArtifactMetadata;
32  import org.apache.maven.artifact.repository.ArtifactRepository;
33  import org.apache.maven.artifact.repository.metadata.Metadata;
34  import org.apache.maven.artifact.repository.metadata.RepositoryMetadataManager;
35  import org.apache.maven.artifact.repository.metadata.SnapshotArtifactRepositoryMetadata;
36  import org.apache.maven.artifact.repository.metadata.Versioning;
37  import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
38  import org.apache.maven.artifact.resolver.ArtifactResolutionException;
39  import org.apache.maven.artifact.resolver.ArtifactResolver;
40  import org.apache.maven.plugin.logging.Log;
41  import org.apache.maven.project.MavenProject;
42  import org.apache.maven.project.MavenProjectBuilder;
43  import org.apache.maven.project.ProjectBuildingException;
44  import org.apache.maven.settings.Proxy;
45  import org.apache.maven.settings.Settings;
46  import org.apache.maven.wagon.ConnectionException;
47  import org.apache.maven.wagon.TransferFailedException;
48  import org.apache.maven.wagon.UnsupportedProtocolException;
49  import org.apache.maven.wagon.Wagon;
50  import org.apache.maven.wagon.authentication.AuthenticationException;
51  import org.apache.maven.wagon.authentication.AuthenticationInfo;
52  import org.apache.maven.wagon.authorization.AuthorizationException;
53  import org.apache.maven.wagon.observers.Debug;
54  import org.apache.maven.wagon.proxy.ProxyInfo;
55  import org.apache.maven.wagon.repository.Repository;
56  import org.codehaus.plexus.util.StringUtils;
57  
58  /**
59   * Utilities methods to play with repository
60   *
61   * @version $Id: RepositoryUtils.java 1100809 2011-05-08 20:40:20Z hboutemy $
62   * @since 2.1
63   */
64  public class RepositoryUtils
65  {
66      private static final List<String> UNKNOWN_HOSTS = new ArrayList<String>();
67  
68      private final Log log;
69  
70      private final WagonManager wagonManager;
71  
72      private final Settings settings;
73  
74      private final MavenProjectBuilder mavenProjectBuilder;
75  
76      private final ArtifactFactory factory;
77  
78      private final List<ArtifactRepository> remoteRepositories;
79  
80      private final List<ArtifactRepository> pluginRepositories;
81  
82      private final ArtifactResolver resolver;
83  
84      private final ArtifactRepository localRepository;
85  
86      /**
87       * @param log
88       * @param wagonManager
89       * @param settings
90       * @param mavenProjectBuilder
91       * @param factory
92       * @param resolver
93       * @param remoteRepositories
94       * @param pluginRepositories
95       * @param localRepository
96       * @param repositoryMetadataManager
97       */
98      public RepositoryUtils( Log log, WagonManager wagonManager, Settings settings,
99                              MavenProjectBuilder mavenProjectBuilder, ArtifactFactory factory,
100                             ArtifactResolver resolver, List<ArtifactRepository> remoteRepositories,
101                             List<ArtifactRepository> pluginRepositories, ArtifactRepository localRepository,
102                             RepositoryMetadataManager repositoryMetadataManager )
103     {
104         this.log = log;
105         this.wagonManager = wagonManager;
106         this.settings = settings;
107         this.mavenProjectBuilder = mavenProjectBuilder;
108         this.factory = factory;
109         this.resolver = resolver;
110         this.remoteRepositories = remoteRepositories;
111         this.pluginRepositories = pluginRepositories;
112         this.localRepository = localRepository;
113     }
114 
115     /**
116      * @return localrepo
117      */
118     public ArtifactRepository getLocalRepository()
119     {
120         return localRepository;
121     }
122 
123     /**
124      * @return remote artifact repo
125      */
126     public List<ArtifactRepository> getRemoteArtifactRepositories()
127     {
128         return remoteRepositories;
129     }
130 
131     /**
132      * @return plugin artifact repo
133      */
134     public List<ArtifactRepository> getPluginArtifactRepositories()
135     {
136         return pluginRepositories;
137     }
138 
139     /**
140      * @param artifact not null
141      * @throws ArtifactResolutionException if any
142      * @throws ArtifactNotFoundException if any
143      * @see ArtifactResolver#resolve(Artifact, List, ArtifactRepository)
144      */
145     public void resolve( Artifact artifact )
146         throws ArtifactResolutionException, ArtifactNotFoundException
147     {
148         List<ArtifactRepository> repos =
149             new ArrayList<ArtifactRepository>( pluginRepositories.size() + remoteRepositories.size() );
150         repos.addAll( pluginRepositories );
151         repos.addAll( remoteRepositories );
152 
153         resolver.resolve( artifact, repos, localRepository );
154     }
155 
156     /**
157      * @param repo not null
158      * @param artifact not null
159      * @return <code>true</code> if the artifact exists in the given repo, <code>false</code> otherwise or if
160      * the repo is blacklisted.
161      */
162     public boolean dependencyExistsInRepo( ArtifactRepository repo, Artifact artifact )
163     {
164         if ( repo.isBlacklisted() )
165         {
166             if ( log.isDebugEnabled() )
167             {
168                 log.debug( "The repo '" + repo.getId() + "' is black listed - Ignored it" );
169             }
170             return false;
171         }
172 
173         if ( UNKNOWN_HOSTS.contains( repo.getUrl() ) )
174         {
175             if ( log.isDebugEnabled() )
176             {
177                 log.debug( "The repo url '" + repo.getUrl() + "' is unknowned - Ignored it" );
178             }
179             return false;
180         }
181 
182         repo = wagonManager.getMirrorRepository( repo );
183 
184         String id = repo.getId();
185         Repository repository = new Repository( id, repo.getUrl() );
186 
187         Wagon wagon;
188         try
189         {
190             wagon = wagonManager.getWagon( repository );
191         }
192         catch ( UnsupportedProtocolException e )
193         {
194             logError( "Unsupported protocol: '" + repo.getProtocol() + "'", e );
195             return false;
196         }
197         catch ( WagonConfigurationException e )
198         {
199             logError( "Unsupported protocol: '" + repo.getProtocol() + "'", e );
200             return false;
201         }
202 
203         wagon.setTimeout( 1000 );
204 
205         if ( log.isDebugEnabled() )
206         {
207             Debug debug = new Debug();
208 
209             wagon.addSessionListener( debug );
210             wagon.addTransferListener( debug );
211         }
212 
213         try
214         {
215             // FIXME when upgrading to maven 3.x : this must be changed.
216             AuthenticationInfo auth = wagonManager.getAuthenticationInfo( repo.getId() );
217 
218             ProxyInfo proxyInfo = getProxyInfo();
219             if ( proxyInfo != null )
220             {
221                 wagon.connect( repository, auth, proxyInfo );
222             }
223             else
224             {
225                 wagon.connect( repository, auth );
226             }
227 
228             return wagon.resourceExists( StringUtils.replace( getDependencyUrlFromRepository( artifact, repo ),
229                                                               repo.getUrl(), "" ) );
230         }
231         catch ( ConnectionException e )
232         {
233             logError( "Unable to connect to: " + repo.getUrl(), e );
234             return false;
235         }
236         catch ( AuthenticationException e )
237         {
238             logError( "Unable to connect to: " + repo.getUrl(), e );
239             return false;
240         }
241         catch ( TransferFailedException e )
242         {
243             if ( e.getCause() instanceof UnknownHostException )
244             {
245                 log.error( "Unknown host " + e.getCause().getMessage() + " - ignored it" );
246                 UNKNOWN_HOSTS.add( repo.getUrl() );
247             }
248             else
249             {
250                 logError( "Unable to determine if resource " + artifact + " exists in " + repo.getUrl(), e );
251             }
252             return false;
253         }
254         catch ( AuthorizationException e )
255         {
256             logError( "Unable to connect to: " + repo.getUrl(), e );
257             return false;
258         }
259         catch ( AbstractMethodError e )
260         {
261             log.error( "Wagon " + wagon.getClass().getName() + " does not support the resourceExists method" );
262             return false;
263         }
264         finally
265         {
266             try
267             {
268                 wagon.disconnect();
269             }
270             catch ( ConnectionException e )
271             {
272                 logError( "Error disconnecting wagon - ignored", e );
273             }
274         }
275     }
276 
277     /**
278      * Get the <code>Maven project</code> from the repository depending the <code>Artifact</code> given.
279      *
280      * @param artifact an artifact
281      * @return the Maven project for the given artifact
282      * @throws ProjectBuildingException if any
283      */
284     public MavenProject getMavenProjectFromRepository( Artifact artifact )
285         throws ProjectBuildingException
286     {
287         Artifact projectArtifact = artifact;
288 
289         boolean allowStubModel = false;
290         if ( !"pom".equals( artifact.getType() ) )
291         {
292             projectArtifact = factory.createProjectArtifact( artifact.getGroupId(), artifact.getArtifactId(),
293                                                              artifact.getVersion(), artifact.getScope() );
294             allowStubModel = true;
295         }
296 
297         // TODO: we should use the MavenMetadataSource instead
298         return mavenProjectBuilder.buildFromRepository( projectArtifact, remoteRepositories, localRepository,
299                                                         allowStubModel );
300     }
301 
302     /**
303      * @param artifact not null
304      * @param repo not null
305      * @return the artifact url in the given repo for the given artifact. If it is a snapshot artifact, the version
306      * will be the timestamp and the build number from the metadata. Could return null if the repo is blacklisted.
307      */
308     public String getDependencyUrlFromRepository( Artifact artifact, ArtifactRepository repo )
309     {
310         if ( repo.isBlacklisted() )
311         {
312             return null;
313         }
314 
315         Artifact copyArtifact = ArtifactUtils.copyArtifact( artifact );
316         // Try to get the last artifact repo name depending the snapshot version
317         if ( ( artifact.isSnapshot() && repo.getSnapshots().isEnabled() ) )
318         {
319             if ( artifact.getBaseVersion().equals( artifact.getVersion() ) )
320             {
321                 // Try to resolve it if not already done
322                 if ( artifact.getMetadataList() == null || artifact.getMetadataList().isEmpty() )
323                 {
324                     try
325                     {
326                         resolve( artifact );
327                     }
328                     catch ( ArtifactResolutionException e )
329                     {
330                         log.error( "Artifact: " + artifact.getId() + " could not be resolved." );
331                     }
332                     catch ( ArtifactNotFoundException e )
333                     {
334                         log.error( "Artifact: " + artifact.getId() + " was not found." );
335                     }
336                 }
337 
338                 for ( ArtifactMetadata m : artifact.getMetadataList() )
339                 {
340                     if ( m instanceof SnapshotArtifactRepositoryMetadata )
341                     {
342                         SnapshotArtifactRepositoryMetadata snapshotMetadata = (SnapshotArtifactRepositoryMetadata) m;
343 
344                         Metadata metadata = snapshotMetadata.getMetadata();
345                         Versioning versioning = metadata.getVersioning();
346                         if ( versioning == null || versioning.getSnapshot() == null
347                             || versioning.getSnapshot().isLocalCopy()
348                             || versioning.getSnapshot().getTimestamp() == null )
349                         {
350                             continue;
351                         }
352 
353                         // create the version according SnapshotTransformation
354                         String version =
355                             StringUtils.replace( copyArtifact.getVersion(), Artifact.SNAPSHOT_VERSION,
356                                                  versioning.getSnapshot().getTimestamp() )
357                                 + "-" + versioning.getSnapshot().getBuildNumber();
358                         copyArtifact.setVersion( version );
359                     }
360                 }
361             }
362         }
363 
364         return repo.getUrl() + "/" + repo.pathOf( copyArtifact );
365     }
366 
367     // ----------------------------------------------------------------------
368     // Private methods
369     // ----------------------------------------------------------------------
370 
371     /**
372      * Convenience method to map a <code>Proxy</code> object from the user system settings to a <code>ProxyInfo</code>
373      * object.
374      *
375      * @return a proxyInfo object instanced or null if no active proxy is define in the settings.xml
376      */
377     private ProxyInfo getProxyInfo()
378     {
379         if ( settings == null || settings.getActiveProxy() == null )
380         {
381             return null;
382         }
383 
384         Proxy settingsProxy = settings.getActiveProxy();
385 
386         ProxyInfo proxyInfo = new ProxyInfo();
387         proxyInfo.setHost( settingsProxy.getHost() );
388         proxyInfo.setType( settingsProxy.getProtocol() );
389         proxyInfo.setPort( settingsProxy.getPort() );
390         proxyInfo.setNonProxyHosts( settingsProxy.getNonProxyHosts() );
391         proxyInfo.setUserName( settingsProxy.getUsername() );
392         proxyInfo.setPassword( settingsProxy.getPassword() );
393 
394         return proxyInfo;
395     }
396 
397     /**
398      * Log an error, adding the stacktrace only is debug is enabled.
399      * 
400      * @param message the error message
401      * @param e the cause
402      */
403     private void logError( String message, Exception e )
404     {
405         if ( log.isDebugEnabled() )
406         {
407             log.error( message, e );
408         }
409         else
410         {
411             log.error( message );
412         }
413     }
414 }