View Javadoc

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 }