001: package com.jeantessier.dependency;
002:
003: import java.util.*;
004:
005: import org.apache.log4j.*;
006:
007: /**
008: * TODO Class comment
009: */
010: public class CycleDetector extends VisitorBase {
011: private LinkedList<Node> currentPath = new LinkedList<Node>();
012: private Collection<Cycle> cycles = new TreeSet<Cycle>(
013: new CycleComparator());
014: private int maximumCycleLength = Integer.MAX_VALUE;
015:
016: public CycleDetector() {
017: }
018:
019: public CycleDetector(SelectionCriteria criteria) {
020: super (new SelectiveTraversalStrategy(criteria,
021: new ComprehensiveSelectionCriteria()));
022: }
023:
024: public Collection<Cycle> getCycles() {
025: return cycles;
026: }
027:
028: public int getMaximumCycleLength() {
029: return maximumCycleLength;
030: }
031:
032: public void setMaximumCycleLength(int maximumCycleLength) {
033: this .maximumCycleLength = maximumCycleLength;
034: }
035:
036: protected void preprocessPackageNode(PackageNode node) {
037: super .preprocessPackageNode(node);
038:
039: pushNodeOnCurrentPath(node);
040: }
041:
042: protected void preprocessAfterDependenciesPackageNode(
043: PackageNode node) {
044: super .preprocessAfterDependenciesPackageNode(node);
045:
046: popNodeFromCurrentPath(node);
047: }
048:
049: public void visitOutboundPackageNode(PackageNode node) {
050: super .visitOutboundPackageNode(node);
051:
052: if (getStrategy().isInFilter(node)) {
053: if (currentPath.getFirst().equals(node)
054: && currentPath.size() <= getMaximumCycleLength()) {
055: addCycle();
056: } else if (!currentPath.contains(node)) {
057: pushNodeOnCurrentPath(node);
058: traverseOutbound(node.getOutboundDependencies());
059: traverseOutbound(node.getClasses());
060: popNodeFromCurrentPath(node);
061: }
062: }
063: }
064:
065: protected void preprocessClassNode(ClassNode node) {
066: super .preprocessClassNode(node);
067:
068: pushNodeOnCurrentPath(node);
069: }
070:
071: protected void preprocessAfterDependenciesClassNode(ClassNode node) {
072: super .preprocessAfterDependenciesClassNode(node);
073:
074: popNodeFromCurrentPath(node);
075: }
076:
077: public void visitOutboundClassNode(ClassNode node) {
078: super .visitOutboundClassNode(node);
079:
080: if (getStrategy().isInFilter(node)) {
081: if (currentPath.getFirst().equals(node)
082: && currentPath.size() <= getMaximumCycleLength()) {
083: addCycle();
084: } else if (!currentPath.contains(node)) {
085: pushNodeOnCurrentPath(node);
086: traverseOutbound(node.getOutboundDependencies());
087: traverseOutbound(node.getFeatures());
088: popNodeFromCurrentPath(node);
089: }
090: }
091: }
092:
093: protected void preprocessFeatureNode(FeatureNode node) {
094: super .preprocessFeatureNode(node);
095:
096: pushNodeOnCurrentPath(node);
097: }
098:
099: protected void postprocessFeatureNode(FeatureNode node) {
100: super .postprocessFeatureNode(node);
101:
102: popNodeFromCurrentPath(node);
103: }
104:
105: public void visitOutboundFeatureNode(FeatureNode node) {
106: super .visitOutboundFeatureNode(node);
107:
108: if (getStrategy().isInFilter(node)) {
109: if (currentPath.getFirst().equals(node)
110: && currentPath.size() <= getMaximumCycleLength()) {
111: addCycle();
112: } else if (!currentPath.contains(node)) {
113: pushNodeOnCurrentPath(node);
114: traverseOutbound(node.getOutboundDependencies());
115: popNodeFromCurrentPath(node);
116: }
117: }
118: }
119:
120: private void addCycle() {
121: Cycle cycle = new Cycle(currentPath);
122: cycles.add(cycle);
123: Logger.getLogger(getClass()).debug("Found cycle " + cycle);
124: }
125:
126: private void pushNodeOnCurrentPath(Node node) {
127: currentPath.addLast(node);
128: Logger.getLogger(getClass()).debug(
129: "Pushed " + node + " on currentPath: " + currentPath);
130: }
131:
132: private void popNodeFromCurrentPath(Node node) {
133: Node popedNode = currentPath.removeLast();
134: Logger.getLogger(getClass()).debug(
135: "Popped " + node + " (" + popedNode
136: + ") from currentPath: " + currentPath);
137: }
138: }
|