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