[MRM-1615] Artifact detail view

start working on dependency tree tab add a rest service.

git-svn-id: https://svn.apache.org/repos/asf/archiva/trunk@1303921 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Olivier Lamy 2012-03-22 17:52:17 +00:00
parent f1c69d471f
commit 110d011627
5 changed files with 226 additions and 4 deletions

View File

@ -0,0 +1,69 @@
package org.apache.archiva.rest.api.model;
/*
* 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 javax.xml.bind.annotation.XmlRootElement;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* @author Olivier Lamy
*/
@XmlRootElement( name = "treeEntry" )
public class TreeEntry
implements Serializable
{
private List<TreeEntry> childs = new ArrayList<TreeEntry>();
private Artifact artifact;
public TreeEntry()
{
// no op
}
public TreeEntry( Artifact artifact )
{
this.artifact = artifact;
}
public Artifact getArtifact()
{
return artifact;
}
public void setArtifact( Artifact artifact )
{
this.artifact = artifact;
}
public List<TreeEntry> getChilds()
{
return childs;
}
public void setChilds( List<TreeEntry> childs )
{
this.childs = childs;
}
}

View File

@ -21,6 +21,7 @@ package org.apache.archiva.rest.api.services;
import org.apache.archiva.admin.model.beans.ManagedRepository; import org.apache.archiva.admin.model.beans.ManagedRepository;
import org.apache.archiva.metadata.model.ProjectVersionMetadata; import org.apache.archiva.metadata.model.ProjectVersionMetadata;
import org.apache.archiva.rest.api.model.BrowseResult; import org.apache.archiva.rest.api.model.BrowseResult;
import org.apache.archiva.rest.api.model.TreeEntry;
import org.apache.archiva.rest.api.model.VersionsList; import org.apache.archiva.rest.api.model.VersionsList;
import org.codehaus.plexus.redback.authorization.RedbackAuthorization; import org.codehaus.plexus.redback.authorization.RedbackAuthorization;
@ -86,4 +87,13 @@ public interface BrowseService
@RedbackAuthorization( noPermission = true, noRestriction = true ) @RedbackAuthorization( noPermission = true, noRestriction = true )
List<ManagedRepository> getUserRepositories() List<ManagedRepository> getUserRepositories()
throws ArchivaRestServiceException; throws ArchivaRestServiceException;
@Path( "treeEntries/{g}/{a}/{v}" )
@GET
@Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML } )
@RedbackAuthorization( noPermission = true, noRestriction = true )
List<TreeEntry> getTreeEntries( @PathParam( "g" ) String groupId, @PathParam( "a" ) String artifactId,
@PathParam( "v" ) String version,
@QueryParam( "repositoryId" ) String repositoryId )
throws ArchivaRestServiceException;
} }

View File

