1 package org.apache.archiva.rest.services;
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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
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;
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;
45 * @author Olivier Lamy
48 @Service( "browseService#rest" )
49 public class DefaultBrowseService
50 extends AbstractRestService
51 implements BrowseService
54 public BrowseResult getRootGroups()
55 throws ArchivaRestServiceException
57 List<String> selectedRepos = getObservableRepos();
58 if ( CollectionUtils.isEmpty( selectedRepos ) )
61 return new BrowseResult();
64 Set<String> namespaces = new LinkedHashSet<String>();
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();
73 MetadataResolver metadataResolver = repositorySession.getResolver();
74 namespacesToCollapse = new LinkedHashSet<String>();
75 for ( String repoId : selectedRepos )
77 namespacesToCollapse.addAll( metadataResolver.resolveRootNamespaces( repositorySession, repoId ) );
79 for ( String n : namespacesToCollapse )
81 // TODO: check performance of this
82 namespaces.add( collapseNamespaces( repositorySession, metadataResolver, selectedRepos, n ) );
85 catch ( MetadataResolutionException e )
87 throw new ArchivaRestServiceException( e.getMessage(),
88 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode() );
92 repositorySession.close();
95 List<BrowseResultEntry> browseGroupResultEntries = new ArrayList<BrowseResultEntry>( namespaces.size() );
96 for ( String namespace : namespaces )
98 browseGroupResultEntries.add( new BrowseResultEntry( namespace, false ) );
101 Collections.sort( browseGroupResultEntries );
102 return new BrowseResult( browseGroupResultEntries );
105 public BrowseResult browseGroupId( String groupId )
106 throws ArchivaRestServiceException
109 List<String> selectedRepos = getObservableRepos();
110 if ( CollectionUtils.isEmpty( selectedRepos ) )
113 return new BrowseResult();
116 Set<String> projects = new LinkedHashSet<String>();
118 RepositorySession repositorySession = repositorySessionFactory.createSession();
119 Set<String> namespaces;
122 MetadataResolver metadataResolver = repositorySession.getResolver();
124 Set<String> namespacesToCollapse = new LinkedHashSet<String>();
125 for ( String repoId : selectedRepos )
127 namespacesToCollapse.addAll( metadataResolver.resolveNamespaces( repositorySession, repoId, groupId ) );
129 projects.addAll( metadataResolver.resolveProjects( repositorySession, repoId, groupId ) );
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 )
138 // TODO: check performance of this
140 collapseNamespaces( repositorySession, metadataResolver, selectedRepos, groupId + "." + n ) );
143 catch ( MetadataResolutionException e )
145 throw new ArchivaRestServiceException( e.getMessage(),
146 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode() );
150 repositorySession.close();
152 List<BrowseResultEntry> browseGroupResultEntries =
153 new ArrayList<BrowseResultEntry>( namespaces.size() + projects.size() );
154 for ( String namespace : namespaces )
156 browseGroupResultEntries.add( new BrowseResultEntry( namespace, false ) );
158 for ( String project : projects )
160 browseGroupResultEntries.add( new BrowseResultEntry( groupId + '.' + project, true ) );
162 Collections.sort( browseGroupResultEntries );
163 return new BrowseResult( browseGroupResultEntries );
167 public VersionsList getVersionsList( String groupId, String artifactId )
168 throws ArchivaRestServiceException
170 List<String> selectedRepos = getObservableRepos();
171 if ( CollectionUtils.isEmpty( selectedRepos ) )
174 return new VersionsList();
179 return new VersionsList( new ArrayList<String>( getVersions( selectedRepos, groupId, artifactId ) ) );
181 catch ( MetadataResolutionException e )
183 throw new ArchivaRestServiceException( e.getMessage(),
184 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode() );
189 private Collection<String> getVersions( List<String> selectedRepos, String groupId, String artifactId )
190 throws MetadataResolutionException
193 RepositorySession repositorySession = repositorySessionFactory.createSession();
196 MetadataResolver metadataResolver = repositorySession.getResolver();
198 Set<String> versions = new LinkedHashSet<String>();
200 for ( String repoId : selectedRepos )
203 metadataResolver.resolveProjectVersions( repositorySession, repoId, groupId, artifactId ) );
206 List<String> sortedVersions = new ArrayList<String>( versions );
208 Collections.sort( sortedVersions, VersionComparator.getInstance() );
210 return sortedVersions;
214 repositorySession.close();
218 public ProjectVersionMetadata getProjectVersionMetadata( String groupId, String artifactId )
219 throws ArchivaRestServiceException
222 List<String> selectedRepos = getObservableRepos();
224 if ( CollectionUtils.isEmpty( selectedRepos ) )
230 RepositorySession repositorySession = null;
234 Collection<String> projectVersions = getVersions( selectedRepos, groupId, artifactId );
236 repositorySession = repositorySessionFactory.createSession();
238 MetadataResolver metadataResolver = repositorySession.getResolver();
240 ProjectVersionMetadata sharedModel = new ProjectVersionMetadata();
242 MavenProjectFacet mavenFacet = new MavenProjectFacet();
243 mavenFacet.setGroupId( groupId );
244 mavenFacet.setArtifactId( artifactId );
245 sharedModel.addFacet( mavenFacet );
247 boolean isFirstVersion = true;
249 for ( String version : projectVersions )
251 ProjectVersionMetadata versionMetadata = null;
252 for ( String repoId : selectedRepos )
254 if ( versionMetadata == null )
259 metadataResolver.resolveProjectVersion( repositorySession, repoId, groupId, artifactId,
262 catch ( MetadataResolutionException e )
264 log.error( "Skipping invalid metadata while compiling shared model for " + groupId + ":"
265 + artifactId + " in repo " + repoId + ": " + e.getMessage() );
270 if ( versionMetadata == null )
275 if ( isFirstVersion )
277 sharedModel = versionMetadata;
278 sharedModel.setId( null );
282 MavenProjectFacet versionMetadataMavenFacet =
283 (MavenProjectFacet) versionMetadata.getFacet( MavenProjectFacet.FACET_ID );
284 if ( versionMetadataMavenFacet != null )
286 if ( mavenFacet.getPackaging() != null && !StringUtils.equalsIgnoreCase(
287 mavenFacet.getPackaging(), versionMetadataMavenFacet.getPackaging() ) )
289 mavenFacet.setPackaging( null );
293 if ( sharedModel.getName() != null && !StringUtils.equalsIgnoreCase( sharedModel.getName(),
294 versionMetadata.getName() ) )
296 sharedModel.setName( "" );
299 if ( sharedModel.getDescription() != null && !StringUtils.equalsIgnoreCase(
300 sharedModel.getDescription(), versionMetadata.getDescription() ) )
302 sharedModel.setDescription( StringUtils.isNotEmpty( versionMetadata.getDescription() )
303 ? versionMetadata.getDescription()
307 if ( sharedModel.getIssueManagement() != null && versionMetadata.getIssueManagement() != null
308 && !StringUtils.equalsIgnoreCase( sharedModel.getIssueManagement().getUrl(),
309 versionMetadata.getIssueManagement().getUrl() ) )
311 sharedModel.setIssueManagement( null );
314 if ( sharedModel.getCiManagement() != null && versionMetadata.getCiManagement() != null
315 && !StringUtils.equalsIgnoreCase( sharedModel.getCiManagement().getUrl(),
316 versionMetadata.getCiManagement().getUrl() ) )
318 sharedModel.setCiManagement( null );
321 if ( sharedModel.getOrganization() != null && versionMetadata.getOrganization() != null
322 && !StringUtils.equalsIgnoreCase( sharedModel.getOrganization().getName(),
323 versionMetadata.getOrganization().getName() ) )
325 sharedModel.setOrganization( null );
328 if ( sharedModel.getUrl() != null && !StringUtils.equalsIgnoreCase( sharedModel.getUrl(),
329 versionMetadata.getUrl() ) )
331 sharedModel.setUrl( null );
335 isFirstVersion = false;
339 catch ( MetadataResolutionException e )
341 throw new ArchivaRestServiceException( e.getMessage(),
342 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode() );
346 if ( repositorySession != null )
348 repositorySession.close();
353 public List<String> getUserRepositories()
354 throws ArchivaRestServiceException
356 return getObservableRepos();
359 //---------------------------
361 //---------------------------
363 private List<String> getSortedList( Set<String> set )
365 List<String> list = new ArrayList<String>( set );
366 Collections.sort( list );
370 private String collapseNamespaces( RepositorySession repositorySession, MetadataResolver metadataResolver,
371 Collection<String> repoIds, String n )
372 throws MetadataResolutionException
374 Set<String> subNamespaces = new LinkedHashSet<String>();
375 for ( String repoId : repoIds )
377 subNamespaces.addAll( metadataResolver.resolveNamespaces( repositorySession, repoId, n ) );
379 if ( subNamespaces.size() != 1 )
381 log.debug( "{} is not collapsible as it has sub-namespaces: {}", n, subNamespaces );
386 for ( String repoId : repoIds )
388 Collection<String> projects = metadataResolver.resolveProjects( repositorySession, repoId, n );
389 if ( projects != null && !projects.isEmpty() )
391 log.debug( "{} is not collapsible as it has projects", n );
395 return collapseNamespaces( repositorySession, metadataResolver, repoIds,
396 n + "." + subNamespaces.iterator().next() );