View Javadoc
1   package org.apache.maven.plugins.dependency.tree;
2   
3   /*
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
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
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
19   * under the License.
20   */
21  
22  import org.eclipse.aether.graph.DependencyNode;
23  
24  import java.util.HashMap;
25  import java.util.HashSet;
26  import java.util.LinkedList;
27  import java.util.Map;
28  import java.util.Queue;
29  import java.util.Set;
30  
31  /**
32   * Parses dependency graph and outputs in GraphML format for end user to review.
33   */
34  public class VerboseGraphGraphmlSerializer extends AbstractVerboseGraphSerializer
35  {
36      @Override
37      public String serialize( DependencyNode root )
38      {
39          Set<String> coordinateStrings = new HashSet<>();
40          Map<String, String> coordinateVersionMap = new HashMap<>();
41          Map<DependencyNode, String> nodeErrors = getNodeConflictMessagesBfs( root, coordinateStrings,
42                  coordinateVersionMap );
43  
44          Set<DependencyNode> visitedNodes = new HashSet<>();
45          Queue<DependencyNode> queue = new LinkedList<>();
46          queue.add( root );
47          StringBuilder result = new StringBuilder( "<?xml version=\"1.0\" encoding=\"UTF-8\"?> "
48                  + "<graphml xmlns=\"http://graphml.graphdrawing.org/xmlns\" "
49                  + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
50                  + "xmlns:y=\"http://www.yworks.com/xml/graphml\" "
51                  + "xsi:schemaLocation=\"http://graphml.graphdrawing.org/xmlns "
52                  + "http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd\">"
53                  + "\n"
54                  + "  <key for=\"node\" id=\"d0\" yfiles.type=\"nodegraphics\"/>"
55                  + "\n"
56                  + "  <key for=\"edge\" id=\"d1\" yfiles.type=\"edgegraphics\"/>"
57                  + "\n"
58                  + "<graph id=\"dependencies\" edgedefault=\"directed\">" + "\n" );
59  
60          StringBuilder nodes = new StringBuilder();
61          StringBuilder edges = new StringBuilder();
62          while ( !queue.isEmpty() )
63          {
64              DependencyNode node = queue.poll();
65              nodes.append( getGraphmlNodeLine( node, nodeErrors ) );
66              if ( nodeErrors.get( node ) == null && !node.getArtifact().getProperties().containsKey( "Cycle" ) )
67              {
68                  for ( DependencyNode child : node.getChildren() )
69                  {
70                      if ( !visitedNodes.contains( child ) )
71                      {
72                          visitedNodes.add( child );
73                          queue.add( child );
74                      }
75                      edges.append( getGraphmlEdgeLine( node, child, nodeErrors ) );
76                  }
77              }
78          }
79          result.append( nodes ).append( edges );
80          result.append( "</graph></graphml>" );
81          return result.toString();
82      }
83  
84      private String getGraphmlEdgeLine( DependencyNode parent, DependencyNode child,
85                                         Map<DependencyNode, String> nodeErrors )
86      {
87          StringBuilder builder = new StringBuilder();
88          builder.append( "<edge source=\"" ).append( parent.hashCode() ).append( "\" target=\"" ).append(
89                  child.hashCode() ).append( "\"><data key=\"d1\"><y:PolyLineEdge><y:EdgeLabel>" );
90  
91  
92          boolean messageAdded = false;
93  
94          if ( child.getArtifact().getProperties().containsKey( PRE_MANAGED_SCOPE ) )
95          {
96              messageAdded = true;
97              builder.append( child.getArtifact().getProperties().get( MANAGED_SCOPE ) );
98              builder.append( ", scope managed from " ).append(
99                      child.getArtifact().getProperties().get( PRE_MANAGED_SCOPE ) );
100         }
101         else
102         {
103             builder.append( child.getDependency().getScope() );
104         }
105         if ( child.getArtifact().getProperties().containsKey( "Cycle" ) )
106         {
107             if ( messageAdded )
108             {
109                 builder.append( "," );
110             }
111             builder.append( " omitted due to cycle" );
112         }
113         else if ( nodeErrors.get( child ) != null )
114         {
115             if ( messageAdded )
116             {
117                 builder.append( "," );
118             }
119             builder.append( " " ).append( nodeErrors.get( child ) );
120         }
121         builder.append( "</y:EdgeLabel></y:PolyLineEdge></data></edge>" ).append( "\n" );
122         return builder.toString();
123     }
124 
125     private String getGraphmlNodeLine( DependencyNode node, Map<DependencyNode, String> nodeErrors )
126     {
127         StringBuilder builder = new StringBuilder();
128         builder.append( "<node id=\"" ).append( node.hashCode() ).append(
129                 "\"><data key=\"d0\"><y:ShapeNode>" + "<y:NodeLabel>" );
130 
131         String coordString = "";
132         boolean messageAdded = false;
133 
134         if ( node.getArtifact().getProperties().containsKey( PRE_MANAGED_VERSION ) )
135         {
136             coordString +=
137                     " - version managed from " + node.getArtifact().getProperties().get( PRE_MANAGED_VERSION );
138             messageAdded = true;
139         }
140         if ( node.getArtifact().getProperties().containsKey( PRE_MANAGED_SCOPE ) )
141         {
142             if ( messageAdded )
143             {
144                 coordString += "; ";
145             }
146             else
147             {
148                 coordString += " - ";
149                 messageAdded = true;
150             }
151             coordString +=
152                     "scope managed from " + node.getArtifact().getProperties().get( PRE_MANAGED_SCOPE );
153         }
154         builder.append( getDependencyCoordinate( node ) ).append( coordString );
155         if ( node.getData().containsKey( "ContainsModule" ) )
156         {
157             builder.append( " WARNING: this tree contains a submodule. Once it reaches the submodule will print "
158                     + "in nonVerbose fashion, to see the actual submodule "
159                     + "verbose output refer to the rest of the output" );
160         }
161         if ( node.getArtifact().getProperties().containsKey( "Cycle" ) )
162         {
163             if ( !messageAdded )
164             {
165                 builder.append( " - " );
166             }
167             builder.append( "omitted due to cycle" );
168         }
169         else if ( nodeErrors.get( node ) != null )
170         {
171             if ( !messageAdded )
172             {
173                 builder.append( " - " );
174             }
175             builder.append( nodeErrors.get( node ) );
176         }
177         builder.append( "</y:NodeLabel></y:ShapeNode></data></node>" ).append( "\n" );
178         return builder.toString();
179     }
180 }