]> source.dussan.org Git - archiva.git/commitdiff
[MRM-1615] Artifact detail view
authorOlivier Lamy <olamy@apache.org>
Thu, 22 Mar 2012 17:52:17 +0000 (17:52 +0000)
committerOlivier Lamy <olamy@apache.org>
Thu, 22 Mar 2012 17:52:17 +0000 (17:52 +0000)
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

archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/model/TreeEntry.java [new file with mode: 0644]
archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/services/BrowseService.java
archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/DefaultBrowseService.java
archiva-modules/archiva-web/archiva-webapp-js/src/main/webapp/js/archiva/search.js
archiva-modules/archiva-web/archiva-webapp-js/src/main/webapp/js/archiva/templates/search.html

diff --git a/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/model/TreeEntry.java b/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/model/TreeEntry.java
new file mode 100644 (file)
index 0000000..6ed3b2f
--- /dev/null
@@ -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;
+    }
+}
index 92091d2edd208b7f52a0179b9a41bd121ee38639..bd9095f191fef884602e8f2bac698201fa96b5d3 100644 (file)
@@ -21,6 +21,7 @@ package org.apache.archiva.rest.api.services;
 import org.apache.archiva.admin.model.beans.ManagedRepository;
 import org.apache.archiva.metadata.model.ProjectVersionMetadata;
 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.codehaus.plexus.redback.authorization.RedbackAuthorization;
 
@@ -86,4 +87,13 @@ public interface BrowseService
     @RedbackAuthorization( noPermission = true, noRestriction = true )
     List<ManagedRepository> getUserRepositories()
         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;
 }
index 6889de8b651006b1a0d931c6461874313b6f7d9f..59a922b98b56ae7815200f8f0d4b012c44abcf10 100644 (file)
@@ -18,23 +18,31 @@ package org.apache.archiva.rest.services;
  * under the License.
  */
 
+import net.sf.beanlib.provider.replicator.BeanReplicator;
 import org.apache.archiva.admin.model.beans.ManagedRepository;
 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.repository.MetadataResolutionException;
 import org.apache.archiva.metadata.repository.MetadataResolver;
 import org.apache.archiva.metadata.repository.RepositorySession;
 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.BrowseResultEntry;
+import org.apache.archiva.rest.api.model.TreeEntry;
 import org.apache.archiva.rest.api.model.VersionsList;
 import org.apache.archiva.rest.api.services.ArchivaRestServiceException;
 import org.apache.archiva.rest.api.services.BrowseService;
 import org.apache.archiva.security.ArchivaSecurityException;
 import org.apache.commons.collections.CollectionUtils;
 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 javax.inject.Inject;
 import javax.ws.rs.core.Response;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -53,6 +61,9 @@ public class DefaultBrowseService
     implements BrowseService
 {
 
+    @Inject
+    private DependencyTreeBuilder dependencyTreeBuilder;
+
     public BrowseResult getRootGroups( String repositoryId )
         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()
         throws ArchivaRestServiceException
     {
index c74476d44f43bf06eac949b9d4a4ee6aabc29025..fc80868332c08c75c2ecc47c0e783c8e43a71441 100644 (file)
@@ -202,7 +202,25 @@ $(function() {
               mainContent.find("#browse-autocomplete-divider" ).hide();
               mainContent.find("#artifact-details-tabs").on('show', function (e) {
                 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") {
                   $.log("#artifact-details-used-by-content");
@@ -231,6 +249,8 @@ $(function() {
     }
   }
 
+
+
   displayArtifactDetail=function(groupId,artifactId,parentBrowseViewModel,restUrl){
     var artifactDetailViewModel=new ArtifactDetailViewModel(groupId,artifactId);
     var mainContent = $("#main-content");
index 5f75fc32c39021c31d03f6c3a9aec16e50f2542b..d10ee5dd9c7f37aa88fd7e18e4a280f8a962c9ab 100644 (file)
         </table>
          </div>
 
-      <div id="artifact-details-dependency-tree-content" class="tab-pane">
-        dependency tree
-      </div>
+      <div id="artifact-details-dependency-tree-content" class="tab-pane"></div>
 
       <div id="artifact-details-used-by-content" class="tab-pane">
         used by
       </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>
\ No newline at end of file