View Javadoc

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