]> source.dussan.org Git - archiva.git/blob
580b91f7aefcba5159c2accb543c05b6845008d8
[archiva.git] /
1 package org.apache.archiva.rest.services;
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  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  */
20
21 import org.apache.archiva.common.utils.VersionComparator;
22 import org.apache.archiva.metadata.model.ProjectVersionMetadata;
23 import org.apache.archiva.metadata.repository.MetadataResolutionException;
24 import org.apache.archiva.metadata.repository.MetadataResolver;
25 import org.apache.archiva.metadata.repository.RepositorySession;
26 import org.apache.archiva.metadata.repository.storage.maven2.MavenProjectFacet;
27 import org.apache.archiva.rest.api.model.BrowseResult;
28 import org.apache.archiva.rest.api.model.BrowseResultEntry;
29 import org.apache.archiva.rest.api.model.VersionsList;
30 import org.apache.archiva.rest.api.services.ArchivaRestServiceException;
31 import org.apache.archiva.rest.api.services.BrowseService;
32 import org.apache.commons.collections.CollectionUtils;
33 import org.apache.commons.lang.StringUtils;
34 import org.springframework.stereotype.Service;
35
36 import javax.ws.rs.core.Response;
37 import java.util.ArrayList;
38 import java.util.Collection;
39 import java.util.Collections;
40 import java.util.LinkedHashSet;
41 import java.util.List;
42 import java.util.Set;
43
44 /**
45  * @author Olivier Lamy
46  * @since 1.4-M3
47  */
48 @Service( "browseService#rest" )
49 public class DefaultBrowseService
50     extends AbstractRestService
51     implements BrowseService
52 {
53
54     public BrowseResult getRootGroups()
55         throws ArchivaRestServiceException
56     {
57         List<String> selectedRepos = getObservableRepos();
58         if ( CollectionUtils.isEmpty( selectedRepos ) )
59         {
60             // FIXME 403 ???
61             return new BrowseResult();
62         }
63
64         Set<String> namespaces = new LinkedHashSet<String>();
65
66         // TODO: this logic should be optional, particularly remembering we want to keep this code simple
67         //       it is located here to avoid the content repository implementation needing to do too much for what
68         //       is essentially presentation code
69         Set<String> namespacesToCollapse;
70         RepositorySession repositorySession = repositorySessionFactory.createSession();
71         try
72         {
73             MetadataResolver metadataResolver = repositorySession.getResolver();
74             namespacesToCollapse = new LinkedHashSet<String>();
75             for ( String repoId : selectedRepos )
76             {
77                 namespacesToCollapse.addAll( metadataResolver.resolveRootNamespaces( repositorySession, repoId ) );
78             }
79             for ( String n : namespacesToCollapse )
80             {
81                 // TODO: check performance of this
82                 namespaces.add( collapseNamespaces( repositorySession, metadataResolver, selectedRepos, n ) );
83             }
84         }
85         catch ( MetadataResolutionException e )
86         {
87             throw new ArchivaRestServiceException( e.getMessage(),
88                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode() );
89         }
90         finally
91         {
92             repositorySession.close();
93         }
94
95         List<BrowseResultEntry> browseGroupResultEntries = new ArrayList<BrowseResultEntry>( namespaces.size() );
96         for ( String namespace : namespaces )
97         {
98             browseGroupResultEntries.add( new BrowseResultEntry( namespace, false ) );
99         }
100
101         Collections.sort( browseGroupResultEntries );
102         return new BrowseResult( browseGroupResultEntries );
103     }
104
105     public BrowseResult browseGroupId( String groupId )
106         throws ArchivaRestServiceException
107     {
108
109         List<String> selectedRepos = getObservableRepos();
110         if ( CollectionUtils.isEmpty( selectedRepos ) )
111         {
112             // FIXME 403 ???
113             return new BrowseResult();
114         }
115
116         Set<String> projects = new LinkedHashSet<String>();
117
118         RepositorySession repositorySession = repositorySessionFactory.createSession();
119         Set<String> namespaces;
120         try
121         {
122             MetadataResolver metadataResolver = repositorySession.getResolver();
123
124             Set<String> namespacesToCollapse = new LinkedHashSet<String>();
125             for ( String repoId : selectedRepos )
126             {
127                 namespacesToCollapse.addAll( metadataResolver.resolveNamespaces( repositorySession, repoId, groupId ) );
128
129                 projects.addAll( metadataResolver.resolveProjects( repositorySession, repoId, groupId ) );
130             }
131
132             // TODO: this logic should be optional, particularly remembering we want to keep this code simple
133             // it is located here to avoid the content repository implementation needing to do too much for what
134             // is essentially presentation code
135             namespaces = new LinkedHashSet<String>();
136             for ( String n : namespacesToCollapse )
137             {
138                 // TODO: check performance of this
139                 namespaces.add(
140                     collapseNamespaces( repositorySession, metadataResolver, selectedRepos, groupId + "." + n ) );
141             }
142         }
143         catch ( MetadataResolutionException e )
144         {
145             throw new ArchivaRestServiceException( e.getMessage(),
146                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode() );
147         }
148         finally
149         {
150             repositorySession.close();
151         }
152         List<BrowseResultEntry> browseGroupResultEntries =
153             new ArrayList<BrowseResultEntry>( namespaces.size() + projects.size() );
154         for ( String namespace : namespaces )
155         {
156             browseGroupResultEntries.add( new BrowseResultEntry( namespace, false ) );
157         }
158         for ( String project : projects )
159         {
160             browseGroupResultEntries.add( new BrowseResultEntry( groupId + '.' + project, true ) );
161         }
162         Collections.sort( browseGroupResultEntries );
163         return new BrowseResult( browseGroupResultEntries );
164
165     }
166
167     public VersionsList getVersionsList( String groupId, String artifactId )
168         throws ArchivaRestServiceException
169     {
170         List<String> selectedRepos = getObservableRepos();
171         if ( CollectionUtils.isEmpty( selectedRepos ) )
172         {
173             // FIXME 403 ???
174             return new VersionsList();
175         }
176
177         try
178         {
179             return new VersionsList( new ArrayList<String>( getVersions( selectedRepos, groupId, artifactId ) ) );
180         }
181         catch ( MetadataResolutionException e )
182         {
183             throw new ArchivaRestServiceException( e.getMessage(),
184                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode() );
185         }
186
187     }
188
189     private Collection<String> getVersions( List<String> selectedRepos, String groupId, String artifactId )
190         throws MetadataResolutionException
191
192     {
193         RepositorySession repositorySession = repositorySessionFactory.createSession();
194         try
195         {
196             MetadataResolver metadataResolver = repositorySession.getResolver();
197
198             Set<String> versions = new LinkedHashSet<String>();
199
200             for ( String repoId : selectedRepos )
201             {
202                 versions.addAll(
203                     metadataResolver.resolveProjectVersions( repositorySession, repoId, groupId, artifactId ) );
204             }
205
206             List<String> sortedVersions = new ArrayList<String>( versions );
207
208             Collections.sort( sortedVersions, VersionComparator.getInstance() );
209
210             return sortedVersions;
211         }
212         finally
213         {
214             repositorySession.close();
215         }
216     }
217
218     public ProjectVersionMetadata getProjectVersionMetadata( String groupId, String artifactId )
219         throws ArchivaRestServiceException
220     {
221
222         List<String> selectedRepos = getObservableRepos();
223
224         if ( CollectionUtils.isEmpty( selectedRepos ) )
225         {
226             // FIXME 403 ???
227             return null;
228         }
229
230         RepositorySession repositorySession = null;
231         try
232         {
233
234             Collection<String> projectVersions = getVersions( selectedRepos, groupId, artifactId );
235
236             repositorySession = repositorySessionFactory.createSession();
237
238             MetadataResolver metadataResolver = repositorySession.getResolver();
239
240             ProjectVersionMetadata sharedModel = new ProjectVersionMetadata();
241
242             MavenProjectFacet mavenFacet = new MavenProjectFacet();
243             mavenFacet.setGroupId( groupId );
244             mavenFacet.setArtifactId( artifactId );
245             sharedModel.addFacet( mavenFacet );
246
247             boolean isFirstVersion = true;
248
249             for ( String version : projectVersions )
250             {
251                 ProjectVersionMetadata versionMetadata = null;
252                 for ( String repoId : selectedRepos )
253                 {
254                     if ( versionMetadata == null )
255                     {
256                         try
257                         {
258                             versionMetadata =
259                                 metadataResolver.resolveProjectVersion( repositorySession, repoId, groupId, artifactId,
260                                                                         version );
261                         }
262                         catch ( MetadataResolutionException e )
263                         {
264                             log.error( "Skipping invalid metadata while compiling shared model for " + groupId + ":"
265                                            + artifactId + " in repo " + repoId + ": " + e.getMessage() );
266                         }
267                     }
268                 }
269
270                 if ( versionMetadata == null )
271                 {
272                     continue;
273                 }
274
275                 if ( isFirstVersion )
276                 {
277                     sharedModel = versionMetadata;
278                     sharedModel.setId( null );
279                 }
280                 else
281                 {
282                     MavenProjectFacet versionMetadataMavenFacet =
283                         (MavenProjectFacet) versionMetadata.getFacet( MavenProjectFacet.FACET_ID );
284                     if ( versionMetadataMavenFacet != null )
285                     {
286                         if ( mavenFacet.getPackaging() != null && !StringUtils.equalsIgnoreCase(
287                             mavenFacet.getPackaging(), versionMetadataMavenFacet.getPackaging() ) )
288                         {
289                             mavenFacet.setPackaging( null );
290                         }
291                     }
292
293                     if ( sharedModel.getName() != null && !StringUtils.equalsIgnoreCase( sharedModel.getName(),
294                                                                                          versionMetadata.getName() ) )
295                     {
296                         sharedModel.setName( "" );
297                     }
298
299                     if ( sharedModel.getDescription() != null && !StringUtils.equalsIgnoreCase(
300                         sharedModel.getDescription(), versionMetadata.getDescription() ) )
301                     {
302                         sharedModel.setDescription( StringUtils.isNotEmpty( versionMetadata.getDescription() )
303                                                         ? versionMetadata.getDescription()
304                                                         : "" );
305                     }
306
307                     if ( sharedModel.getIssueManagement() != null && versionMetadata.getIssueManagement() != null
308                         && !StringUtils.equalsIgnoreCase( sharedModel.getIssueManagement().getUrl(),
309                                                           versionMetadata.getIssueManagement().getUrl() ) )
310                     {
311                         sharedModel.setIssueManagement( null );
312                     }
313
314                     if ( sharedModel.getCiManagement() != null && versionMetadata.getCiManagement() != null
315                         && !StringUtils.equalsIgnoreCase( sharedModel.getCiManagement().getUrl(),
316                                                           versionMetadata.getCiManagement().getUrl() ) )
317                     {
318                         sharedModel.setCiManagement( null );
319                     }
320
321                     if ( sharedModel.getOrganization() != null && versionMetadata.getOrganization() != null
322                         && !StringUtils.equalsIgnoreCase( sharedModel.getOrganization().getName(),
323                                                           versionMetadata.getOrganization().getName() ) )
324                     {
325                         sharedModel.setOrganization( null );
326                     }
327
328                     if ( sharedModel.getUrl() != null && !StringUtils.equalsIgnoreCase( sharedModel.getUrl(),
329                                                                                         versionMetadata.getUrl() ) )
330                     {
331                         sharedModel.setUrl( null );
332                     }
333                 }
334
335                 isFirstVersion = false;
336             }
337             return sharedModel;
338         }
339         catch ( MetadataResolutionException e )
340         {
341             throw new ArchivaRestServiceException( e.getMessage(),
342                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode() );
343         }
344         finally
345         {
346             if ( repositorySession != null )
347             {
348                 repositorySession.close();
349             }
350         }
351     }
352
353     public List<String> getUserRepositories()
354         throws ArchivaRestServiceException
355     {
356         return getObservableRepos();
357     }
358
359     //---------------------------
360     // internals
361     //---------------------------
362
363     private List<String> getSortedList( Set<String> set )
364     {
365         List<String> list = new ArrayList<String>( set );
366         Collections.sort( list );
367         return list;
368     }
369
370     private String collapseNamespaces( RepositorySession repositorySession, MetadataResolver metadataResolver,
371                                        Collection<String> repoIds, String n )
372         throws MetadataResolutionException
373     {
374         Set<String> subNamespaces = new LinkedHashSet<String>();
375         for ( String repoId : repoIds )
376         {
377             subNamespaces.addAll( metadataResolver.resolveNamespaces( repositorySession, repoId, n ) );
378         }
379         if ( subNamespaces.size() != 1 )
380         {
381             log.debug( "{} is not collapsible as it has sub-namespaces: {}", n, subNamespaces );
382             return n;
383         }
384         else
385         {
386             for ( String repoId : repoIds )
387             {
388                 Collection<String> projects = metadataResolver.resolveProjects( repositorySession, repoId, n );
389                 if ( projects != null && !projects.isEmpty() )
390                 {
391                     log.debug( "{} is not collapsible as it has projects", n );
392                     return n;
393                 }
394             }
395             return collapseNamespaces( repositorySession, metadataResolver, repoIds,
396                                        n + "." + subNamespaces.iterator().next() );
397         }
398     }
399 }