[MRM-1573] start work on browse screen

git-svn-id: https://svn.apache.org/repos/asf/archiva/trunk@1244606 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Olivier Lamy 2012-02-15 17:42:55 +00:00
parent dc0f7bd90d
commit f6ec5a7e86
9 changed files with 270 additions and 50 deletions

View File

@ -0,0 +1,43 @@
package org.apache.archiva.rest.api.services;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import org.apache.archiva.rest.api.model.GroupIdList;
import org.codehaus.plexus.redback.authorization.RedbackAuthorization;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import java.util.List;
/**
* @author Olivier Lamy
* @since 1.4-M3
*/
@Path( "/browseService/" )
public interface BrowseService
{
@Path( "rootGroups" )
@GET
@Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML } )
@RedbackAuthorization( noRestriction = true, noPermission = false )
GroupIdList getRootGroups()
throws ArchivaRestServiceException;
}

View File

@ -20,8 +20,14 @@ package org.apache.archiva.rest.services;
import org.apache.archiva.admin.model.AuditInformation; import org.apache.archiva.admin.model.AuditInformation;
import org.apache.archiva.audit.AuditListener; import org.apache.archiva.audit.AuditListener;
import org.apache.archiva.metadata.repository.RepositorySessionFactory;
import org.apache.archiva.security.AccessDeniedException;
import org.apache.archiva.security.ArchivaSecurityException;
import org.apache.archiva.security.PrincipalNotFoundException;
import org.apache.archiva.security.UserRepositories;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.codehaus.plexus.redback.users.User; import org.codehaus.plexus.redback.users.User;
import org.codehaus.plexus.redback.users.UserManager;
import org.codehaus.redback.rest.services.RedbackAuthenticationThreadLocal; import org.codehaus.redback.rest.services.RedbackAuthenticationThreadLocal;
import org.codehaus.redback.rest.services.RedbackRequestInformation; import org.codehaus.redback.rest.services.RedbackRequestInformation;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -29,9 +35,11 @@ import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.core.Context; import javax.ws.rs.core.Context;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -50,6 +58,14 @@ public abstract class AbstractRestService
@Inject @Inject
private List<AuditListener> auditListeners = new ArrayList<AuditListener>(); private List<AuditListener> auditListeners = new ArrayList<AuditListener>();
@Inject
private UserRepositories userRepositories;
@Inject
@Named( value = "repositorySessionFactory" )
protected RepositorySessionFactory repositorySessionFactory;
@Context @Context
protected HttpServletRequest httpServletRequest; protected HttpServletRequest httpServletRequest;
@ -71,6 +87,39 @@ public abstract class AbstractRestService
this.auditListeners = auditListeners; this.auditListeners = auditListeners;
} }
protected List<String> getObservableRepos()
{
try
{
List<String> ids = userRepositories.getObservableRepositoryIds( getPrincipal() );
return ids == null ? Collections.<String>emptyList() : ids;
}
catch ( PrincipalNotFoundException e )
{
log.warn( e.getMessage(), e );
}
catch ( AccessDeniedException e )
{
log.warn( e.getMessage(), e );
}
catch ( ArchivaSecurityException e )
{
log.warn( e.getMessage(), e );
}
return Collections.emptyList();
}
protected String getPrincipal()
{
RedbackRequestInformation redbackRequestInformation = RedbackAuthenticationThreadLocal.get();
return redbackRequestInformation == null
? UserManager.GUEST_USERNAME
: ( redbackRequestInformation.getUser() == null
? UserManager.GUEST_USERNAME
: redbackRequestInformation.getUser().getUsername() );
}
protected String getBaseUrl( HttpServletRequest req ) protected String getBaseUrl( HttpServletRequest req )
{ {
return req.getScheme() + "://" + req.getServerName() + ( req.getServerPort() == 80 return req.getScheme() + "://" + req.getServerName() + ( req.getServerPort() == 80

View File

@ -0,0 +1,133 @@
package org.apache.archiva.rest.services;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import org.apache.archiva.metadata.repository.MetadataResolutionException;
import org.apache.archiva.metadata.repository.MetadataResolver;
import org.apache.archiva.metadata.repository.RepositorySession;
import org.apache.archiva.rest.api.model.GroupIdList;
import org.apache.archiva.rest.api.services.ArchivaRestServiceException;
import org.apache.archiva.rest.api.services.BrowseService;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Service;
import javax.ws.rs.core.Response;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
/**
* @author Olivier Lamy
* @since 1.4-M3
*/
@Service( "browseService#rest" )
public class DefaultBrowseService
extends AbstractRestService
implements BrowseService
{
public GroupIdList getRootGroups()
throws ArchivaRestServiceException
{
List<String> selectedRepos = getObservableRepos();
if ( CollectionUtils.isEmpty( selectedRepos ) )
{
// FIXME 403 ???
return new GroupIdList( Collections.<String>emptyList() );
}
Set<String> namespaces = new LinkedHashSet<String>();
// TODO: this logic should be optional, particularly remembering we want to keep this code simple
// it is located here to avoid the content repository implementation needing to do too much for what
// is essentially presentation code
Set<String> namespacesToCollapse;
RepositorySession repositorySession = repositorySessionFactory.createSession();
try
{
MetadataResolver metadataResolver = repositorySession.getResolver();
namespacesToCollapse = new LinkedHashSet<String>();
for ( String repoId : selectedRepos )
{
namespacesToCollapse.addAll( metadataResolver.resolveRootNamespaces( repositorySession, repoId ) );
}
for ( String n : namespacesToCollapse )
{
// TODO: check performance of this
namespaces.add( collapseNamespaces( repositorySession, metadataResolver, selectedRepos, n ) );
}
}
catch ( MetadataResolutionException e )
{
throw new ArchivaRestServiceException( e.getMessage(),
Response.Status.INTERNAL_SERVER_ERROR.getStatusCode() );
}
finally
{
repositorySession.close();
}
return new GroupIdList( getSortedList( namespaces ) );
}
//---------------------------
// internals
//---------------------------
private List<String> getSortedList( Set<String> set )
{
List<String> list = new ArrayList<String>( set );
Collections.sort( list );
return list;
}
private String collapseNamespaces( RepositorySession repositorySession, MetadataResolver metadataResolver,
Collection<String> repoIds, String n )
throws MetadataResolutionException
{
Set<String> subNamespaces = new LinkedHashSet<String>();
for ( String repoId : repoIds )
{
subNamespaces.addAll( metadataResolver.resolveNamespaces( repositorySession, repoId, n ) );
}
if ( subNamespaces.size() != 1 )
{
log.debug( "{} is not collapsible as it has sub-namespaces: {}", n, subNamespaces );
return n;
}
else
{
for ( String repoId : repoIds )
{
Collection<String> projects = metadataResolver.resolveProjects( repositorySession, repoId, n );
if ( projects != null && !projects.isEmpty() )
{
log.debug( "{} is not collapsible as it has projects", n );
return n;
}
}
return collapseNamespaces( repositorySession, metadataResolver, repoIds,
n + "." + subNamespaces.iterator().next() );
}
}
}

View File

@ -56,20 +56,12 @@ public class DefaultManagedRepositoriesService
@Inject @Inject
private ManagedRepositoryAdmin managedRepositoryAdmin; private ManagedRepositoryAdmin managedRepositoryAdmin;
@Inject
private PlexusSisuBridge plexusSisuBridge;
@Inject @Inject
private RepositoryCommonValidator repositoryCommonValidator; private RepositoryCommonValidator repositoryCommonValidator;
@Inject @Inject
private RepositoryStatisticsManager repositoryStatisticsManager; private RepositoryStatisticsManager repositoryStatisticsManager;
@Inject
@Named( value = "repositorySessionFactory" )
protected RepositorySessionFactory repositorySessionFactory;
public List<ManagedRepository> getManagedRepositories() public List<ManagedRepository> getManagedRepositories()
throws ArchivaRestServiceException throws ArchivaRestServiceException
{ {

View File

@ -61,14 +61,10 @@ public class DefaultSearchService
implements SearchService implements SearchService
{ {
private Logger log = LoggerFactory.getLogger( getClass() );
@Inject @Inject
private RepositorySearch repositorySearch; private RepositorySearch repositorySearch;
@Inject
private UserRepositories userRepositories;
public List<Artifact> quickSearch( String queryString ) public List<Artifact> quickSearch( String queryString )
throws ArchivaRestServiceException throws ArchivaRestServiceException
{ {
@ -180,40 +176,6 @@ public class DefaultSearchService
return null; //To change body of implemented methods use File | Settings | File Templates. return null; //To change body of implemented methods use File | Settings | File Templates.
} }
protected List<String> getObservableRepos()
{
try
{
List<String> ids = userRepositories.getObservableRepositoryIds( getPrincipal() );
return ids == null ? Collections.<String>emptyList() : ids;
}
catch ( PrincipalNotFoundException e )
{
log.warn( e.getMessage(), e );
}
catch ( AccessDeniedException e )
{
log.warn( e.getMessage(), e );
}
catch ( ArchivaSecurityException e )
{
log.warn( e.getMessage(), e );
}
return Collections.emptyList();
}
protected String getPrincipal()
{
RedbackRequestInformation redbackRequestInformation = RedbackAuthenticationThreadLocal.get();
return redbackRequestInformation == null
? UserManager.GUEST_USERNAME
: ( redbackRequestInformation.getUser() == null
? UserManager.GUEST_USERNAME
: redbackRequestInformation.getUser().getUsername() );
}
protected List<Artifact> getArtifacts( SearchResults searchResults ) protected List<Artifact> getArtifacts( SearchResults searchResults )
{ {

View File

@ -58,6 +58,7 @@
<ref bean="archivaAdministrationService#default"/> <ref bean="archivaAdministrationService#default"/>
<ref bean="searchService#rest"/> <ref bean="searchService#rest"/>
<ref bean="commonServices#rest"/> <ref bean="commonServices#rest"/>
<ref bean="browseService#rest"/>
</jaxrs:serviceBeans> </jaxrs:serviceBeans>
<jaxrs:outInterceptors> <jaxrs:outInterceptors>

View File

@ -17,8 +17,29 @@
* under the License. * under the License.
*/ */
$(function() { $(function() {
BrowseTopViewModel=function(groupIds){
this.groupIds=groupIds;
}
displayBrowse=function(){ displayBrowse=function(){
$("#main-content" ).html("coming soon :-)"); var mainContent = $("#main-content");
mainContent.html(mediumSpinnerImg());
$.ajax("restServices/archivaServices/browseService/rootGroups", {
type: "GET",
dataType: 'json',
success: function(data) {
var groupdIds = $.map(data.groupIdList.groupIds,function(item){
return item;
});
$.log("size:"+groupdIds.length);
var browseTopViewModel = new BrowseTopViewModel(groupdIds);
mainContent.html($("#browse-tmpl" ).tmpl());
ko.applyBindings(browseTopViewModel,mainContent.find("#browse_result" ).get(0));
}
});
} }
displaySearch=function(){ displaySearch=function(){

View File

@ -16,3 +16,22 @@
~ specific language governing permissions and limitations ~ specific language governing permissions and limitations
~ under the License. ~ under the License.
--> -->
<script id="browse-tmpl" type="text/html">
<div>
<div class="page-header">
<h2>${$.i18n.prop('browse.groups')}</h2>
</div>
</div>
<div id="browse_result" data-bind='template:{name:"browse-top-tmpl"}'>
</div>
</script>
<script id="browse-top-tmpl" type="text/html">
<ul>
{{each(i,groupId) groupIds}}
<li>${groupId}</li>
{{/each}}
</ul>
</script>

View File

@ -183,9 +183,9 @@ public class BrowseAction
return SUCCESS; return SUCCESS;
} }
private ArrayList<String> getSortedList( Set<String> set ) private List<String> getSortedList( Set<String> set )
{ {
ArrayList<String> list = new ArrayList<String>( set ); List<String> list = new ArrayList<String>( set );
Collections.sort( list ); Collections.sort( list );
return list; return list;
} }