001: package jdepend.framework;
002:
003: import java.util.*;
004:
005: import jdepend.framework.JavaPackage;
006:
007: /**
008: * The <code>DependencyConstraint</code> class is a constraint that tests
009: * whether two package-dependency graphs are equivalent.
010: * <p>
011: * This class is useful for writing package dependency assertions (e.g. JUnit).
012: * For example, the following JUnit test will ensure that the 'ejb' and 'web'
013: * packages only depend upon the 'util' package, and no others:
014: * <p>
015: * <blockquote>
016: *
017: * <pre>
018: *
019: * public void testDependencyConstraint() {
020: *
021: * JDepend jdepend = new JDepend();
022: * jdepend.addDirectory("/path/to/classes");
023: * Collection analyzedPackages = jdepend.analyze();
024: *
025: * DependencyConstraint constraint = new DependencyConstraint();
026: *
027: * JavaPackage ejb = constraint.addPackage("com.xyz.ejb");
028: * JavaPackage web = constraint.addPackage("com.xyz.web");
029: * JavaPackage util = constraint.addPackage("com.xyz.util");
030: *
031: * ejb.dependsUpon(util);
032: * web.dependsUpon(util);
033: *
034: * assertEquals("Dependency mismatch", true, constraint
035: * .match(analyzedPackages));
036: * }
037: * </pre>
038: *
039: * </blockquote>
040: * </p>
041: *
042: * @author <b>Mike Clark</b>
043: * @author Clarkware Consulting, Inc.
044: */
045:
046: public class DependencyConstraint {
047:
048: private HashMap packages;
049:
050: public DependencyConstraint() {
051: packages = new HashMap();
052: }
053:
054: public JavaPackage addPackage(String packageName) {
055: JavaPackage jPackage = (JavaPackage) packages.get(packageName);
056: if (jPackage == null) {
057: jPackage = new JavaPackage(packageName);
058: addPackage(jPackage);
059: }
060: return jPackage;
061: }
062:
063: public void addPackage(JavaPackage jPackage) {
064: if (!packages.containsValue(jPackage)) {
065: packages.put(jPackage.getName(), jPackage);
066: }
067: }
068:
069: public Collection getPackages() {
070: return packages.values();
071: }
072:
073: /**
074: * Indicates whether the specified packages match the
075: * packages in this constraint.
076: *
077: * @return <code>true</code> if the packages match this constraint
078: */
079: public boolean match(Collection expectedPackages) {
080:
081: if (packages.size() == expectedPackages.size()) {
082:
083: for (Iterator i = expectedPackages.iterator(); i.hasNext();) {
084: Object next = i.next();
085: if (next instanceof JavaPackage) {
086: JavaPackage nextPackage = (JavaPackage) next;
087: if (!matchPackage(nextPackage)) {
088: return false;
089: }
090: } else {
091: break;
092: }
093:
094: return true;
095: }
096: }
097:
098: return false;
099: }
100:
101: private boolean matchPackage(JavaPackage expectedPackage) {
102:
103: JavaPackage actualPackage = (JavaPackage) packages
104: .get(expectedPackage.getName());
105:
106: if (actualPackage != null) {
107: if (equalsDependencies(actualPackage, expectedPackage)) {
108: return true;
109: }
110: }
111:
112: return false;
113: }
114:
115: private boolean equalsDependencies(JavaPackage a, JavaPackage b) {
116: return equalsAfferents(a, b) && equalsEfferents(a, b);
117: }
118:
119: private boolean equalsAfferents(JavaPackage a, JavaPackage b) {
120:
121: if (a.equals(b)) {
122:
123: Collection otherAfferents = b.getAfferents();
124:
125: if (a.getAfferents().size() == otherAfferents.size()) {
126: for (Iterator i = a.getAfferents().iterator(); i
127: .hasNext();) {
128: JavaPackage afferent = (JavaPackage) i.next();
129: if (!otherAfferents.contains(afferent)) {
130: return false;
131: }
132: }
133:
134: return true;
135: }
136: }
137:
138: return false;
139: }
140:
141: private boolean equalsEfferents(JavaPackage a, JavaPackage b) {
142:
143: if (a.equals(b)) {
144:
145: Collection otherEfferents = b.getEfferents();
146:
147: if (a.getEfferents().size() == otherEfferents.size()) {
148: for (Iterator i = a.getEfferents().iterator(); i
149: .hasNext();) {
150: JavaPackage efferent = (JavaPackage) i.next();
151: if (!otherEfferents.contains(efferent)) {
152: return false;
153: }
154: }
155:
156: return true;
157: }
158: }
159:
160: return false;
161: }
162: }
|