View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.plugins.dependency.tree;
20  
21  import java.io.IOException;
22  import java.io.UncheckedIOException;
23  import java.io.Writer;
24  import java.util.ArrayList;
25  import java.util.List;
26  
27  import org.apache.maven.shared.dependency.graph.DependencyNode;
28  import org.apache.maven.shared.dependency.graph.traversal.DependencyNodeVisitor;
29  
30  /**
31   * A dependency node visitor that serializes visited nodes to a writer using the
32   * <a href="https://en.wikipedia.org/wiki/Trivial_Graph_Format">TGF format</a>.
33   *
34   * @author <a href="mailto:jerome.creignou@gmail.com">Jerome Creignou</a>
35   * @since 2.1
36   */
37  public class TGFDependencyNodeVisitor extends AbstractSerializingVisitor implements DependencyNodeVisitor {
38  
39      /**
40       * Utility class to write an Edge.
41       *
42       * @author <a href="mailto:jerome.creignou@gmail.com">Jerome Creignou</a>
43       */
44      static final class EdgeAppender {
45          /**
46           * Edge start.
47           */
48          private final DependencyNode from;
49  
50          /**
51           * Edge end.
52           */
53          private final DependencyNode to;
54  
55          /**
56           * Edge label. (optional)
57           */
58          private final String label;
59  
60          /**
61           * Build a new EdgeAppender.
62           *
63           * @param from edge start
64           * @param to edge end
65           * @param label optional label
66           */
67          EdgeAppender(DependencyNode from, DependencyNode to, String label) {
68              super();
69              this.from = from;
70              this.to = to;
71              this.label = label;
72          }
73  
74          /**
75           * Build a string representing the edge.
76           */
77          @Override
78          public String toString() {
79              StringBuilder result = new StringBuilder(generateId(from));
80              result.append(' ').append(generateId(to));
81              if (label != null) {
82                  result.append(' ').append(label);
83              }
84              return result.toString();
85          }
86      }
87  
88      /**
89       * List of edges.
90       */
91      private final List<EdgeAppender> edges = new ArrayList<>();
92  
93      /**
94       * Constructor.
95       *
96       * @param writer the writer to write to
97       */
98      public TGFDependencyNodeVisitor(Writer writer) {
99          super(writer);
100     }
101 
102     /**
103      * {@inheritDoc}
104      */
105     @Override
106     public boolean endVisit(DependencyNode node) {
107         try {
108             if (node.getParent() == null || node.getParent() == node) {
109                 // dump edges on last node endVisit
110                 writer.write("#" + System.lineSeparator());
111                 for (EdgeAppender edge : edges) {
112                     writer.write(edge.toString() + System.lineSeparator());
113                 }
114                 writer.flush();
115             } else {
116                 DependencyNode parent = node.getParent();
117                 // using scope as edge label.
118                 edges.add(new EdgeAppender(parent, node, node.getArtifact().getScope()));
119             }
120             return true;
121         } catch (IOException e) {
122             throw new UncheckedIOException("Failed to write TGF format output", e);
123         }
124     }
125 
126     /**
127      * {@inheritDoc}
128      */
129     @Override
130     public boolean visit(DependencyNode node) {
131         try {
132             // Write node
133             writer.write(generateId(node));
134             writer.write(" ");
135             writer.write(node.toNodeString());
136             writer.write(System.lineSeparator());
137             writer.flush();
138             return true;
139         } catch (IOException e) {
140             throw new UncheckedIOException("Failed to write TGF format output", e);
141         }
142     }
143 
144     /**
145      * Generate a unique id from a DependencyNode.
146      * <p>
147      * Current implementation is rather simple and uses hashcode.
148      * </p>
149      *
150      * @param node the DependencyNode to use
151      * @return the unique id
152      */
153     private static String generateId(DependencyNode node) {
154         return String.valueOf(node.hashCode());
155     }
156 }