001: package jdepend.framework;
002:
003: import java.util.*;
004:
005: /**
006: * The <code>JavaPackage</code> class represents a Java package.
007: *
008: * @author <b>Mike Clark</b>
009: * @author Clarkware Consulting, Inc.
010: */
011:
012: public class JavaPackage {
013:
014: private String name;
015: private int volatility;
016: private HashSet classes;
017: private List afferents;
018: private List efferents;
019:
020: public JavaPackage(String name) {
021: this (name, 1);
022: }
023:
024: public JavaPackage(String name, int volatility) {
025: this .name = name;
026: setVolatility(volatility);
027: classes = new HashSet();
028: afferents = new ArrayList();
029: efferents = new ArrayList();
030: }
031:
032: public String getName() {
033: return name;
034: }
035:
036: /**
037: * @return The package's volatility (0-1).
038: */
039: public int getVolatility() {
040: return volatility;
041: }
042:
043: /**
044: * @param v Volatility (0-1).
045: */
046: public void setVolatility(int v) {
047: volatility = v;
048: }
049:
050: public boolean containsCycle() {
051: return collectCycle(new ArrayList());
052: }
053:
054: /**
055: * Collects the packages participating in the first package dependency cycle
056: * detected which originates from this package.
057: *
058: * @param list Collecting object to be populated with the list of
059: * JavaPackage instances in a cycle.
060: * @return <code>true</code> if a cycle exist; <code>false</code>
061: * otherwise.
062: */
063: public boolean collectCycle(List list) {
064:
065: if (list.contains(this )) {
066: list.add(this );
067: return true;
068: }
069:
070: list.add(this );
071:
072: for (Iterator i = getEfferents().iterator(); i.hasNext();) {
073: JavaPackage efferent = (JavaPackage) i.next();
074: if (efferent.collectCycle(list)) {
075: return true;
076: }
077: }
078:
079: list.remove(this );
080:
081: return false;
082: }
083:
084: /**
085: * Collects all the packages participating in a package dependency cycle
086: * which originates from this package.
087: * <p>
088: * This is a more exhaustive search than that employed by
089: * <code>collectCycle</code>.
090: *
091: * @param list Collecting object to be populated with the list of
092: * JavaPackage instances in a cycle.
093: * @return <code>true</code> if a cycle exist; <code>false</code>
094: * otherwise.
095: */
096: public boolean collectAllCycles(List list) {
097:
098: if (list.contains(this )) {
099: list.add(this );
100: return true;
101: }
102:
103: list.add(this );
104:
105: boolean containsCycle = false;
106: for (Iterator i = getEfferents().iterator(); i.hasNext();) {
107: JavaPackage efferent = (JavaPackage) i.next();
108: if (efferent.collectAllCycles(list)) {
109: containsCycle = true;
110: }
111: }
112:
113: if (containsCycle) {
114: return true;
115: }
116:
117: list.remove(this );
118: return false;
119: }
120:
121: public void addClass(JavaClass clazz) {
122: classes.add(clazz);
123: }
124:
125: public Collection getClasses() {
126: return classes;
127: }
128:
129: public int getClassCount() {
130: return classes.size();
131: }
132:
133: public int getAbstractClassCount() {
134: int count = 0;
135:
136: for (Iterator i = classes.iterator(); i.hasNext();) {
137: JavaClass clazz = (JavaClass) i.next();
138: if (clazz.isAbstract()) {
139: count++;
140: }
141: }
142:
143: return count;
144: }
145:
146: public int getConcreteClassCount() {
147: int count = 0;
148:
149: for (Iterator i = classes.iterator(); i.hasNext();) {
150: JavaClass clazz = (JavaClass) i.next();
151: if (!clazz.isAbstract()) {
152: count++;
153: }
154: }
155:
156: return count;
157: }
158:
159: /**
160: * Adds the specified Java package as an efferent of this package
161: * and adds this package as an afferent of it.
162: *
163: * @param imported Java package.
164: */
165: public void dependsUpon(JavaPackage imported) {
166: addEfferent(imported);
167: imported.addAfferent(this );
168: }
169:
170: /**
171: * Adds the specified Java package as an afferent of this package.
172: *
173: * @param jPackage Java package.
174: */
175: public void addAfferent(JavaPackage jPackage) {
176: if (!jPackage.getName().equals(getName())) {
177: if (!afferents.contains(jPackage)) {
178: afferents.add(jPackage);
179: }
180: }
181: }
182:
183: public Collection getAfferents() {
184: return afferents;
185: }
186:
187: public void setAfferents(Collection afferents) {
188: this .afferents = new ArrayList(afferents);
189: }
190:
191: public void addEfferent(JavaPackage jPackage) {
192: if (!jPackage.getName().equals(getName())) {
193: if (!efferents.contains(jPackage)) {
194: efferents.add(jPackage);
195: }
196: }
197: }
198:
199: public Collection getEfferents() {
200: return efferents;
201: }
202:
203: public void setEfferents(Collection efferents) {
204: this .efferents = new ArrayList(efferents);
205: }
206:
207: /**
208: * @return The afferent coupling (Ca) of this package.
209: */
210: public int afferentCoupling() {
211: return afferents.size();
212: }
213:
214: /**
215: * @return The efferent coupling (Ce) of this package.
216: */
217: public int efferentCoupling() {
218: return efferents.size();
219: }
220:
221: /**
222: * @return Instability (0-1).
223: */
224: public float instability() {
225:
226: float totalCoupling = (float) efferentCoupling()
227: + (float) afferentCoupling();
228:
229: if (totalCoupling > 0) {
230: return efferentCoupling() / totalCoupling;
231: }
232:
233: return 0;
234: }
235:
236: /**
237: * @return The package's abstractness (0-1).
238: */
239: public float abstractness() {
240:
241: if (getClassCount() > 0) {
242: return (float) getAbstractClassCount()
243: / (float) getClassCount();
244: }
245:
246: return 0;
247: }
248:
249: /**
250: * @return The package's distance from the main sequence (D).
251: */
252: public float distance() {
253: float d = Math.abs(abstractness() + instability() - 1);
254: return d * volatility;
255: }
256:
257: public boolean equals(Object other) {
258: if (other instanceof JavaPackage) {
259: JavaPackage otherPackage = (JavaPackage) other;
260: return otherPackage.getName().equals(getName());
261: }
262: return false;
263: }
264:
265: public int hashCode() {
266: return getName().hashCode();
267: }
268: }
|