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 }