1 package org.apache.maven.shared.dependency.tree.traversal;
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 java.io.PrintWriter;
23 import java.io.Writer;
24 import java.util.List;
25
26 import org.apache.maven.shared.dependency.tree.DependencyNode;
27
28 /**
29 * A dependency node visitor that serializes visited nodes to a writer.
30 *
31 * @author <a href="mailto:markhobson@gmail.com">Mark Hobson</a>
32 * @version $Id: SerializingDependencyNodeVisitor.java 1100703 2011-05-08 08:27:33Z hboutemy $
33 * @since 1.1
34 */
35 public class SerializingDependencyNodeVisitor
36 implements DependencyNodeVisitor
37 {
38 // classes ----------------------------------------------------------------
39
40 /**
41 * Provides tokens to use when serializing the dependency tree.
42 */
43 public static class TreeTokens
44 {
45 private final String nodeIndent;
46
47 private final String lastNodeIndent;
48
49 private final String fillIndent;
50
51 private final String lastFillIndent;
52
53 public TreeTokens( String nodeIndent, String lastNodeIndent, String fillIndent, String lastFillIndent )
54 {
55 this.nodeIndent = nodeIndent;
56 this.lastNodeIndent = lastNodeIndent;
57 this.fillIndent = fillIndent;
58 this.lastFillIndent = lastFillIndent;
59 }
60
61 public String getNodeIndent( boolean last )
62 {
63 return last ? lastNodeIndent : nodeIndent;
64 }
65
66 public String getFillIndent( boolean last )
67 {
68 return last ? lastFillIndent : fillIndent;
69 }
70 }
71
72 // constants --------------------------------------------------------------
73
74 /**
75 * Whitespace tokens to use when outputing the dependency tree.
76 */
77 public static final TreeTokens WHITESPACE_TOKENS = new TreeTokens( " ", " ", " ", " " );
78
79 /**
80 * The standard ASCII tokens to use when outputing the dependency tree.
81 */
82 public static final TreeTokens STANDARD_TOKENS = new TreeTokens( "+- ", "\\- ", "| ", " " );
83
84 /**
85 * The extended ASCII tokens to use when outputing the dependency tree.
86 */
87 public static final TreeTokens EXTENDED_TOKENS =
88 new TreeTokens( "\u00c3\u00c4 ", "\u00c0\u00c4 ", "\u00b3 ", " " );
89
90 // fields -----------------------------------------------------------------
91
92 /**
93 * The writer to serialize to.
94 */
95 private final PrintWriter writer;
96
97 /**
98 * The tokens to use when serializing the dependency tree.
99 */
100 private final TreeTokens tokens;
101
102 /**
103 * The depth of the currently visited dependency node.
104 */
105 private int depth;
106
107 // constructors -----------------------------------------------------------
108
109 /**
110 * Creates a dependency node visitor that serializes visited nodes to the specified writer using whitespace tokens.
111 *
112 * @param writer
113 * the writer to serialize to
114 */
115 public SerializingDependencyNodeVisitor( Writer writer )
116 {
117 this( writer, WHITESPACE_TOKENS );
118 }
119
120 /**
121 * Creates a dependency node visitor that serializes visited nodes to the specified writer using the specified
122 * tokens.
123 *
124 * @param writer
125 * the writer to serialize to
126 * @param tokens
127 * the tokens to use when serializing the dependency tree
128 */
129 public SerializingDependencyNodeVisitor( Writer writer, TreeTokens tokens )
130 {
131 if ( writer instanceof PrintWriter )
132 {
133 this.writer = (PrintWriter) writer;
134 }
135 else
136 {
137 this.writer = new PrintWriter( writer, true );
138 }
139
140 this.tokens = tokens;
141
142 depth = 0;
143 }
144
145 // DependencyNodeVisitor methods ------------------------------------------
146
147 /**
148 * {@inheritDoc}
149 */
150 public boolean visit( DependencyNode node )
151 {
152 indent( node );
153
154 writer.println( node.toNodeString() );
155
156 depth++;
157
158 return true;
159 }
160
161 /**
162 * {@inheritDoc}
163 */
164 public boolean endVisit( DependencyNode node )
165 {
166 depth--;
167
168 return true;
169 }
170
171 // private methods --------------------------------------------------------
172
173 /**
174 * Writes the necessary tokens to indent the specified dependency node to this visitor's writer.
175 *
176 * @param node
177 * the dependency node to indent
178 */
179 private void indent( DependencyNode node )
180 {
181 for ( int i = 1; i < depth; i++ )
182 {
183 writer.write( tokens.getFillIndent( isLast( node, i ) ) );
184 }
185
186 if ( depth > 0 )
187 {
188 writer.write( tokens.getNodeIndent( isLast( node ) ) );
189 }
190 }
191
192 /**
193 * Gets whether the specified dependency node is the last of its siblings.
194 *
195 * @param node
196 * the dependency node to check
197 * @return <code>true</code> if the specified dependency node is the last of its last siblings
198 */
199 private boolean isLast( DependencyNode node )
200 {
201 // TODO: remove node argument and calculate from visitor calls only
202
203 DependencyNode parent = node.getParent();
204
205 boolean last;
206
207 if ( parent == null )
208 {
209 last = true;
210 }
211 else
212 {
213 List<DependencyNode> siblings = parent.getChildren();
214
215 last = ( siblings.indexOf( node ) == siblings.size() - 1 );
216 }
217
218 return last;
219 }
220
221 /**
222 * Gets whether the specified dependency node ancestor is the last of its siblings.
223 *
224 * @param node
225 * the dependency node whose ancestor to check
226 * @param ancestorDepth
227 * the depth of the ancestor of the specified dependency node to check
228 * @return <code>true</code> if the specified dependency node ancestor is the last of its siblings
229 */
230 private boolean isLast( DependencyNode node, int ancestorDepth )
231 {
232 // TODO: remove node argument and calculate from visitor calls only
233
234 int distance = depth - ancestorDepth;
235
236 while ( distance-- > 0 )
237 {
238 node = node.getParent();
239 }
240
241 return isLast( node );
242 }
243 }