View Javadoc

1   package net.sourceforge.pmd.dfa.report;
2   
3   import net.sourceforge.pmd.RuleViolation;
4   
5   import java.util.ArrayList;
6   import java.util.Iterator;
7   import java.util.List;
8   import java.util.StringTokenizer;
9   
10  public class ReportTree {
11  
12      private PackageNode rootNode = new PackageNode("");
13      private AbstractReportNode level;
14  
15      private class TreeIterator implements Iterator {
16  
17          private AbstractReportNode iterNode = rootNode;
18          private boolean hasNextFlag;
19  
20          public void remove() {
21              throw new UnsupportedOperationException();
22          }
23  
24          public boolean hasNext() {
25              this.hasNextFlag = true;
26              return this.getNext() != null;
27          }
28  
29          public Object next() {
30  
31              if (!this.hasNextFlag) {
32                  this.getNext();
33              } else {
34                  this.hasNextFlag = false;
35              }
36  
37              if (this.iterNode instanceof ViolationNode) {
38                  return ((ViolationNode) this.iterNode).getRuleViolation();
39              }
40              return null;
41          }
42  
43          /***
44           * It's some kind of left-right-middle search (postorder).
45           * It always returns only
46           * leafs. The first node he returns is the most left handed leaf he can
47           * found. Now he's looking for siblings and if there are any, he starts
48           * searching for the next most left handed leaf. If there are no
49           * siblings he goes up to his parent and starts looking for siblings.
50           * If there are any he starts searching for the next most left handed
51           * leaf again. And so on ... until he wants to get the parent of the
52           * root node. Because there is no one, the search stops.
53           */
54  
55          private Object getNext() {
56              AbstractReportNode node;
57  
58              while (true) {
59                  if (this.iterNode.isLeaf()) {
60  
61                      while ((node = (this.iterNode).getNextSibling()) == null) {
62  
63                          node = this.iterNode.getParent();
64                          if (node == null) {
65                              return null;
66                          } else {
67                              this.iterNode = node;
68                          }
69                      }
70  
71                      this.iterNode = node;
72                      if (this.iterNode.isLeaf()) {
73                          return this.iterNode;
74                      } else {
75                          continue;
76                      }
77                  } else {
78                      this.iterNode = this.iterNode.getFirstChild();
79                      if (this.iterNode.isLeaf()) {
80                          return this.iterNode;
81                      } else {
82                          continue;
83                      }
84                  }
85              }
86          }
87      }
88  
89  
90      public Iterator iterator() {
91          return new TreeIterator();
92      }
93  
94      public int size() {
95          int count = 0;
96          for (Iterator i = iterator(); i.hasNext();) {
97              i.next();
98              count++;
99          }
100         return count;
101     }
102 
103     public AbstractReportNode getRootNode() {
104         return rootNode;
105     }
106 
107     /***
108      * Adds the RuleViolation to the tree. Splits the package name. Each
109      * package, class and violation gets there own tree node.
110      */
111     public void addRuleViolation(RuleViolation violation) {
112         String pack = violation.getPackageName();
113         String[] a = {};
114         if (pack == null) {
115             a = new String[]{""};
116         } else if (pack.indexOf(".") != -1) {
117             // TODO Remove when minimal runtime support is >= JDK 1.4
118             try {
119                 if (String.class.getMethod("split", new Class[]{String.class}) != null) {
120                     // Compatible with >= JDK 1.4
121                     a = pack.split("//.");
122                 }
123             } catch (NoSuchMethodException nsme) {
124                 // Compatible with < JDK 1.4
125                 StringTokenizer toker = new StringTokenizer(pack, ".");
126                 List parts = new ArrayList();
127                 while (toker.hasMoreTokens()) {
128                     parts.add(toker.nextToken());
129                 }
130                 a = (String[])parts.toArray(new String[parts.size()]);
131             }
132         } else {
133             a = new String[]{pack};
134         }
135 
136         this.level = this.rootNode;
137         String plugedPackageName = "";
138 
139         for (int i = 0; i < a.length; i++) {
140             String packageName = a[i];
141             plugedPackageName += packageName + ".";
142 
143             if (!this.isStringInLevel(plugedPackageName)) {
144                 PackageNode node = new PackageNode(plugedPackageName);
145                 this.level.addFirst(node);
146                 // gotoLevel
147                 this.level = node;
148             }
149         }
150 
151         String cl = violation.getClassName();
152 
153         if (!this.isStringInLevel(cl)) {
154             ClassNode node = new ClassNode(cl);
155             this.level.addFirst(node);
156             // gotoLevel
157             this.level = node;
158         }
159 
160         /*
161          * Filters dublicated rule violations. Like the comparator in
162          * RuleViolation if he already exists.
163          */
164         ViolationNode tmp = new ViolationNode(violation);
165         if (!this.equalsNodeInLevel(this.level, tmp)) {
166             this.level.add(tmp);
167         }
168     }
169     
170     /***
171      * Checks if node is a child of the level node.
172      */
173     private boolean equalsNodeInLevel(AbstractReportNode level, AbstractReportNode node) {
174         for (int i = 0; i < level.getChildCount(); i++) {
175             if ((level.getChildAt(i)).equalsNode(node)) {
176                 return true;
177             }
178         }
179         return false;
180     }
181 
182     /***
183      * Checks if the packageName or the className is a child of the current
184      * (this.level) node. If it's true, the current node changes to the
185      * child node.
186      */
187     private boolean isStringInLevel(String str) {
188 
189         for (int i = 0; i < this.level.getChildCount(); i++) {
190             AbstractReportNode child = this.level.getChildAt(i);
191             String tmp = null;
192 
193             if (child instanceof PackageNode) {
194                 tmp = ((PackageNode) child).getPackageName();
195             }
196             if (child instanceof ClassNode) {
197                 tmp = ((ClassNode) child).getClassName();
198             }
199 
200             if (tmp == null) {
201                 return false;
202             }
203 
204             if (tmp.equals(str)) {
205                 // goto level
206                 this.level = child;
207                 return true;
208             }
209         }
210         return false;
211     }
212 
213 }