This project has retired. For details please refer to its Attic page.
Source code
001package org.apache.archiva.dependency.tree.maven2;
002/*
003 * Licensed to the Apache Software Foundation (ASF) under one
004 * or more contributor license agreements.  See the NOTICE file
005 * distributed with this work for additional information
006 * regarding copyright ownership.  The ASF licenses this file
007 * to you under the Apache License, Version 2.0 (the
008 * "License"); you may not use this file except in compliance
009 * with the License.  You may obtain a copy of the License at
010 *
011 *   http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing,
014 * software distributed under the License is distributed on an
015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
016 * KIND, either express or implied.  See the License for the
017 * specific language governing permissions and limitations
018 * under the License.
019 */
020
021
022import org.apache.archiva.admin.model.RepositoryAdminException;
023import org.apache.archiva.admin.model.beans.ManagedRepository;
024import org.apache.archiva.admin.model.beans.NetworkProxy;
025import org.apache.archiva.admin.model.beans.ProxyConnector;
026import org.apache.archiva.admin.model.beans.RemoteRepository;
027import org.apache.archiva.admin.model.managed.ManagedRepositoryAdmin;
028import org.apache.archiva.admin.model.networkproxy.NetworkProxyAdmin;
029import org.apache.archiva.admin.model.proxyconnector.ProxyConnectorAdmin;
030import org.apache.archiva.admin.model.remote.RemoteRepositoryAdmin;
031import org.apache.archiva.common.plexusbridge.PlexusSisuBridge;
032import org.apache.archiva.common.plexusbridge.PlexusSisuBridgeException;
033import org.apache.archiva.common.utils.VersionUtil;
034import org.apache.archiva.maven2.metadata.MavenMetadataReader;
035import org.apache.archiva.maven2.model.TreeEntry;
036import org.apache.archiva.metadata.repository.storage.RepositoryPathTranslator;
037import org.apache.archiva.model.ArchivaRepositoryMetadata;
038import org.apache.archiva.proxy.common.WagonFactory;
039import org.apache.archiva.repository.metadata.MetadataTools;
040import org.apache.archiva.xml.XMLException;
041import org.apache.commons.lang.StringUtils;
042import org.apache.maven.artifact.Artifact;
043import org.apache.maven.artifact.factory.ArtifactFactory;
044import org.apache.maven.model.building.DefaultModelBuilderFactory;
045import org.apache.maven.model.building.ModelBuilder;
046import org.apache.maven.repository.internal.DefaultArtifactDescriptorReader;
047import org.apache.maven.repository.internal.DefaultVersionRangeResolver;
048import org.apache.maven.repository.internal.DefaultVersionResolver;
049import org.apache.maven.repository.internal.MavenRepositorySystemSession;
050import org.slf4j.Logger;
051import org.slf4j.LoggerFactory;
052import org.sonatype.aether.RepositorySystem;
053import org.sonatype.aether.RepositorySystemSession;
054import org.sonatype.aether.collection.CollectRequest;
055import org.sonatype.aether.collection.CollectResult;
056import org.sonatype.aether.collection.DependencyCollectionException;
057import org.sonatype.aether.collection.DependencySelector;
058import org.sonatype.aether.graph.Dependency;
059import org.sonatype.aether.graph.DependencyVisitor;
060import org.sonatype.aether.impl.ArtifactDescriptorReader;
061import org.sonatype.aether.impl.VersionRangeResolver;
062import org.sonatype.aether.impl.VersionResolver;
063import org.sonatype.aether.impl.internal.DefaultServiceLocator;
064import org.sonatype.aether.impl.internal.SimpleLocalRepositoryManager;
065import org.sonatype.aether.repository.LocalRepository;
066import org.sonatype.aether.spi.connector.RepositoryConnectorFactory;
067import org.sonatype.aether.util.artifact.DefaultArtifact;
068import org.sonatype.aether.util.graph.selector.AndDependencySelector;
069import org.sonatype.aether.util.graph.selector.ExclusionDependencySelector;
070import org.springframework.stereotype.Service;
071
072import javax.annotation.PostConstruct;
073import javax.inject.Inject;
074import javax.inject.Named;
075import java.io.File;
076import java.util.ArrayList;
077import java.util.HashMap;
078import java.util.List;
079import java.util.Map;
080
081/**
082 * @author Olivier Lamy
083 * @since 1.4-M3
084 */
085@Service("dependencyTreeBuilder#maven3")
086public class Maven3DependencyTreeBuilder
087    implements DependencyTreeBuilder
088{
089    private Logger log = LoggerFactory.getLogger( getClass() );
090
091    @Inject
092    private PlexusSisuBridge plexusSisuBridge;
093
094    @Inject
095    @Named( "repositoryPathTranslator#maven2" )
096    private RepositoryPathTranslator pathTranslator;
097
098    @Inject
099    private WagonFactory wagonFactory;
100
101    @Inject
102    private ManagedRepositoryAdmin managedRepositoryAdmin;
103
104    @Inject
105    private ProxyConnectorAdmin proxyConnectorAdmin;
106
107    @Inject
108    private NetworkProxyAdmin networkProxyAdmin;
109
110    @Inject
111    private RemoteRepositoryAdmin remoteRepositoryAdmin;
112
113    private ArtifactFactory factory;
114
115    private ModelBuilder builder;
116
117    @PostConstruct
118    public void initialize()
119        throws PlexusSisuBridgeException
120    {
121        factory = plexusSisuBridge.lookup( ArtifactFactory.class, "default" );
122
123        DefaultModelBuilderFactory defaultModelBuilderFactory = new DefaultModelBuilderFactory();
124        builder = defaultModelBuilderFactory.newInstance();
125    }
126
127    @Override
128    public void buildDependencyTree( List<String> repositoryIds, String groupId, String artifactId, String version,
129                                     DependencyVisitor dependencyVisitor )
130        throws DependencyTreeBuilderException
131    {
132        Artifact projectArtifact = factory.createProjectArtifact( groupId, artifactId, version );
133        ManagedRepository repository = null;
134        try
135        {
136            repository = findArtifactInRepositories( repositoryIds, projectArtifact );
137        }
138        catch ( RepositoryAdminException e )
139        {
140            // FIXME better exception
141            throw new DependencyTreeBuilderException( "Cannot build project dependency tree " + e.getMessage(), e );
142        }
143
144        if ( repository == null )
145        {
146            // metadata could not be resolved
147            return;
148        }
149
150        List<RemoteRepository> remoteRepositories = new ArrayList<>();
151        Map<String, NetworkProxy> networkProxies = new HashMap<>();
152
153        try
154        {
155            // MRM-1411
156            // TODO: this is a workaround for a lack of proxy capability in the resolvers - replace when it can all be
157            //       handled there. It doesn't cache anything locally!
158
159            Map<String, List<ProxyConnector>> proxyConnectorsMap = proxyConnectorAdmin.getProxyConnectorAsMap();
160            List<ProxyConnector> proxyConnectors = proxyConnectorsMap.get( repository.getId() );
161            if ( proxyConnectors != null )
162            {
163                for ( ProxyConnector proxyConnector : proxyConnectors )
164                {
165                    remoteRepositories.add(
166                        remoteRepositoryAdmin.getRemoteRepository( proxyConnector.getTargetRepoId() ) );
167
168                    NetworkProxy networkProxyConfig = networkProxyAdmin.getNetworkProxy( proxyConnector.getProxyId() );
169
170                    if ( networkProxyConfig != null )
171                    {
172                        // key/value: remote repo ID/proxy info
173                        networkProxies.put( proxyConnector.getTargetRepoId(), networkProxyConfig );
174                    }
175                }
176            }
177        }
178        catch ( RepositoryAdminException e )
179        {
180            throw new DependencyTreeBuilderException( e.getMessage(), e );
181        }
182
183        // FIXME take care of relative path
184        ResolveRequest resolveRequest = new ResolveRequest();
185        resolveRequest.dependencyVisitor = dependencyVisitor;
186        resolveRequest.localRepoDir = repository.getLocation();
187        resolveRequest.groupId = groupId;
188        resolveRequest.artifactId = artifactId;
189        resolveRequest.version = version;
190        resolveRequest.remoteRepositories = remoteRepositories;
191        resolveRequest.networkProxies = networkProxies;
192        resolve( resolveRequest );
193    }
194
195
196    @Override
197    public List<TreeEntry> buildDependencyTree( List<String> repositoryIds, String groupId, String artifactId,
198                                                String version )
199        throws DependencyTreeBuilderException
200    {
201
202        List<TreeEntry> treeEntries = new ArrayList<>();
203        TreeDependencyNodeVisitor treeDependencyNodeVisitor = new TreeDependencyNodeVisitor( treeEntries );
204
205        buildDependencyTree( repositoryIds, groupId, artifactId, version, treeDependencyNodeVisitor );
206
207        log.debug( "treeEntrie: {}", treeEntries );
208        return treeEntries;
209    }
210
211    private static class ResolveRequest
212    {
213        String localRepoDir, groupId, artifactId, version;
214
215        DependencyVisitor dependencyVisitor;
216
217        List<RemoteRepository> remoteRepositories;
218
219        Map<String, NetworkProxy> networkProxies;
220
221    }
222
223
224    private void resolve( ResolveRequest resolveRequest )
225    {
226
227        RepositorySystem system = newRepositorySystem();
228
229        RepositorySystemSession session = newRepositorySystemSession( system, resolveRequest.localRepoDir );
230
231        org.sonatype.aether.artifact.Artifact artifact = new DefaultArtifact(
232            resolveRequest.groupId + ":" + resolveRequest.artifactId + ":" + resolveRequest.version );
233
234        CollectRequest collectRequest = new CollectRequest();
235        collectRequest.setRoot( new Dependency( artifact, "" ) );
236
237        // add remote repositories
238        for ( RemoteRepository remoteRepository : resolveRequest.remoteRepositories )
239        {
240            collectRequest.addRepository(
241                new org.sonatype.aether.repository.RemoteRepository( remoteRepository.getId(), "default",
242                                                                     remoteRepository.getUrl() ) );
243        }
244        collectRequest.setRequestContext( "project" );
245
246        //collectRequest.addRepository( repo );
247
248        try
249        {
250            CollectResult collectResult = system.collectDependencies( session, collectRequest );
251            collectResult.getRoot().accept( resolveRequest.dependencyVisitor );
252            log.debug( "test" );
253        }
254        catch ( DependencyCollectionException e )
255        {
256            log.error( e.getMessage(), e );
257        }
258
259
260    }
261
262    private RepositorySystem newRepositorySystem()
263    {
264        DefaultServiceLocator locator = new DefaultServiceLocator();
265        locator.addService( RepositoryConnectorFactory.class,
266                            ArchivaRepositoryConnectorFactory.class );// FileRepositoryConnectorFactory.class );
267        locator.addService( VersionResolver.class, DefaultVersionResolver.class );
268        locator.addService( VersionRangeResolver.class, DefaultVersionRangeResolver.class );
269        locator.addService( ArtifactDescriptorReader.class, DefaultArtifactDescriptorReader.class );
270        //locator.addService( RepositoryConnectorFactory.class, WagonRepositoryConnectorFactory.class );
271        //locator.setServices( WagonProvider.class,  );
272
273        return locator.getService( RepositorySystem.class );
274    }
275
276    private RepositorySystemSession newRepositorySystemSession( RepositorySystem system, String localRepoDir )
277    {
278        MavenRepositorySystemSession session = new MavenRepositorySystemSession();
279
280        DependencySelector depFilter = new AndDependencySelector( new ExclusionDependencySelector() );
281        session.setDependencySelector( depFilter );
282
283        session.setLocalRepositoryManager(
284            new SimpleLocalRepositoryManager( localRepoDir ) );
285
286        return session;
287    }
288
289
290    private ManagedRepository findArtifactInRepositories( List<String> repositoryIds, Artifact projectArtifact )
291        throws RepositoryAdminException
292    {
293        for ( String repoId : repositoryIds )
294        {
295            ManagedRepository managedRepository = managedRepositoryAdmin.getManagedRepository( repoId );
296
297            File repoDir = new File( managedRepository.getLocation() );
298            File file = pathTranslator.toFile( repoDir, projectArtifact.getGroupId(), projectArtifact.getArtifactId(),
299                                               projectArtifact.getBaseVersion(),
300                                               projectArtifact.getArtifactId() + "-" + projectArtifact.getVersion()
301                                                   + ".pom" );
302
303            if ( file.exists() )
304            {
305                return managedRepository;
306            }
307            // try with snapshot version
308            if ( StringUtils.endsWith( projectArtifact.getBaseVersion(), VersionUtil.SNAPSHOT ) )
309            {
310                File metadataFile = new File( file.getParent(), MetadataTools.MAVEN_METADATA );
311                if ( metadataFile.exists() )
312                {
313                    try
314                    {
315                        ArchivaRepositoryMetadata archivaRepositoryMetadata = MavenMetadataReader.read( metadataFile );
316                        int buildNumber = archivaRepositoryMetadata.getSnapshotVersion().getBuildNumber();
317                        String timeStamp = archivaRepositoryMetadata.getSnapshotVersion().getTimestamp();
318                        // rebuild file name with timestamped version and build number
319                        String timeStampFileName =
320                            new StringBuilder( projectArtifact.getArtifactId() ).append( '-' ).append(
321                                StringUtils.remove( projectArtifact.getBaseVersion(),
322                                                    "-" + VersionUtil.SNAPSHOT ) ).append( '-' ).append(
323                                timeStamp ).append( '-' ).append( Integer.toString( buildNumber ) ).append(
324                                ".pom" ).toString();
325                        File timeStampFile = new File( file.getParent(), timeStampFileName );
326                        log.debug( "try to find timestamped snapshot version file: {}", timeStampFile.getPath() );
327                        if ( timeStampFile.exists() )
328                        {
329                            return managedRepository;
330                        }
331                    }
332                    catch ( XMLException e )
333                    {
334                        log.warn( "skip fail to find timestamped snapshot pom: {}", e.getMessage() );
335                    }
336                }
337            }
338        }
339        return null;
340    }
341
342}