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.Iterator;
22 import java.util.List;
23 import java.util.Vector;
24
25
26 /***
27 * Makes sure you close your database connections. It does this by
28 * looking for code patterned like this:
29 * <pre>
30 * Connection c = X;
31 * try {
32 * // do stuff, and maybe catch something
33 * } finally {
34 * c.close();
35 * }
36 * </pre>
37 */
38 public class CloseConnection extends AbstractRule {
39
40 public Object visit(ASTCompilationUnit node, Object data) {
41 if (!importsJavaSqlPackage(node)) {
42 return data;
43 }
44 return super.visit(node, data);
45 }
46
47 public Object visit(ASTMethodDeclaration node, Object data) {
48 List vars = node.findChildrenOfType(ASTLocalVariableDeclaration.class);
49 List ids = new Vector();
50
51
52 for (Iterator it = vars.iterator(); it.hasNext();) {
53 ASTLocalVariableDeclaration var = (ASTLocalVariableDeclaration) it.next();
54 ASTType type = (ASTType) var.jjtGetChild(0);
55
56 if (type.jjtGetChild(0) instanceof ASTReferenceType) {
57 ASTReferenceType ref = (ASTReferenceType)type.jjtGetChild(0);
58 if (ref.jjtGetChild(0) instanceof ASTClassOrInterfaceType) {
59 ASTClassOrInterfaceType clazz = (ASTClassOrInterfaceType)ref.jjtGetChild(0);
60 if (clazz.getImage().equals("Connection")) {
61 ASTVariableDeclaratorId id = (ASTVariableDeclaratorId) var.jjtGetChild(1).jjtGetChild(0);
62 ids.add(id);
63 }
64 }
65 }
66 }
67
68
69 for (int i = 0; i < ids.size(); i++) {
70 ASTVariableDeclaratorId x = (ASTVariableDeclaratorId) ids.get(i);
71 ensureClosed((ASTLocalVariableDeclaration) x.jjtGetParent()
72 .jjtGetParent(), x, data);
73 }
74 return data;
75 }
76
77 private void ensureClosed(ASTLocalVariableDeclaration var,
78 ASTVariableDeclaratorId id, Object data) {
79
80
81 String target = id.getImage() + ".close";
82 Node n = var;
83
84 while (!((n = n.jjtGetParent()) instanceof ASTBlock));
85
86 ASTBlock top = (ASTBlock) n;
87
88 List tryblocks = new Vector();
89 top.findChildrenOfType(ASTTryStatement.class, tryblocks, true);
90
91 boolean closed = false;
92
93
94
95
96 for (Iterator it = tryblocks.iterator(); it.hasNext();) {
97 ASTTryStatement t = (ASTTryStatement) it.next();
98
99 if ((t.getBeginLine() > id.getBeginLine()) && (t.hasFinally())) {
100 ASTBlock f = (ASTBlock)t.getFinally().jjtGetChild(0);
101 List names = new ArrayList();
102 f.findChildrenOfType(ASTName.class, names, true);
103 for (Iterator it2 = names.iterator(); it2.hasNext();) {
104 if (((ASTName) it2.next()).getImage().equals(target)) {
105 closed = true;
106 }
107 }
108 }
109 }
110
111
112 if (!closed) {
113 addViolation(data, id);
114 }
115 }
116
117 private boolean importsJavaSqlPackage(ASTCompilationUnit node) {
118 List nodes = node.findChildrenOfType(ASTImportDeclaration.class);
119 for (Iterator i = nodes.iterator(); i.hasNext();) {
120 ASTImportDeclaration n = (ASTImportDeclaration)i.next();
121 if (n.getPackageName().startsWith("java.sql")) {
122 return true;
123 }
124 }
125 return false;
126 }
127
128 }