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