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
118 try {
119 if (String.class.getMethod("split", new Class[]{String.class}) != null) {
120
121 a = pack.split("//.");
122 }
123 } catch (NoSuchMethodException nsme) {
124
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
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
157 this.level = node;
158 }
159
160
161
162
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
206 this.level = child;
207 return true;
208 }
209 }
210 return false;
211 }
212
213 }