--- /dev/null
+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;
+}
import org.apache.archiva.admin.model.AuditInformation;
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.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.RedbackRequestInformation;
import org.slf4j.Logger;
import org.springframework.context.ApplicationContext;
import javax.inject.Inject;
+import javax.inject.Named;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.core.Context;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Inject
private List<AuditListener> auditListeners = new ArrayList<AuditListener>();
+ @Inject
+ private UserRepositories userRepositories;
+
+
+ @Inject
+ @Named( value = "repositorySessionFactory" )
+ protected RepositorySessionFactory repositorySessionFactory;
+
@Context
protected HttpServletRequest httpServletRequest;
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 )
{
return req.getScheme() + "://" + req.getServerName() + ( req.getServerPort() == 80
--- /dev/null
+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() );
+ }
+ }
+}
@Inject
private ManagedRepositoryAdmin managedRepositoryAdmin;
- @Inject
- private PlexusSisuBridge plexusSisuBridge;
-
@Inject
private RepositoryCommonValidator repositoryCommonValidator;
@Inject
private RepositoryStatisticsManager repositoryStatisticsManager;
- @Inject
- @Named( value = "repositorySessionFactory" )
- protected RepositorySessionFactory repositorySessionFactory;
-
-
public List<ManagedRepository> getManagedRepositories()
throws ArchivaRestServiceException
{
implements SearchService
{
- private Logger log = LoggerFactory.getLogger( getClass() );
@Inject
private RepositorySearch repositorySearch;
- @Inject
- private UserRepositories userRepositories;
-
public List<Artifact> quickSearch( String queryString )
throws ArchivaRestServiceException
{
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 )
{
<ref bean="archivaAdministrationService#default"/>
<ref bean="searchService#rest"/>
<ref bean="commonServices#rest"/>
+ <ref bean="browseService#rest"/>
</jaxrs:serviceBeans>
<jaxrs:outInterceptors>
* under the License.
*/
$(function() {
+
+ BrowseTopViewModel=function(groupIds){
+ this.groupIds=groupIds;
+
+
+ }
+
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(){
~ KIND, either express or implied. See the License for the
~ specific language governing permissions and limitations
~ under the License.
--->
\ No newline at end of file
+-->
+
+<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>
\ No newline at end of file
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 );
return list;
}