]> source.dussan.org Git - archiva.git/blob
a83c3e13dcd6a0c039fc164747ad6d5cfe224886
[archiva.git] /
1 package org.apache.archiva.repository.maven.dependency.tree;
2 /*
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied.  See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19
20
21 import org.apache.archiva.admin.model.RepositoryAdminException;
22 import org.apache.archiva.admin.model.beans.NetworkProxy;
23 import org.apache.archiva.admin.model.beans.ProxyConnector;
24 import org.apache.archiva.admin.model.networkproxy.NetworkProxyAdmin;
25 import org.apache.archiva.admin.model.proxyconnector.ProxyConnectorAdmin;
26 import org.apache.archiva.common.utils.VersionUtil;
27 import org.apache.archiva.maven2.model.TreeEntry;
28 import org.apache.archiva.metadata.maven.MavenMetadataReader;
29 import org.apache.archiva.metadata.repository.storage.RepositoryPathTranslator;
30 import org.apache.archiva.model.ArchivaRepositoryMetadata;
31 import org.apache.archiva.repository.ManagedRepository;
32 import org.apache.archiva.repository.RemoteRepository;
33 import org.apache.archiva.repository.RepositoryRegistry;
34 import org.apache.archiva.repository.maven.MavenSystemManager;
35 import org.apache.archiva.repository.metadata.RepositoryMetadataException;
36 import org.apache.archiva.repository.metadata.base.MetadataTools;
37 import org.apache.archiva.repository.storage.StorageAsset;
38 import org.apache.commons.lang3.StringUtils;
39 import org.apache.commons.lang3.reflect.FieldUtils;
40 import org.apache.maven.artifact.Artifact;
41 import org.apache.maven.artifact.handler.manager.DefaultArtifactHandlerManager;
42 import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
43 import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout;
44 import org.apache.maven.bridge.MavenRepositorySystem;
45 import org.eclipse.aether.RepositorySystem;
46 import org.eclipse.aether.RepositorySystemSession;
47 import org.eclipse.aether.artifact.DefaultArtifact;
48 import org.eclipse.aether.collection.CollectRequest;
49 import org.eclipse.aether.collection.CollectResult;
50 import org.eclipse.aether.collection.DependencyCollectionException;
51 import org.eclipse.aether.graph.Dependency;
52 import org.eclipse.aether.graph.DependencyVisitor;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
55 import org.springframework.stereotype.Service;
56
57 import javax.annotation.PostConstruct;
58 import javax.inject.Inject;
59 import javax.inject.Named;
60 import java.util.ArrayList;
61 import java.util.HashMap;
62 import java.util.List;
63 import java.util.Map;
64
65 /**
66  * @author Olivier Lamy
67  * @since 1.4-M3
68  */
69 @Service("dependencyTreeBuilder#maven3")
70 public class Maven3DependencyTreeBuilder
71     implements DependencyTreeBuilder
72 {
73     private Logger log = LoggerFactory.getLogger( Maven3DependencyTreeBuilder.class );
74
75     private MavenRepositorySystem mavenRepositorySystem;
76
77     @Inject
78     @Named( "repositoryPathTranslator#maven2" )
79     private RepositoryPathTranslator pathTranslator;
80
81     @Inject
82     @Named("metadataReader#maven")
83     private MavenMetadataReader metadataReader;
84
85     @Inject
86     private ProxyConnectorAdmin proxyConnectorAdmin;
87
88     @Inject
89     private NetworkProxyAdmin networkProxyAdmin;
90
91     @Inject
92     RepositoryRegistry repositoryRegistry;
93
94     @Inject
95     MavenSystemManager mavenSystemManager;
96
97
98     @PostConstruct
99     public void initialize()
100         throws RuntimeException
101     {
102         try
103         {
104             mavenRepositorySystem = initMaven( );
105         }
106         catch ( IllegalAccessException e )
107         {
108             throw new RuntimeException( "Could not initialize maven" );
109         }
110     }
111
112     MavenRepositorySystem initMaven() throws IllegalAccessException
113     {
114         MavenRepositorySystem system = new MavenRepositorySystem( );
115         DefaultArtifactHandlerManager afm = new DefaultArtifactHandlerManager( );
116         DefaultRepositoryLayout layout = new DefaultRepositoryLayout( );
117         FieldUtils.writeField( system, "artifactHandlerManager",  afm, true);
118         Map<String, ArtifactRepositoryLayout> map = new HashMap<>( );
119         map.put( "defaultRepositoryLayout", layout );
120         FieldUtils.writeField( system, "layouts",  map, true);
121         return system;
122     }
123
124
125
126     public void buildDependencyTree( List<String> repositoryIds, String groupId, String artifactId, String version,
127                                      DependencyVisitor dependencyVisitor )
128         throws DependencyTreeBuilderException
129     {
130
131         Artifact projectArtifact = mavenRepositorySystem.createProjectArtifact(groupId, artifactId, version);
132         ManagedRepository repository = findArtifactInRepositories( repositoryIds, projectArtifact );
133
134         if ( repository == null )
135         {
136             // metadata could not be resolved
137             log.info("Did not find repository with artifact {}/{}/{}", groupId, artifactId, version);
138             return;
139         }
140
141         List<org.apache.archiva.repository.RemoteRepository> remoteRepositories = new ArrayList<>();
142         Map<String, NetworkProxy> networkProxies = new HashMap<>();
143
144         try
145         {
146             // MRM-1411
147             // TODO: this is a workaround for a lack of proxy capability in the resolvers - replace when it can all be
148             //       handled there. It doesn't cache anything locally!
149
150             Map<String, List<ProxyConnector>> proxyConnectorsMap = proxyConnectorAdmin.getProxyConnectorAsMap();
151             List<ProxyConnector> proxyConnectors = proxyConnectorsMap.get( repository.getId() );
152             if ( proxyConnectors != null )
153             {
154                 for ( ProxyConnector proxyConnector : proxyConnectors )
155                 {
156                     remoteRepositories.add(
157                         repositoryRegistry.getRemoteRepository( proxyConnector.getTargetRepoId() ) );
158
159                     NetworkProxy networkProxyConfig = networkProxyAdmin.getNetworkProxy( proxyConnector.getProxyId() );
160
161                     if ( networkProxyConfig != null )
162                     {
163                         // key/value: remote repo ID/proxy info
164                         networkProxies.put( proxyConnector.getTargetRepoId(), networkProxyConfig );
165                     }
166                 }
167             }
168         }
169         catch ( RepositoryAdminException e )
170         {
171             throw new DependencyTreeBuilderException( e.getMessage(), e );
172         }
173
174         // FIXME take care of relative path
175         ResolveRequest resolveRequest = new ResolveRequest();
176         resolveRequest.dependencyVisitor = dependencyVisitor;
177         resolveRequest.localRepoDir = repository.getRoot().getFilePath().toAbsolutePath().toString();
178         resolveRequest.groupId = groupId;
179         resolveRequest.artifactId = artifactId;
180         resolveRequest.version = version;
181         resolveRequest.remoteRepositories = remoteRepositories;
182         resolveRequest.networkProxies = networkProxies;
183         resolve( resolveRequest );
184     }
185
186
187     @Override
188     public List<TreeEntry> buildDependencyTree( List<String> repositoryIds, String groupId, String artifactId,
189                                                 String version )
190         throws DependencyTreeBuilderException
191     {
192
193         List<TreeEntry> treeEntries = new ArrayList<>();
194         TreeDependencyNodeVisitor treeDependencyNodeVisitor = new TreeDependencyNodeVisitor( treeEntries );
195
196         buildDependencyTree( repositoryIds, groupId, artifactId, version, treeDependencyNodeVisitor );
197
198         log.debug( "treeEntries: {}", treeEntries );
199         return treeEntries;
200     }
201
202     private static class ResolveRequest
203     {
204         String localRepoDir, groupId, artifactId, version;
205
206         DependencyVisitor dependencyVisitor;
207
208         List<org.apache.archiva.repository.RemoteRepository> remoteRepositories;
209
210         Map<String, NetworkProxy> networkProxies;
211
212     }
213
214
215     private void resolve( ResolveRequest resolveRequest )
216     {
217
218         RepositorySystem system = mavenSystemManager.getRepositorySystem();
219         RepositorySystemSession session = MavenSystemManager.newRepositorySystemSession( resolveRequest.localRepoDir );
220
221         org.eclipse.aether.artifact.Artifact artifact = new DefaultArtifact(
222             resolveRequest.groupId + ":" + resolveRequest.artifactId + ":" + resolveRequest.version );
223
224         CollectRequest collectRequest = new CollectRequest();
225         collectRequest.setRoot( new Dependency( artifact, "" ) );
226
227         // add remote repositories
228         for ( RemoteRepository remoteRepository : resolveRequest.remoteRepositories )
229         {
230             org.eclipse.aether.repository.RemoteRepository repo = new org.eclipse.aether.repository.RemoteRepository.Builder( remoteRepository.getId( ), "default", remoteRepository.getLocation( ).toString() ).build( );
231             collectRequest.addRepository(repo);
232         }
233         collectRequest.setRequestContext( "project" );
234
235         //collectRequest.addRepository( repo );
236
237         try
238         {
239             CollectResult collectResult = system.collectDependencies( session, collectRequest );
240             collectResult.getRoot().accept( resolveRequest.dependencyVisitor );
241             log.debug("Collected dependency results for resolve");
242         }
243         catch ( DependencyCollectionException e )
244         {
245             log.error( "Error while collecting dependencies (resolve): {}", e.getMessage(), e );
246         }
247
248
249
250     }
251
252     private ManagedRepository findArtifactInRepositories( List<String> repositoryIds, Artifact projectArtifact ) {
253         for ( String repoId : repositoryIds )
254         {
255             ManagedRepository managedRepo = repositoryRegistry.getManagedRepository(repoId);
256             StorageAsset repoDir = managedRepo.getRoot();
257
258             StorageAsset file = pathTranslator.toFile( repoDir, projectArtifact.getGroupId(), projectArtifact.getArtifactId(),
259                                                projectArtifact.getBaseVersion(),
260                                                projectArtifact.getArtifactId() + "-" + projectArtifact.getVersion()
261                                                    + ".pom" );
262
263             if ( file.exists() )
264             {
265                 return managedRepo;
266             }
267             // try with snapshot version
268             if ( StringUtils.endsWith( projectArtifact.getBaseVersion(), VersionUtil.SNAPSHOT ) )
269             {
270                 StorageAsset metadataFile = file.getParent().resolve( MetadataTools.MAVEN_METADATA );
271                 if ( metadataFile.exists() )
272                 {
273                     try
274                     {
275                         ArchivaRepositoryMetadata archivaRepositoryMetadata = metadataReader.read( metadataFile);
276                         int buildNumber = archivaRepositoryMetadata.getSnapshotVersion().getBuildNumber();
277                         String timeStamp = archivaRepositoryMetadata.getSnapshotVersion().getTimestamp();
278                         // rebuild file name with timestamped version and build number
279                         String timeStampFileName =
280                             new StringBuilder( projectArtifact.getArtifactId() ).append( '-' ).append(
281                                 StringUtils.remove( projectArtifact.getBaseVersion(),
282                                                     "-" + VersionUtil.SNAPSHOT ) ).append( '-' ).append(
283                                 timeStamp ).append( '-' ).append( Integer.toString( buildNumber ) ).append(
284                                 ".pom" ).toString();
285                         StorageAsset timeStampFile = file.getParent().resolve( timeStampFileName );
286                         log.debug( "try to find timestamped snapshot version file: {}", timeStampFile);
287                         if ( timeStampFile.exists() )
288                         {
289                             return managedRepo;
290                         }
291                     }
292                     catch ( RepositoryMetadataException e )
293                     {
294                         log.warn( "skip fail to find timestamped snapshot pom: {}", e.getMessage() );
295                     }
296                 }
297             }
298         }
299         return null;
300     }
301
302 }