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 org.apache.log4j.spi.LoggingEvent;
21
22 import java.util.Stack;
23 import java.util.StringTokenizer;
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) {
107 return rule.evaluate(event);
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 StringTokenizer tokenizer = new StringTokenizer(expression);
132
133 while (tokenizer.hasMoreTokens()) {
134
135 String token = tokenizer.nextToken();
136 if ((token.startsWith("'"))
137 && (token.endsWith("'")
138 && (token.length() > 2))) {
139 token = token.substring(1, token.length() - 1);
140 }
141 if ((token.startsWith("'"))
142 && (token.endsWith("'")
143 && (token.length() == 2))) {
144 token = "";
145 }
146
147 boolean inText = token.startsWith("'");
148 if (inText) {
149 token = token.substring(1);
150 while (inText && tokenizer.hasMoreTokens()) {
151 token = token + " " + tokenizer.nextToken();
152 inText = !(token.endsWith("'"));
153 }
154 if (token.length() > 0) {
155 token = token.substring(0, token.length() - 1);
156 }
157 }
158
159
160
161 if (factory.isRule(token)) {
162 Rule r = factory.getRule(token, stack);
163 stack.push(r);
164 } else {
165
166 if (token.length() > 0) {
167 stack.push(token);
168 }
169 }
170 }
171
172 if ((stack.size() == 1) && (!(stack.peek() instanceof Rule))) {
173
174
175
176 Object o = stack.pop();
177 stack.push("MSG");
178 stack.push(o);
179 return factory.getRule("~=", stack);
180 }
181
182
183 if ((stack.size() != 1) || (!(stack.peek() instanceof Rule))) {
184 throw new IllegalArgumentException("invalid expression: " + expression);
185 } else {
186 return (Rule) stack.pop();
187 }
188 }
189 }
190 }
191
192