View Javadoc

1   package org.apache.onami.configuration.variables;
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.util.ArrayList;
23  import java.util.List;
24  
25  /**
26   * Basic implementation of a tree.
27   *
28   * @param <T>
29   */
30  final class Tree<T>
31  {
32  
33      /** Current tree node data */
34      private T data;
35  
36      /** Parent node */
37      private Tree<T> parent = null;
38  
39      /** Children */
40      private List<Tree<T>> children = new ArrayList<Tree<T>>();
41  
42      /**
43       * Default constructor
44       *
45       * @param data
46       */
47      public Tree( T data )
48      {
49          this.data = data;
50      }
51  
52      /**
53       * @return True if parent is not null
54       */
55      public boolean isRoot()
56      {
57          return parent == null;
58      }
59  
60      /**
61       * @return True if no children
62       */
63      public boolean isLeaf()
64      {
65          return children.isEmpty();
66      }
67  
68      /**
69       * Add a new leaf to this tree
70       *
71       * @param child
72       * @return Tree node of the newly added leaf
73       */
74      public Tree<T> addLeaf( T child )
75      {
76          Tree<T> leaf = new Tree<T>( child );
77          leaf.parent = this;
78          children.add( leaf );
79          return leaf;
80      }
81  
82      /**
83       * @return Parent node, or null if this node is root
84       */
85      public Tree<T> getParent()
86      {
87          return parent;
88      }
89  
90      /**
91       * Remove this tree from its parent, if any.
92       */
93      public void removeFromParent()
94      {
95          if ( !isRoot() )
96          {
97              getParent().removeSubtree( this );
98          }
99      }
100 
101     /**
102      * Remove given subtree
103      *
104      * @param subtree
105      */
106     public void removeSubtree( Tree<T> subtree )
107     {
108         if ( children.remove( subtree ) )
109         {
110             subtree.parent = null;
111         }
112     }
113 
114     /**
115      * @return Node data
116      */
117     public T getData()
118     {
119         return data;
120     }
121 
122     /**
123      *
124      * @return Node depth
125      */
126     public int getDepth()
127     {
128         int depth = 0;
129         Tree<T> curr = parent;
130         while ( curr != null )
131         {
132             curr = curr.parent;
133             depth++;
134         }
135         return depth;
136     }
137 
138     /**
139      * @return Subtrees
140      */
141     public List<Tree<T>> getChildren()
142     {
143         return children;
144     }
145 
146     /**
147      * Add a subtree, provided tree is not modified.
148      *
149      * @param subtree
150      * @return subtree copy added
151      */
152     public Tree<T> addSubtree( Tree<T> subtree )
153     {
154         Tree<T> copy = addLeaf( subtree.data );
155         copy.children = new ArrayList<Tree<T>>( subtree.children );
156         return copy;
157     }
158 
159     /**
160      * @param element
161      * @return true if element is contained in this node subtrees.
162      */
163     public boolean inSubtrees( T element )
164     {
165         for ( Tree<T> child : getChildren() )
166         {
167             if ( child.isElement( element ) || child.inSubtrees( element ) )
168             {
169                 return true;
170             }
171         }
172         return false;
173     }
174 
175     /**
176      * @param element
177      * @return True if element is equal to this node data.
178      */
179     public boolean isElement( T element )
180     {
181         return ( data.equals( element ) );
182     }
183 
184     /**
185      *
186      * @param element
187      * @return true if element is is in the ancestors of this node
188      */
189     public boolean inAncestors( T element )
190     {
191         if ( !isRoot() )
192         {
193             return getParent().isElement( element ) || getParent().inAncestors( element );
194         }
195         return false;
196     }
197 
198     /**
199      * @return Root node, this if current node is root
200      */
201     public Tree<T> getRoot()
202     {
203         if ( isRoot() )
204         {
205             return this;
206         }
207         return getParent().getRoot();
208     }
209 
210     @Override
211     public String toString()
212     {
213         StringBuilder buffer = new StringBuilder();
214         toString( buffer, 0 );
215         return buffer.toString();
216     }
217 
218     private void toString( StringBuilder buffer, int level )
219     {
220         // Create proper indent
221         // Search for next cousins in each level
222         StringBuilder indent = new StringBuilder();
223         Tree<T> prev;
224         Tree<T> curr = this;
225         for ( int i = level - 1; i >= 0; i-- )
226         {
227             prev = curr;
228             curr = prev.parent;
229             if ( i == level - 1 )
230             {
231                 indent.append( " _|" );
232             }
233             else
234             {
235                 indent.append( "  " );
236 
237                 if ( i < level && curr.children.indexOf( prev ) < curr.children.size() - 1 )
238                 {
239                     indent.append( "|" );
240                 }
241                 else
242                 {
243                     indent.append( " " );
244                 }
245             }
246         }
247         buffer.append( indent.reverse() );
248 
249         // Print data
250         buffer.append( getData() ).append( "\n" );
251 
252         // Print subtrees
253         for ( Tree<T> child : getChildren() )
254         {
255             child.toString( buffer, level + 1 );
256         }
257     }
258 
259 }