1
2
3
4 package net.sourceforge.pmd.lang.java.rule.logging;
5
6 import java.util.ArrayList;
7 import java.util.Arrays;
8 import java.util.Collections;
9 import java.util.HashMap;
10 import java.util.List;
11 import java.util.Map;
12 import java.util.Map.Entry;
13
14 import net.sourceforge.pmd.Rule;
15 import net.sourceforge.pmd.lang.ast.Node;
16 import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
17 import net.sourceforge.pmd.lang.java.rule.optimizations.AbstractOptimizationRule;
18 import net.sourceforge.pmd.lang.rule.properties.StringMultiProperty;
19
20 import org.jaxen.JaxenException;
21
22
23
24
25
26
27
28
29
30
31 public class GuardLogStatementRule extends AbstractOptimizationRule implements
32 Rule {
33
34 public static final StringMultiProperty LOG_LEVELS = new StringMultiProperty(
35 "logLevels", "LogLevels to guard", new String[] {}, 1.0f, ',');
36
37 public static final StringMultiProperty GUARD_METHODS = new StringMultiProperty(
38 "guardsMethods", "method use to guard the log statement",
39 new String[] {}, 2.0f, ',');
40
41 protected Map<String, String> guardStmtByLogLevel = new HashMap<String, String>(
42 5);
43
44 private static final String xpathExpression = "//PrimaryPrefix[ends-with(Name/@Image, 'LOG_LEVEL')]"
45 + "[count(../descendant::AdditiveExpression) > 0]"
46 + "[count(ancestor::IfStatement/Expression/descendant::PrimaryExpression["
47 + "ends-with(descendant::PrimaryPrefix/Name/@Image,'GUARD')]) = 0]";
48
49 public GuardLogStatementRule() {
50 definePropertyDescriptor(LOG_LEVELS);
51 definePropertyDescriptor(GUARD_METHODS);
52 }
53
54 @Override
55 public Object visit(ASTCompilationUnit unit, Object data) {
56 extractProperties();
57 findViolationForEachLogStatement(unit, data, xpathExpression);
58 return super.visit(unit, data);
59 }
60
61 protected void findViolationForEachLogStatement(ASTCompilationUnit unit, Object data, String xpathExpression) {
62 for (Entry<String, String> entry : guardStmtByLogLevel.entrySet()) {
63 List<Node> nodes = findViolations(unit, entry.getKey(),
64 entry.getValue(), xpathExpression);
65 for (Node node : nodes) {
66 super.addViolation(data, node);
67 }
68 }
69 }
70
71 @SuppressWarnings("unchecked")
72 private List<Node> findViolations(ASTCompilationUnit unit, String logLevel,
73 String guard, String xpathExpression) {
74 try {
75 return unit.findChildNodesWithXPath(xpathExpression
76 .replaceAll("LOG_LEVEL_UPPERCASE", logLevel.toUpperCase())
77 .replaceAll("LOG_LEVEL", logLevel)
78 .replaceAll("GUARD", guard));
79 } catch (JaxenException e) {
80 e.printStackTrace();
81 }
82 return Collections.EMPTY_LIST;
83 }
84
85 private void setPropertiesDefaultValues(List<String> logLevels,
86 List<String> guardMethods) {
87 logLevels.add("trace");
88 logLevels.add("debug");
89 logLevels.add("info");
90 logLevels.add("warn");
91 logLevels.add("error");
92
93 guardMethods.clear();
94 guardMethods.add("isTraceEnabled");
95 guardMethods.add("isDebugEnabled");
96 guardMethods.add("isInfoEnabled");
97 guardMethods.add("isWarnEnabled");
98 guardMethods.add("isErrorEnabled");
99 }
100
101 protected void extractProperties() {
102 if (guardStmtByLogLevel.isEmpty()) {
103
104 List<String> logLevels = new ArrayList<String>(Arrays.asList(super
105 .getProperty(LOG_LEVELS)));
106 List<String> guardMethods = new ArrayList<String>(
107 Arrays.asList(super.getProperty(GUARD_METHODS)));
108
109 if (guardMethods.isEmpty() && !logLevels.isEmpty()) {
110 throw new IllegalArgumentException(
111 "Can't specify guardMethods without specifiying logLevels.");
112 }
113
114 if (logLevels.isEmpty())
115 setPropertiesDefaultValues(logLevels, guardMethods);
116
117 buildGuardStatementMap(logLevels, guardMethods);
118 }
119 }
120
121 protected void buildGuardStatementMap(List<String> logLevels,
122 List<String> guardMethods) {
123 for (String logLevel : logLevels) {
124 boolean found = false;
125 for (String guardMethod : guardMethods) {
126 if (!found
127 && guardMethod.toLowerCase().contains(
128 logLevel.toLowerCase())) {
129 found = true;
130 guardStmtByLogLevel.put("." + logLevel, guardMethod);
131 }
132 }
133
134 if (!found)
135 throw new IllegalArgumentException(
136 "No guard method associated to the logLevel:"
137 + logLevel + ". Should be something like 'is"
138 + logLevel + "Enabled'.");
139 }
140 }
141 }