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