package org.codehaus.mojo.pomtools.helpers; /* * Copyright 2005-2006 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.InvalidArtifactRTException; import org.apache.maven.artifact.factory.ArtifactFactory; import org.apache.maven.artifact.metadata.ArtifactMetadataRetrievalException; import org.apache.maven.artifact.metadata.ArtifactMetadataSource; import org.apache.maven.artifact.repository.ArtifactRepository; import org.apache.maven.artifact.repository.metadata.ArtifactRepositoryMetadata; import org.apache.maven.artifact.repository.metadata.Metadata; import org.apache.maven.artifact.repository.metadata.RepositoryMetadata; import org.apache.maven.artifact.repository.metadata.RepositoryMetadataManager; import org.apache.maven.artifact.repository.metadata.RepositoryMetadataResolutionException; import org.apache.maven.artifact.resolver.ArtifactNotFoundException; import org.apache.maven.artifact.resolver.ArtifactResolutionException; import org.apache.maven.artifact.resolver.ArtifactResolutionResult; import org.apache.maven.artifact.resolver.ArtifactResolver; import org.apache.maven.artifact.resolver.ResolutionNode; import org.apache.maven.artifact.versioning.ArtifactVersion; import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException; import org.apache.maven.execution.MavenSession; import org.codehaus.mojo.pomtools.PomToolsPluginContext; import org.codehaus.mojo.pomtools.PomToolsException; import org.codehaus.mojo.pomtools.PomToolsRTException; import org.codehaus.mojo.pomtools.PomToolsVersionException; import org.codehaus.mojo.pomtools.wrapper.ObjectWrapper; import org.codehaus.mojo.pomtools.wrapper.custom.ModelVersionRange; import org.apache.maven.project.MavenProject; import org.apache.maven.project.ProjectBuildingException; import org.apache.maven.project.artifact.InvalidDependencyVersionException; import org.codehaus.plexus.PlexusContainer; import org.codehaus.plexus.component.repository.exception.ComponentLookupException; import org.codehaus.plexus.util.StringUtils; /** Wrapper library for Maven Artifact and Metadata routines. * * @author <a href="mailto:dhawkins@codehaus.org">David Hawkins</a> * @version $Id$ */ public class MetadataHelper { private final RepositoryMetadataManager repositoryMetadataManager; private final ArtifactFactory artifactFactory; private final List remoteRepositories; private final ArtifactRepository localRepository; private final ArtifactMetadataSource metadataSource; private final ArtifactResolver artifactResolver; public MetadataHelper( MavenSession session, List remoteArtifactRepositories, ArtifactRepository localRepository ) throws PomToolsRTException { PlexusContainer container = session.getContainer(); try { this.repositoryMetadataManager = (RepositoryMetadataManager) container .lookup( RepositoryMetadataManager.class.getName() ); this.artifactFactory = (ArtifactFactory) container.lookup( ArtifactFactory.ROLE ); this.metadataSource = (ArtifactMetadataSource) container.lookup( ArtifactMetadataSource.ROLE ); this.artifactResolver = (ArtifactResolver) container.lookup( ArtifactResolver.ROLE ); } catch ( ComponentLookupException e ) { throw new PomToolsRTException( e ); } this.remoteRepositories = remoteArtifactRepositories; this.localRepository = localRepository; } /** Simple wrapper for * {@link ArtifactFactory#createArtifact(java.lang.String, java.lang.String, java.lang.String, * java.lang.String, java.lang.String)} * */ public Artifact createArtifact( String groupId, String artifactId, String version, String scope, String type ) { return artifactFactory.createArtifact( groupId, artifactId, StringUtils.defaultString( version, Artifact.LATEST_VERSION ), scope, StringUtils.defaultString( type, "jar" ) ); } public Artifact createArtifact( ObjectWrapper obj ) { if ( obj.getFields().get( "scope" ) != null ) { return createArtifact( (String) obj.getFieldValue( "groupId" ), (String) obj.getFieldValue( "artifactId" ), (String) obj.getFieldValue( "version" ), (String) obj.getFieldValue( "scope" ), (String) obj.getFieldValue( "type" ) ); } else { return createArtifact( (String) obj.getFieldValue( "groupId" ), (String) obj.getFieldValue( "artifactId" ), (String) obj.getFieldValue( "version" ), null, null ); } } public RepositoryMetadata getMetadata( ObjectWrapper obj ) throws ArtifactMetadataRetrievalException { return getMetadata( createArtifact( obj ) ); } public RepositoryMetadata getMetadata( Artifact artifact ) throws ArtifactMetadataRetrievalException { RepositoryMetadata metadata = new ArtifactRepositoryMetadata( artifact ); try { repositoryMetadataManager.resolve( metadata, remoteRepositories, localRepository ); return metadata; } catch ( RepositoryMetadataResolutionException e ) { throw new ArtifactMetadataRetrievalException( "An error occured while resolving repository metadata", e ); } } /** Returns whether the groupId and artifactId appear to be valid. * This differs from {@link #isValidDependencyArtifact(Artifact)} in that the version * can be null or even invalid and still get a positive result * * @param artifact * @return */public boolean isValidGroupIdArtifactId( Artifact artifact ) { if ( isValidDependencyArtifact( artifact ) ) { return true; } try { RepositoryMetadata metadata = getMetadata( artifact ); return metadata.getMetadata().getVersioning() != null; } catch ( ArtifactMetadataRetrievalException e ) { return false; } } /** Determines whether the artifact exists ( in that we are able to locate metadata for the groupId and artifactId) * and that the version or version range specified refers to a version specified in the repository metadata. * * @param artifact * @return */ public boolean isValidDependencyArtifact( Artifact artifact ) { try { ModelVersionRange versionRange = ModelVersionRange.createFromVersionSpec( artifact.getVersionRange().toString() ); Metadata metadata = getMetadata( artifact ).getMetadata(); if ( metadata.getVersioning() != null ) { List availableVersions = metadataSource.retrieveAvailableVersions( artifact, localRepository, remoteRepositories ); for ( Iterator iter = availableVersions.iterator(); iter.hasNext(); ) { ArtifactVersion version = (ArtifactVersion) iter.next(); if ( versionRange.containsVersion( version ) ) { return true; } } } return ( metadata.getVersion() != null && versionRange.containsVersion( metadata.getVersion() ) ); } catch ( InvalidArtifactRTException e ) { return false; } catch ( ArtifactMetadataRetrievalException e ) { return false; } catch ( InvalidVersionSpecificationException e ) { return false; } } /** Resolves all transitive dependencies for the current project and returns a list * of {@link TransitiveDependencyInfo} objects. Each object represents a distinct * groupId:artifactId:type dependency. The {@link TransitiveDependencyInfo#getResolutionNodes()} * represent all of the possible ResolutionNodes which resolve to this groupId:artifactId. * * @return * @throws PomToolsException */ public List getTransitiveDependencies() throws PomToolsException, ProjectBuildingException { // Certain things like groupId or versions for dependencies may be declared in a parent // pom so we need to have maven fully resolve the model before walking the tree. MavenProject project = PomToolsPluginContext.getInstance().getActiveProject().getTemporaryResolvedProject(); try { project.setDependencyArtifacts( project.createArtifacts( artifactFactory, null, null ) ); } catch ( InvalidDependencyVersionException e ) { throw new PomToolsVersionException( "Unable to build project due to an invalid dependency version: " + e.getMessage(), e ); } Artifact projectArtifact = project.getArtifact(); Set artifacts = project.getDependencyArtifacts(); try { List dependencies = new ArrayList(); ArtifactResolutionResult result; result = artifactResolver.resolveTransitively( artifacts, projectArtifact, Collections.EMPTY_MAP, localRepository, remoteRepositories, metadataSource, projectArtifact.getDependencyFilter() ); Map dependencyMap = new HashMap(); Set seen = new HashSet(); // First build our map of distinct groupId:artifactIds for ( Iterator iter = result.getArtifactResolutionNodes().iterator(); iter.hasNext(); ) { ResolutionNode node = (ResolutionNode) iter.next(); TransitiveDependencyInfo info = new TransitiveDependencyInfo( node ); dependencyMap.put( info.getKey(), info ); dependencies.add( info ); } // Now populate the map with all children recurseNode( dependencyMap, seen, result.getArtifactResolutionNodes().iterator(), 0 ); return dependencies; } catch ( ArtifactNotFoundException e ) { throw new PomToolsException( e ); } catch ( ArtifactResolutionException e ) { throw new PomToolsException( e ); } } protected void recurseNode( Map dependencyMap, Set seen, Iterator nodeIter, int depth ) throws PomToolsException { while ( nodeIter.hasNext() ) { ResolutionNode node = (ResolutionNode) nodeIter.next(); if ( !seen.contains( node ) ) { seen.add( node ); TransitiveDependencyInfo info = (TransitiveDependencyInfo) dependencyMap.get( node.getKey() ); // if we couldn't find the info in the map, then its not a dependency that we should // care about because it wasn't returned to the top level dependency resolution. if ( info != null ) { info.addResolutionNode( node ); if ( node.isResolved() ) { recurseNode( dependencyMap, seen, node.getChildrenIterator(), depth + 1 ); } } } } } public ArtifactRepository getLocalRepository() { return localRepository; } public List getRemoteRepositories() { return remoteRepositories; } }