1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.log4j.rule;
19
20 import java.util.Map;
21 import java.util.Stack;
22
23 import org.apache.log4j.spi.LoggingEvent;
24
25
26 /***
27 * A Rule class supporting both infix and postfix expressions,
28 * accepting any rule which
29 * is supported by the <code>RuleFactory</code>.
30 *
31 * NOTE: parsing is supported through the use of
32 * <code>StringTokenizer</code>, which
33 * implies two limitations:
34 * 1: all tokens in the expression must be separated by spaces,
35 * including parenthesis
36 * 2: operands which contain spaces MUST be wrapped in single quotes.
37 * For example, the expression:
38 * msg == 'some msg'
39 * is a valid expression.
40 * 3: To group expressions, use parentheses.
41 * For example, the expression:
42 * level >= INFO || ( msg == 'some msg' || logger == 'test' )
43 * is a valid expression.
44 * See org.apache.log4j.rule.InFixToPostFix for a
45 * description of supported operators.
46 * See org.apache.log4j.spi.LoggingEventFieldResolver for field keywords.
47 *
48 * @author Scott Deboy (sdeboy@apache.org)
49 */
50 public class ExpressionRule extends AbstractRule {
51 /***
52 * Serialization ID.
53 */
54 static final long serialVersionUID = 5809121703146893729L;
55 /***
56 * Converter.
57 */
58 private static final InFixToPostFix CONVERTER = new InFixToPostFix();
59 /***
60 * Compiler.
61 */
62 private static final PostFixExpressionCompiler COMPILER =
63 new PostFixExpressionCompiler();
64 /***
65 * Rule.
66 */
67 private final Rule rule;
68
69 /***
70 * Create new instance.
71 * @param r rule
72 */
73 private ExpressionRule(final Rule r) {
74 super();
75 this.rule = r;
76 }
77
78 /***
79 * Get rule.
80 * @param expression expression.
81 * @return rule.
82 */
83 public static Rule getRule(final String expression) {
84 return getRule(expression, false);
85 }
86
87 /***
88 * Get rule.
89 * @param expression expression.
90 * @param isPostFix If post-fix.
91 * @return rule
92 */
93 public static Rule getRule(final String expression,
94 final boolean isPostFix) {
95 String postFix = expression;
96 if (!isPostFix) {
97 postFix = CONVERTER.convert(expression);
98 }
99
100 return new ExpressionRule(COMPILER.compileExpression(postFix));
101 }
102
103 /***
104 * {@inheritDoc}
105 */
106 public boolean evaluate(final LoggingEvent event, Map matches) {
107 return rule.evaluate(event, matches);
108 }
109
110 /***
111 * {@inheritDoc}
112 */
113 public String toString() {
114 return rule.toString();
115 }
116
117 /***
118 * Evaluate a boolean postfix expression.
119 *
120 */
121 static final class PostFixExpressionCompiler {
122 /***
123 * Compile expression.
124 * @param expression expression.
125 * @return rule.
126 */
127 public Rule compileExpression(final String expression) {
128 RuleFactory factory = RuleFactory.getInstance();
129
130 Stack stack = new Stack();
131 InFixToPostFix.CustomTokenizer tokenizer = new InFixToPostFix.CustomTokenizer(expression);
132
133 while (tokenizer.hasMoreTokens()) {
134
135 String token = tokenizer.nextToken();
136 if (token.startsWith("'") || token.startsWith("\"")) {
137 String quoteChar = token.substring(0, 1);
138 token = token.substring(1);
139 while (!token.endsWith(quoteChar) && tokenizer.hasMoreTokens()) {
140 token = token + " " + tokenizer.nextToken();
141 }
142 if (token.length() > 0) {
143 token = token.substring(0, token.length() - 1);
144 }
145 } else {
146
147
148 if (factory.isRule(token)) {
149 Rule r = factory.getRule(token, stack);
150 stack.push(r);
151
152 token = null;
153 }
154 }
155
156 if (token != null && token.length() > 0) {
157 stack.push(token);
158 }
159 }
160
161 if ((stack.size() == 1) && (!(stack.peek() instanceof Rule))) {
162
163
164
165 Object o = stack.pop();
166 stack.push("MSG");
167 stack.push(o);
168 return factory.getRule("~=", stack);
169 }
170
171
172 if ((stack.size() != 1) || (!(stack.peek() instanceof Rule))) {
173 throw new IllegalArgumentException("invalid expression: " + expression);
174 } else {
175 return (Rule) stack.pop();
176 }
177 }
178 }
179 }
180
181