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.NetworkProxy;
024import org.apache.archiva.admin.model.beans.ProxyConnector;
025import org.apache.archiva.admin.model.networkproxy.NetworkProxyAdmin;
026import org.apache.archiva.admin.model.proxyconnector.ProxyConnectorAdmin;
027import org.apache.archiva.common.plexusbridge.PlexusSisuBridge;
028import org.apache.archiva.common.plexusbridge.PlexusSisuBridgeException;
029import org.apache.archiva.common.utils.VersionUtil;
030import org.apache.archiva.maven2.metadata.MavenMetadataReader;
031import org.apache.archiva.maven2.model.TreeEntry;
032import org.apache.archiva.metadata.repository.storage.RepositoryPathTranslator;
033import org.apache.archiva.model.ArchivaRepositoryMetadata;
034import org.apache.archiva.repository.ManagedRepository;
035import org.apache.archiva.repository.RemoteRepository;
036import org.apache.archiva.repository.RepositoryRegistry;
037import org.apache.archiva.repository.maven2.MavenSystemManager;
038import org.apache.archiva.repository.metadata.base.MetadataTools;
039import org.apache.archiva.repository.storage.StorageAsset;
040import org.apache.archiva.xml.XMLException;
041import org.apache.commons.lang3.StringUtils;
042import org.apache.maven.artifact.Artifact;
043import org.apache.maven.bridge.MavenRepositorySystem;
044import org.eclipse.aether.RepositorySystem;
045import org.eclipse.aether.RepositorySystemSession;
046import org.eclipse.aether.artifact.DefaultArtifact;
047import org.eclipse.aether.collection.CollectRequest;
048import org.eclipse.aether.collection.CollectResult;
049import org.eclipse.aether.collection.DependencyCollectionException;
050import org.eclipse.aether.graph.Dependency;
051import org.eclipse.aether.graph.DependencyVisitor;
052import org.slf4j.Logger;
053import org.slf4j.LoggerFactory;
054import org.springframework.stereotype.Service;
055
056import javax.annotation.PostConstruct;
057import javax.inject.Inject;
058import javax.inject.Named;
059import java.io.IOException;
060import java.util.ArrayList;
061import java.util.HashMap;
062import java.util.List;
063import java.util.Map;
064
065/**
066 * @author Olivier Lamy
067 * @since 1.4-M3
068 */
069@Service("dependencyTreeBuilder#maven3")
070public class Maven3DependencyTreeBuilder
071    implements DependencyTreeBuilder
072{
073    private Logger log = LoggerFactory.getLogger( Maven3DependencyTreeBuilder.class );
074
075    @Inject
076    private PlexusSisuBridge plexusSisuBridge;
077
078    private MavenRepositorySystem mavenRepositorySystem;
079
080    @Inject
081    @Named( "repositoryPathTranslator#maven2" )
082    private RepositoryPathTranslator pathTranslator;
083
084    @Inject
085    private ProxyConnectorAdmin proxyConnectorAdmin;
086
087    @Inject
088    private NetworkProxyAdmin networkProxyAdmin;
089
090    @Inject
091    RepositoryRegistry repositoryRegistry;
092
093    @Inject
094    MavenSystemManager mavenSystemManager;
095
096
097    @PostConstruct
098    public void initialize()
099        throws PlexusSisuBridgeException
100    {
101        mavenRepositorySystem = plexusSisuBridge.lookup(MavenRepositorySystem.class);
102    }
103
104
105
106    public void buildDependencyTree( List<String> repositoryIds, String groupId, String artifactId, String version,
107                                     DependencyVisitor dependencyVisitor )
108        throws DependencyTreeBuilderException
109    {
110
111        Artifact projectArtifact = mavenRepositorySystem.createProjectArtifact(groupId, artifactId, version);
112        ManagedRepository repository = findArtifactInRepositories( repositoryIds, projectArtifact );
113
114        if ( repository == null )
115        {
116            // metadata could not be resolved
117            log.info("Did not find repository with artifact {}/{}/{}", groupId, artifactId, version);
118            return;
119        }
120
121        List<org.apache.archiva.repository.RemoteRepository> remoteRepositories = new ArrayList<>();
122        Map<String, NetworkProxy> networkProxies = new HashMap<>();
123
124        try
125        {
126            // MRM-1411
127            // TODO: this is a workaround for a lack of proxy capability in the resolvers - replace when it can all be
128            //       handled there. It doesn't cache anything locally!
129
130            Map<String, List<ProxyConnector>> proxyConnectorsMap = proxyConnectorAdmin.getProxyConnectorAsMap();
131            List<ProxyConnector> proxyConnectors = proxyConnectorsMap.get( repository.getId() );
132            if ( proxyConnectors != null )
133            {
134                for ( ProxyConnector proxyConnector : proxyConnectors )
135                {
136                    remoteRepositories.add(
137                        repositoryRegistry.getRemoteRepository( proxyConnector.getTargetRepoId() ) );
138
139                    NetworkProxy networkProxyConfig = networkProxyAdmin.getNetworkProxy( proxyConnector.getProxyId() );
140
141                    if ( networkProxyConfig != null )
142                    {
143                        // key/value: remote repo ID/proxy info
144                        networkProxies.put( proxyConnector.getTargetRepoId(), networkProxyConfig );
145                    }
146                }
147            }
148        }
149        catch ( RepositoryAdminException e )
150        {
151            throw new DependencyTreeBuilderException( e.getMessage(), e );
152        }
153
154        // FIXME take care of relative path
155        ResolveRequest resolveRequest = new ResolveRequest();
156        resolveRequest.dependencyVisitor = dependencyVisitor;
157        resolveRequest.localRepoDir = repository.getContent().getRepoRoot();
158        resolveRequest.groupId = groupId;
159        resolveRequest.artifactId = artifactId;
160        resolveRequest.version = version;
161        resolveRequest.remoteRepositories = remoteRepositories;
162        resolveRequest.networkProxies = networkProxies;
163        resolve( resolveRequest );
164    }
165
166
167    @Override
168    public List<TreeEntry> buildDependencyTree( List<String> repositoryIds, String groupId, String artifactId,
169                                                String version )
170        throws DependencyTreeBuilderException
171    {
172
173        List<TreeEntry> treeEntries = new ArrayList<>();
174        TreeDependencyNodeVisitor treeDependencyNodeVisitor = new TreeDependencyNodeVisitor( treeEntries );
175
176        buildDependencyTree( repositoryIds, groupId, artifactId, version, treeDependencyNodeVisitor );
177
178        log.debug( "treeEntries: {}", treeEntries );
179        return treeEntries;
180    }
181
182    private static class ResolveRequest
183    {
184        String localRepoDir, groupId, artifactId, version;
185
186        DependencyVisitor dependencyVisitor;
187
188        List<org.apache.archiva.repository.RemoteRepository> remoteRepositories;
189
190        Map<String, NetworkProxy> networkProxies;
191
192    }
193
194
195    private void resolve( ResolveRequest resolveRequest )
196    {
197
198        RepositorySystem system = mavenSystemManager.getRepositorySystem();
199        RepositorySystemSession session = MavenSystemManager.newRepositorySystemSession( resolveRequest.localRepoDir );
200
201        org.eclipse.aether.artifact.Artifact artifact = new DefaultArtifact(
202            resolveRequest.groupId + ":" + resolveRequest.artifactId + ":" + resolveRequest.version );
203
204        CollectRequest collectRequest = new CollectRequest();
205        collectRequest.setRoot( new Dependency( artifact, "" ) );
206
207        // add remote repositories
208        for ( RemoteRepository remoteRepository : resolveRequest.remoteRepositories )
209        {
210            org.eclipse.aether.repository.RemoteRepository repo = new org.eclipse.aether.repository.RemoteRepository.Builder( remoteRepository.getId( ), "default", remoteRepository.getLocation( ).toString() ).build( );
211            collectRequest.addRepository(repo);
212        }
213        collectRequest.setRequestContext( "project" );
214
215        //collectRequest.addRepository( repo );
216
217        try
218        {
219            CollectResult collectResult = system.collectDependencies( session, collectRequest );
220            collectResult.getRoot().accept( resolveRequest.dependencyVisitor );
221            log.debug("Collected dependency results for resolve");
222        }
223        catch ( DependencyCollectionException e )
224        {
225            log.error( "Error while collecting dependencies (resolve): {}", e.getMessage(), e );
226        }
227
228
229
230    }
231
232    private ManagedRepository findArtifactInRepositories( List<String> repositoryIds, Artifact projectArtifact ) {
233        for ( String repoId : repositoryIds )
234        {
235            ManagedRepository managedRepo = repositoryRegistry.getManagedRepository(repoId);
236            StorageAsset repoDir = managedRepo.getAsset("");
237
238            StorageAsset file = pathTranslator.toFile( repoDir, projectArtifact.getGroupId(), projectArtifact.getArtifactId(),
239                                               projectArtifact.getBaseVersion(),
240                                               projectArtifact.getArtifactId() + "-" + projectArtifact.getVersion()
241                                                   + ".pom" );
242
243            if ( file.exists() )
244            {
245                return managedRepo;
246            }
247            // try with snapshot version
248            if ( StringUtils.endsWith( projectArtifact.getBaseVersion(), VersionUtil.SNAPSHOT ) )
249            {
250                StorageAsset metadataFile = file.getParent().resolve( MetadataTools.MAVEN_METADATA );
251                if ( metadataFile.exists() )
252                {
253                    try
254                    {
255                        ArchivaRepositoryMetadata archivaRepositoryMetadata = MavenMetadataReader.read( metadataFile);
256                        int buildNumber = archivaRepositoryMetadata.getSnapshotVersion().getBuildNumber();
257                        String timeStamp = archivaRepositoryMetadata.getSnapshotVersion().getTimestamp();
258                        // rebuild file name with timestamped version and build number
259                        String timeStampFileName =
260                            new StringBuilder( projectArtifact.getArtifactId() ).append( '-' ).append(
261                                StringUtils.remove( projectArtifact.getBaseVersion(),
262                                                    "-" + VersionUtil.SNAPSHOT ) ).append( '-' ).append(
263                                timeStamp ).append( '-' ).append( Integer.toString( buildNumber ) ).append(
264                                ".pom" ).toString();
265                        StorageAsset timeStampFile = file.getParent().resolve( timeStampFileName );
266                        log.debug( "try to find timestamped snapshot version file: {}", timeStampFile);
267                        if ( timeStampFile.exists() )
268                        {
269                            return managedRepo;
270                        }
271                    }
272                    catch (XMLException | IOException e )
273                    {
274                        log.warn( "skip fail to find timestamped snapshot pom: {}", e.getMessage() );
275                    }
276                }
277            }
278        }
279        return null;
280    }
281
282}