@ -18,23 +18,31 @@ package org.apache.archiva.rest.services;
* under the License. * under the License.
*/ */
import net.sf.beanlib.provider.replicator.BeanReplicator;
import org.apache.archiva.admin.model.beans.ManagedRepository; import org.apache.archiva.admin.model.beans.ManagedRepository;
import org.apache.archiva.common.utils.VersionComparator; import org.apache.archiva.common.utils.VersionComparator;
import org.apache.archiva.dependency.tree.maven2.DependencyTreeBuilder;
import org.apache.archiva.metadata.model.ProjectVersionMetadata; import org.apache.archiva.metadata.model.ProjectVersionMetadata;
import org.apache.archiva.metadata.repository.MetadataResolutionException; import org.apache.archiva.metadata.repository.MetadataResolutionException;
import org.apache.archiva.metadata.repository.MetadataResolver; import org.apache.archiva.metadata.repository.MetadataResolver;
import org.apache.archiva.metadata.repository.RepositorySession; import org.apache.archiva.metadata.repository.RepositorySession;
import org.apache.archiva.metadata.repository.storage.maven2.MavenProjectFacet; import org.apache.archiva.metadata.repository.storage.maven2.MavenProjectFacet;
import org.apache.archiva.rest.api.model.Artifact;
import org.apache.archiva.rest.api.model.BrowseResult; import org.apache.archiva.rest.api.model.BrowseResult;
import org.apache.archiva.rest.api.model.BrowseResultEntry; import org.apache.archiva.rest.api.model.BrowseResultEntry;
import org.apache.archiva.rest.api.model.TreeEntry;
import org.apache.archiva.rest.api.model.VersionsList; import org.apache.archiva.rest.api.model.VersionsList;
import org.apache.archiva.rest.api.services.ArchivaRestServiceException; import org.apache.archiva.rest.api.services.ArchivaRestServiceException;
import org.apache.archiva.rest.api.services.BrowseService; import org.apache.archiva.rest.api.services.BrowseService;
import org.apache.archiva.security.ArchivaSecurityException; import org.apache.archiva.security.ArchivaSecurityException;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.maven.shared.dependency.tree.DependencyNode;
import org.apache.maven.shared.dependency.tree.DependencyTreeBuilderException;
import org.apache.maven.shared.dependency.tree.traversal.DependencyNodeVisitor;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import javax.inject.Inject;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
@ -53,6 +61,9 @@ public class DefaultBrowseService
implements BrowseService implements BrowseService
{ {
@Inject
private DependencyTreeBuilder dependencyTreeBuilder;
public BrowseResult getRootGroups( String repositoryId ) public BrowseResult getRootGroups( String repositoryId )
throws ArchivaRestServiceException throws ArchivaRestServiceException
{ {
@ -459,6 +470,109 @@ public class DefaultBrowseService
} }
} }
public List<TreeEntry> getTreeEntries( String groupId, String artifactId, String version, String repositoryId )
throws ArchivaRestServiceException
{
List<String> selectedRepos = getObservableRepos();
if ( CollectionUtils.isEmpty( selectedRepos ) )
{
// FIXME 403 ???
return null;
}
if ( StringUtils.isNotEmpty( repositoryId ) )
{
// check user has karma on the repository
if ( !selectedRepos.contains( repositoryId ) )
{
throw new ArchivaRestServiceException( "browse.root.groups.repositoy.denied",
Response.Status.FORBIDDEN.getStatusCode() );
}
selectedRepos = Collections.singletonList( repositoryId );
}
List<TreeEntry> treeEntries = new ArrayList<TreeEntry>();
TreeDependencyNodeVisitor treeDependencyNodeVisitor = new TreeDependencyNodeVisitor( treeEntries );
try
{
dependencyTreeBuilder.buildDependencyTree( selectedRepos, groupId, artifactId, version,
treeDependencyNodeVisitor );
}
catch ( DependencyTreeBuilderException e )
{
throw new ArchivaRestServiceException( e.getMessage(),
Response.Status.INTERNAL_SERVER_ERROR.getStatusCode() );
}
return treeEntries;
}
private static class TreeDependencyNodeVisitor
implements DependencyNodeVisitor
{
final List<TreeEntry> treeEntries;
private TreeEntry currentEntry;
private DependencyNode firstNode;
private TreeDependencyNodeVisitor( List<TreeEntry> treeEntries )
{
this.treeEntries = treeEntries;
}
public boolean visit( DependencyNode node )
{
if ( firstNode == null )
{
firstNode = node;
}
if ( currentEntry == null )
{
currentEntry =
new TreeEntry( new BeanReplicator().replicateBean( node.getArtifact(), Artifact.class ) );
treeEntries.add( currentEntry );
}
else
{
if ( node.getChildren().isEmpty() )
{
currentEntry.getChilds().add(
new TreeEntry( new BeanReplicator().replicateBean( node.getArtifact(), Artifact.class ) ) );
}
}
if ( !node.getChildren().isEmpty() )
{
for ( DependencyNode dependencyNode : (List<DependencyNode>) node.getChildren() )
{
if ( dependencyNode.getChildren().isEmpty() )
{
this.currentEntry.getChilds().add( new TreeEntry(
new BeanReplicator().replicateBean( dependencyNode.getArtifact(), Artifact.class ) ) );
}
else
{
TreeEntry backup = this.currentEntry;
this.currentEntry = new TreeEntry(
new BeanReplicator().replicateBean( dependencyNode.getArtifact(), Artifact.class ) );
visit( dependencyNode );
this.currentEntry = backup;
}
}
}
return true;
}
public boolean endVisit( DependencyNode node )
{
firstNode = null;
return true;
}
}
public List<ManagedRepository> getUserRepositories() public List<ManagedRepository> getUserRepositories()
throws ArchivaRestServiceException throws ArchivaRestServiceException
{ {

View File

@ -202,7 +202,25 @@ $(function() {
mainContent.find("#browse-autocomplete-divider" ).hide(); mainContent.find("#browse-autocomplete-divider" ).hide();
mainContent.find("#artifact-details-tabs").on('show', function (e) { mainContent.find("#artifact-details-tabs").on('show', function (e) {
if ($(e.target).attr("href")=="#artifact-details-dependency-tree-content") { if ($(e.target).attr("href")=="#artifact-details-dependency-tree-content") {
$.log("#artifact-details-dependency-tree-content"); var treeContentDiv=$("#artifact-details-dependency-tree-content" );
//if( $.trim(treeContentDiv.html()).length<1){
treeContentDiv.html(mediumSpinnerImg());
var treeDependencyUrl="restServices/archivaServices/browseService/treeEntries/"+encodeURIComponent(groupId);
treeDependencyUrl+="/"+encodeURIComponent(artifactId);
treeDependencyUrl+="/"+encodeURIComponent(version);
var selectedRepo=getSelectedBrowsingRepository();
if (selectedRepo){
treeDependencyUrl+="?repositoryId="+encodeURIComponent(selectedRepo);
}
var treeDependencyUrl=
$.ajax(treeDependencyUrl, {
type: "GET",
dataType: 'json',
success: function(data) {
treeContentDiv.html($("#dependency_tree_tmpl" ).tmpl({treeEntries: [data[0]]}));
}
});
//}
} }
if ($(e.target).attr("href")=="#artifact-details-used-by-content") { if ($(e.target).attr("href")=="#artifact-details-used-by-content") {
$.log("#artifact-details-used-by-content"); $.log("#artifact-details-used-by-content");
@ -231,6 +249,8 @@ $(function() {
} }
} }
displayArtifactDetail=function(groupId,artifactId,parentBrowseViewModel,restUrl){ displayArtifactDetail=function(groupId,artifactId,parentBrowseViewModel,restUrl){
var artifactDetailViewModel=new ArtifactDetailViewModel(groupId,artifactId); var artifactDetailViewModel=new ArtifactDetailViewModel(groupId,artifactId);
var mainContent = $("#main-content"); var mainContent = $("#main-content");

View File

@ -607,9 +607,7 @@
</table> </table>
</div> </div>
<div id="artifact-details-dependency-tree-content" class="tab-pane"> <div id="artifact-details-dependency-tree-content" class="tab-pane"></div>
dependency tree
</div>
<div id="artifact-details-used-by-content" class="tab-pane"> <div id="artifact-details-used-by-content" class="tab-pane">
used by used by
@ -674,4 +672,15 @@
</div> </div>
</div> </div>
</script>
<script id="dependency_tree_tmpl" type="text/html">
<ul>
{{each(i,treeEntry) treeEntries}}
<li>${treeEntry.artifact.groupId}:${treeEntry.artifact.artifactId}:${treeEntry.artifact.version}</li>
{{if treeEntry.childs.length>0}}
{{tmpl({treeEntries:treeEntry.childs}) "#dependency_tree_tmpl"}}
{{/if}}
{{/each}}
</ul>
</script> </script>