Clover coverage report - PMD - 3.7 Coverage timestamp: Wed May 31 2006 09:25:59 EDT FRAMES NO FRAMES |
file stats: | LOC: | 140 |  | Methods: | 4
| NCLOC: | 97 |  | Classes: | 1
Source file | Conditionals | Statements | Methods | TOTAL
CloseResource.java | 65.6% | 87.8% | 100% | 80% |

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.ast.ASTBlock;
8 |  | import net.sourceforge.pmd.ast.ASTClassOrInterfaceType;
9 |  | import net.sourceforge.pmd.ast.ASTCompilationUnit;
10 |  | import net.sourceforge.pmd.ast.ASTImportDeclaration;
11 |  | import net.sourceforge.pmd.ast.ASTLocalVariableDeclaration;
12 |  | import net.sourceforge.pmd.ast.ASTMethodDeclaration;
13 |  | import net.sourceforge.pmd.ast.ASTName;
14 |  | import net.sourceforge.pmd.ast.ASTReferenceType;
15 |  | import net.sourceforge.pmd.ast.ASTTryStatement;
16 |  | import net.sourceforge.pmd.ast.ASTType;
17 |  | import net.sourceforge.pmd.ast.ASTVariableDeclaratorId;
18 |  | import net.sourceforge.pmd.ast.Node;
19 |  |
20 |  | import java.util.ArrayList;
21 |  | import java.util.HashSet;
22 |  | import java.util.Iterator;
23 |  | import java.util.List;
24 |  | import java.util.Set;
25 |  | import java.util.StringTokenizer;
26 |  | import java.util.Vector;
27 |  |
28 |  |
29 |  | /**
30 |  | * Makes sure you close your database connections. It does this by
31 |  | * looking for code patterned like this:
32 |  | * <pre>
33 |  | * Connection c = X;
34 |  | * try {
35 |  | * // do stuff, and maybe catch something
36 |  | * } finally {
37 |  | * c.close();
38 |  | * }
39 |  | * </pre>
40 |  | */
41 |  | public class CloseResource extends AbstractRule {
42 |  |
43 |  | private Set types = new HashSet();
44 |  |
45 | 5 | public Object visit(ASTCompilationUnit node, Object data) {
46 | 5 | if (!importsJavaSqlPackage(node)) {
47 | 2 | return data;
48 |  | }
49 | 3 | if (types.isEmpty()) {
50 | 1 | for (StringTokenizer st = new StringTokenizer(getStringProperty("types"), ","); st.hasMoreTokens();) {
51 | 3 | types.add(st.nextToken());
52 |  | }
53 |  | }
54 | 3 | return super.visit(node, data);
55 |  | }
56 |  |
57 | 3 | public Object visit(ASTMethodDeclaration node, Object data) {
58 | 3 | List vars = node.findChildrenOfType(ASTLocalVariableDeclaration.class);
59 | 3 | List ids = new Vector();
60 |  |
61 |  | // find all variable references to Connection objects
62 | 3 | for (Iterator it = vars.iterator(); it.hasNext();) {
63 | 3 | ASTLocalVariableDeclaration var = (ASTLocalVariableDeclaration) it.next();
64 | 3 | ASTType type = (ASTType) var.jjtGetChild(0);
65 |  |
66 | 3 | if (type.jjtGetChild(0) instanceof ASTReferenceType) {
67 | 3 | ASTReferenceType ref = (ASTReferenceType) type.jjtGetChild(0);
68 | 3 | if (ref.jjtGetChild(0) instanceof ASTClassOrInterfaceType) {
69 | 3 | ASTClassOrInterfaceType clazz = (ASTClassOrInterfaceType) ref.jjtGetChild(0);
70 | 3 | if (types.contains(clazz.getImage())) {
71 | 3 | ASTVariableDeclaratorId id = (ASTVariableDeclaratorId) var.jjtGetChild(1).jjtGetChild(0);
72 | 3 | ids.add(id);
73 |  | }
74 |  | }
75 |  | }
76 |  | }
77 |  |
78 |  | // if there are connections, ensure each is closed.
79 | 3 | for (int i = 0; i < ids.size(); i++) {
80 | 3 | ASTVariableDeclaratorId x = (ASTVariableDeclaratorId) ids.get(i);
81 | 3 | ensureClosed((ASTLocalVariableDeclaration) x.jjtGetParent().jjtGetParent(), x, data);
82 |  | }
83 | 3 | return data;
84 |  | }
85 |  |
86 | 3 | private void ensureClosed(ASTLocalVariableDeclaration var,
87 |  | ASTVariableDeclaratorId id, Object data) {
88 |  | // What are the chances of a Connection being instantiated in a
89 |  | // for-loop init block? Anyway, I'm lazy!
90 | 3 | String target = id.getImage() + ".close";
91 | 3 | Node n = var;
92 |  |
93 | ? | while (!((n = n.jjtGetParent()) instanceof ASTBlock)) ;
94 |  |
95 | 3 | ASTBlock top = (ASTBlock) n;
96 |  |
97 | 3 | List tryblocks = new Vector();
98 | 3 | top.findChildrenOfType(ASTTryStatement.class, tryblocks, true);
99 |  |
100 | 3 | boolean closed = false;
101 |  |
102 |  | // look for try blocks below the line the variable was
103 |  | // introduced and make sure there is a .close call in a finally
104 |  | // block.
105 | 3 | for (Iterator it = tryblocks.iterator(); it.hasNext();) {
106 | 3 | ASTTryStatement t = (ASTTryStatement) it.next();
107 |  |
108 | 3 | if ((t.getBeginLine() > id.getBeginLine()) && (t.hasFinally())) {
109 | 0 | ASTBlock f = (ASTBlock) t.getFinally().jjtGetChild(0);
110 | 0 | List names = new ArrayList();
111 | 0 | f.findChildrenOfType(ASTName.class, names, true);
112 | 0 | for (Iterator it2 = names.iterator(); it2.hasNext();) {
113 | 0 | if (((ASTName) it2.next()).getImage().equals(target)) {
114 | 0 | closed = true;
115 |  | }
116 |  | }
117 |  | }
118 |  | }
119 |  |
120 |  | // if all is not well, complain
121 | 3 | if (!closed) {
122 | 3 | ASTType type = (ASTType) var.jjtGetChild(0);
123 | 3 | ASTReferenceType ref = (ASTReferenceType) type.jjtGetChild(0);
124 | 3 | ASTClassOrInterfaceType clazz = (ASTClassOrInterfaceType) ref.jjtGetChild(0);
125 | 3 | addViolation(data, id, clazz.getImage());
126 |  | }
127 |  | }
128 |  |
129 | 5 | private boolean importsJavaSqlPackage(ASTCompilationUnit node) {
130 | 5 | List nodes = node.findChildrenOfType(ASTImportDeclaration.class);
131 | 5 | for (Iterator i = nodes.iterator(); i.hasNext();) {
132 | 4 | ASTImportDeclaration n = (ASTImportDeclaration) i.next();
133 | 4 | if (n.getPackageName().startsWith("java.sql")) {
134 | 3 | return true;
135 |  | }
136 |  | }
137 | 2 | return false;
138 |  | }
139 |  |
140 |  | }