1 package org.apache.archiva.web.action;
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
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.commons.collections.CollectionUtils;
28 import org.apache.commons.lang.StringUtils;
29 import org.springframework.context.annotation.Scope;
30 import org.springframework.stereotype.Controller;
32 import java.util.ArrayList;
33 import java.util.Collection;
34 import java.util.Collections;
35 import java.util.LinkedHashSet;
36 import java.util.List;
40 * Browse the repository.
42 * @todo implement repository selectors (all or specific repository)
44 @Controller( "browseAction" )
46 public class BrowseAction
47 extends AbstractRepositoryBasedAction
49 private String groupId;
51 private String artifactId;
53 private String repositoryId;
55 private ProjectVersionMetadata sharedModel;
57 private Collection<String> namespaces;
59 private Collection<String> projectIds;
61 private Collection<String> projectVersions;
63 public String browse()
64 throws MetadataResolutionException
66 List<String> selectedRepos = getObservableRepos();
67 if ( CollectionUtils.isEmpty( selectedRepos ) )
69 return GlobalResults.ACCESS_TO_NO_REPOS;
72 Set<String> namespaces = new LinkedHashSet<String>();
74 // TODO: this logic should be optional, particularly remembering we want to keep this code simple
75 // it is located here to avoid the content repository implementation needing to do too much for what
76 // is essentially presentation code
77 Set<String> namespacesToCollapse;
78 RepositorySession repositorySession = repositorySessionFactory.createSession();
81 MetadataResolver metadataResolver = repositorySession.getResolver();
82 namespacesToCollapse = new LinkedHashSet<String>();
83 for ( String repoId : selectedRepos )
85 namespacesToCollapse.addAll( metadataResolver.resolveRootNamespaces( repositorySession, repoId ) );
88 for ( String n : namespacesToCollapse )
90 // TODO: check performance of this
91 namespaces.add( collapseNamespaces( repositorySession, metadataResolver, selectedRepos, n ) );
96 repositorySession.close();
99 this.namespaces = getSortedList( namespaces );
103 private String collapseNamespaces( RepositorySession repositorySession, MetadataResolver metadataResolver,
104 Collection<String> repoIds, String n )
105 throws MetadataResolutionException
107 Set<String> subNamespaces = new LinkedHashSet<String>();
108 for ( String repoId : repoIds )
110 subNamespaces.addAll( metadataResolver.resolveNamespaces( repositorySession, repoId, n ) );
112 if ( subNamespaces.size() != 1 )
114 log.debug( "{} is not collapsible as it has sub-namespaces: {}", n, subNamespaces );
119 for ( String repoId : repoIds )
121 Collection<String> projects = metadataResolver.resolveProjects( repositorySession, repoId, n );
122 if ( projects != null && !projects.isEmpty() )
124 log.debug( "{} is not collapsible as it has projects", n );
128 return collapseNamespaces( repositorySession, metadataResolver, repoIds,
129 n + "." + subNamespaces.iterator().next() );
133 public String browseGroup()
134 throws MetadataResolutionException
136 if ( StringUtils.isEmpty( groupId ) )
139 addActionError( "You must specify a group ID to browse" );
143 List<String> selectedRepos = getObservableRepos();
144 if ( CollectionUtils.isEmpty( selectedRepos ) )
146 return GlobalResults.ACCESS_TO_NO_REPOS;
149 Set<String> projects = new LinkedHashSet<String>();
151 RepositorySession repositorySession = repositorySessionFactory.createSession();
152 Set<String> namespaces;
155 MetadataResolver metadataResolver = repositorySession.getResolver();
157 Set<String> namespacesToCollapse = new LinkedHashSet<String>();
158 for ( String repoId : selectedRepos )
160 namespacesToCollapse.addAll( metadataResolver.resolveNamespaces( repositorySession, repoId, groupId ) );
162 projects.addAll( metadataResolver.resolveProjects( repositorySession, repoId, groupId ) );
165 // TODO: this logic should be optional, particularly remembering we want to keep this code simple
166 // it is located here to avoid the content repository implementation needing to do too much for what
167 // is essentially presentation code
168 namespaces = new LinkedHashSet<String>();
169 for ( String n : namespacesToCollapse )
171 // TODO: check performance of this
173 collapseNamespaces( repositorySession, metadataResolver, selectedRepos, groupId + "." + n ) );
178 repositorySession.close();
181 this.namespaces = getSortedList( namespaces );
182 this.projectIds = getSortedList( projects );
186 private List<String> getSortedList( Set<String> set )
188 List<String> list = new ArrayList<String>( set );
189 Collections.sort( list );
193 public String browseArtifact()
194 throws MetadataResolutionException
196 if ( StringUtils.isEmpty( groupId ) )
199 addActionError( "You must specify a group ID to browse" );
203 if ( StringUtils.isEmpty( artifactId ) )
206 addActionError( "You must specify a artifact ID to browse" );
210 List<String> selectedRepos = getObservableRepos();
211 if ( CollectionUtils.isEmpty( selectedRepos ) )
213 return GlobalResults.ACCESS_TO_NO_REPOS;
216 RepositorySession repositorySession = repositorySessionFactory.createSession();
219 MetadataResolver metadataResolver = repositorySession.getResolver();
221 Set<String> versions = new LinkedHashSet<String>();
222 for ( String repoId : selectedRepos )
225 metadataResolver.resolveProjectVersions( repositorySession, repoId, groupId, artifactId ) );
228 // TODO: sort by known version ordering method
229 this.projectVersions = new ArrayList<String>( versions );
231 populateSharedModel( repositorySession, metadataResolver, selectedRepos, versions );
235 repositorySession.close();
241 private void populateSharedModel( RepositorySession repositorySession, MetadataResolver metadataResolver,
242 Collection<String> selectedRepos, Collection<String> projectVersions )
244 sharedModel = new ProjectVersionMetadata();
246 MavenProjectFacet mavenFacet = new MavenProjectFacet();
247 mavenFacet.setGroupId( groupId );
248 mavenFacet.setArtifactId( artifactId );
249 sharedModel.addFacet( mavenFacet );
251 boolean isFirstVersion = true;
253 for ( String version : projectVersions )
255 ProjectVersionMetadata versionMetadata = null;
256 for ( String repoId : selectedRepos )
258 if ( versionMetadata == null )
263 metadataResolver.resolveProjectVersion( repositorySession, repoId, groupId, artifactId,
266 catch ( MetadataResolutionException e )
269 "Skipping invalid metadata while compiling shared model for " + groupId + ":" + artifactId
270 + " in repo " + repoId + ": " + e.getMessage() );
275 if ( versionMetadata == null )
280 if ( isFirstVersion )
282 sharedModel = versionMetadata;
283 sharedModel.setId( null );
287 MavenProjectFacet versionMetadataMavenFacet =
288 (MavenProjectFacet) versionMetadata.getFacet( MavenProjectFacet.FACET_ID );
289 if ( versionMetadataMavenFacet != null )
291 if ( mavenFacet.getPackaging() != null && !StringUtils.equalsIgnoreCase( mavenFacet.getPackaging(),
292 versionMetadataMavenFacet.getPackaging() ) )
294 mavenFacet.setPackaging( null );
298 if ( sharedModel.getName() != null && !StringUtils.equalsIgnoreCase( sharedModel.getName(),
299 versionMetadata.getName() ) )
301 sharedModel.setName( "" );
304 if ( sharedModel.getDescription() != null && !StringUtils.equalsIgnoreCase(
305 sharedModel.getDescription(), versionMetadata.getDescription() ) )
307 sharedModel.setDescription( null );
310 if ( sharedModel.getIssueManagement() != null && versionMetadata.getIssueManagement() != null
311 && !StringUtils.equalsIgnoreCase( sharedModel.getIssueManagement().getUrl(),
312 versionMetadata.getIssueManagement().getUrl() ) )
314 sharedModel.setIssueManagement( null );
317 if ( sharedModel.getCiManagement() != null && versionMetadata.getCiManagement() != null
318 && !StringUtils.equalsIgnoreCase( sharedModel.getCiManagement().getUrl(),
319 versionMetadata.getCiManagement().getUrl() ) )
321 sharedModel.setCiManagement( null );
324 if ( sharedModel.getOrganization() != null && versionMetadata.getOrganization() != null
325 && !StringUtils.equalsIgnoreCase( sharedModel.getOrganization().getName(),
326 versionMetadata.getOrganization().getName() ) )
328 sharedModel.setOrganization( null );
331 if ( sharedModel.getUrl() != null && !StringUtils.equalsIgnoreCase( sharedModel.getUrl(),
332 versionMetadata.getUrl() ) )
334 sharedModel.setUrl( null );
338 isFirstVersion = false;
342 public String getGroupId()
347 public void setGroupId( String groupId )
349 this.groupId = groupId;
352 public String getArtifactId()
357 public void setArtifactId( String artifactId )
359 this.artifactId = artifactId;
362 public Collection<String> getNamespaces()
367 public String getRepositoryId()
373 public void setRepositoryId( String repositoryId )
376 this.repositoryId = repositoryId;
379 public ProjectVersionMetadata getSharedModel()
384 public Collection<String> getProjectIds()
389 public Collection<String> getProjectVersions()
391 return projectVersions;