KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sourceforge > pmd > rules > CouplingBetweenObjects


1 /**
2  * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3  */

4 package net.sourceforge.pmd.rules;
5
6 import net.sourceforge.pmd.AbstractRule;
7 import net.sourceforge.pmd.PropertyDescriptor;
8 import net.sourceforge.pmd.ast.ASTClassOrInterfaceDeclaration;
9 import net.sourceforge.pmd.ast.ASTClassOrInterfaceType;
10 import net.sourceforge.pmd.ast.ASTCompilationUnit;
11 import net.sourceforge.pmd.ast.ASTFieldDeclaration;
12 import net.sourceforge.pmd.ast.ASTFormalParameter;
13 import net.sourceforge.pmd.ast.ASTLocalVariableDeclaration;
14 import net.sourceforge.pmd.ast.ASTReferenceType;
15 import net.sourceforge.pmd.ast.ASTResultType;
16 import net.sourceforge.pmd.ast.ASTType;
17 import net.sourceforge.pmd.ast.SimpleNode;
18 import net.sourceforge.pmd.properties.IntegerProperty;
19 import net.sourceforge.pmd.symboltable.ClassScope;
20
21 import java.util.HashSet JavaDoc;
22 import java.util.Map JavaDoc;
23 import java.util.Set JavaDoc;
24
25
26 /**
27  * CouplingBetweenObjects attempts to capture all unique Class attributes,
28  * local variables, and return types to determine how many objects a class is
29  * coupled to. This is only a guage and isn't a hard and fast rule. The threshold
30  * value is configurable and should be determined accordingly
31  *
32  * @author aglover
33  * @since Feb 20, 2003
34  */

35 public class CouplingBetweenObjects extends AbstractRule {
36
37     private int couplingCount;
38     private Set JavaDoc typesFoundSoFar;
39
40     private static final PropertyDescriptor thresholdDescriptor = new IntegerProperty(
41         "threshold", "Coupling threshold value", 2, 1.0f
42         );
43     
44     private static final Map JavaDoc propertyDescriptorsByName = asFixedMap(thresholdDescriptor);
45         
46     
47     public Object JavaDoc visit(ASTCompilationUnit cu, Object JavaDoc data) {
48         typesFoundSoFar = new HashSet JavaDoc();
49         couplingCount = 0;
50
51         Object JavaDoc returnObj = cu.childrenAccept(this, data);
52
53         if (couplingCount > getIntProperty(thresholdDescriptor)) {
54             addViolation(data, cu, "A value of " + couplingCount + " may denote a high amount of coupling within the class");
55         }
56
57         return returnObj;
58     }
59
60     public Object JavaDoc visit(ASTClassOrInterfaceDeclaration node, Object JavaDoc data) {
61         if (node.isInterface()) {
62             return data;
63         }
64         return super.visit(node, data);
65     }
66
67     public Object JavaDoc visit(ASTResultType node, Object JavaDoc data) {
68         for (int x = 0; x < node.jjtGetNumChildren(); x++) {
69             SimpleNode tNode = (SimpleNode) node.jjtGetChild(x);
70             if (tNode instanceof ASTType) {
71                 SimpleNode reftypeNode = (SimpleNode) tNode.jjtGetChild(0);
72                 if (reftypeNode instanceof ASTReferenceType) {
73                     SimpleNode classOrIntType = (SimpleNode) reftypeNode.jjtGetChild(0);
74                     if (classOrIntType instanceof ASTClassOrInterfaceType) {
75                         SimpleNode nameNode = classOrIntType;
76                         this.checkVariableType(nameNode, nameNode.getImage());
77                     }
78                 }
79             }
80         }
81         return super.visit(node, data);
82     }
83
84     public Object JavaDoc visit(ASTLocalVariableDeclaration node, Object JavaDoc data) {
85         handleASTTypeChildren(node);
86         return super.visit(node, data);
87     }
88
89     public Object JavaDoc visit(ASTFormalParameter node, Object JavaDoc data) {
90         handleASTTypeChildren(node);
91         return super.visit(node, data);
92     }
93
94     public Object JavaDoc visit(ASTFieldDeclaration node, Object JavaDoc data) {
95         for (int x = 0; x < node.jjtGetNumChildren(); ++x) {
96             SimpleNode firstStmt = (SimpleNode) node.jjtGetChild(x);
97             if (firstStmt instanceof ASTType) {
98                 ASTType tp = (ASTType) firstStmt;
99                 SimpleNode nd = (SimpleNode) tp.jjtGetChild(0);
100                 checkVariableType(nd, nd.getImage());
101             }
102         }
103
104         return super.visit(node, data);
105     }
106
107     /**
108      * convience method to handle hierarchy. This is probably too much
109      * work and will go away once I figure out the framework
110      */

111     private void handleASTTypeChildren(SimpleNode node) {
112         for (int x = 0; x < node.jjtGetNumChildren(); x++) {
113             SimpleNode sNode = (SimpleNode) node.jjtGetChild(x);
114             if (sNode instanceof ASTType) {
115                 SimpleNode nameNode = (SimpleNode) sNode.jjtGetChild(0);
116                 checkVariableType(nameNode, nameNode.getImage());
117             }
118         }
119     }
120
121     /**
122      * performs a check on the variable and updates the counter. Counter is
123      * instance for a class and is reset upon new class scan.
124      *
125      * @param String variableType
126      */

127     private void checkVariableType(SimpleNode nameNode, String JavaDoc variableType) {
128         // TODO - move this into the symbol table somehow?
129
if (nameNode.getParentsOfType(ASTClassOrInterfaceDeclaration.class).isEmpty()) {
130             return;
131         }
132         //if the field is of any type other than the class type
133
//increment the count
134
ClassScope clzScope = nameNode.getScope().getEnclosingClassScope();
135         if (!clzScope.getClassName().equals(variableType) && (!this.filterTypes(variableType)) && !this.typesFoundSoFar.contains(variableType)) {
136             couplingCount++;
137             typesFoundSoFar.add(variableType);
138         }
139     }
140
141     /**
142      * Filters variable type - we don't want primatives, wrappers, strings, etc.
143      * This needs more work. I'd like to filter out super types and perhaps interfaces
144      *
145      * @param String variableType
146      * @return boolean true if variableType is not what we care about
147      */

148     private boolean filterTypes(String JavaDoc variableType) {
149         return variableType != null && (variableType.startsWith("java.lang.") || (variableType.equals("String")) || filterPrimitivesAndWrappers(variableType));
150     }
151
152     /**
153      * @param String variableType
154      * @return boolean true if variableType is a primative or wrapper
155      */

156     private boolean filterPrimitivesAndWrappers(String JavaDoc variableType) {
157         return (variableType.equals("int") || variableType.equals("Integer") || variableType.equals("char") || variableType.equals("Character") || variableType.equalsIgnoreCase("double") || variableType.equalsIgnoreCase("long") || variableType.equalsIgnoreCase("short") || variableType.equalsIgnoreCase("float") || variableType.equalsIgnoreCase("byte") || variableType.equalsIgnoreCase("boolean"));
158     }
159     
160     /**
161      * @return Map
162      */

163     protected Map JavaDoc propertiesByName() {
164         return propertyDescriptorsByName;
165     }
166 }
167
Popular Tags