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