KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > mr > api > jms > selector > syntax > Selector


1 /*
2  * Copyright 2002 by
3  * <a HREF="http://www.coridan.com">Coridan</a>
4  * <a HREF="mailto: support@coridan.com ">support@coridan.com</a>
5  *
6  * The contents of this file are subject to the Mozilla Public License Version
7  * 1.1 (the "License"); you may not use this file except in compliance with the
8  * License. You may obtain a copy of the License at
9  * http://www.mozilla.org/MPL/
10  *
11  * Software distributed under the License is distributed on an "AS IS" basis,
12  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13  * for the specific language governing rights and limitations under the
14  * License.
15  *
16  * The Original Code is "MantaRay" (TM).
17  *
18  * The Initial Developer of the Original Code is Coridan.
19  * Portions created by the Initial Developer are Copyright (C) 2006
20  * Coridan Inc. All Rights Reserved.
21  *
22  * Contributor(s): all the names of the contributors are added in the source
23  * code where applicable.
24  *
25  * Alternatively, the contents of this file may be used under the terms of the
26  * LGPL license (the "GNU LESSER GENERAL PUBLIC LICENSE"), in which case the
27  * provisions of LGPL are applicable instead of those above. If you wish to
28  * allow use of your version of this file only under the terms of the LGPL
29  * License and not to allow others to use your version of this file under
30  * the MPL, indicate your decision by deleting the provisions above and
31  * replace them with the notice and other provisions required by the LGPL.
32  * If you do not delete the provisions above, a recipient may use your version
33  * of this file under either the MPL or the GNU LESSER GENERAL PUBLIC LICENSE.
34  
35  *
36  * This library is free software; you can redistribute it and/or modify it
37  * under the terms of the MPL as stated above or under the terms of the GNU
38  * Lesser General Public License as published by the Free Software Foundation;
39  * either version 2.1 of the License, or any later version.
40  *
41  * This library is distributed in the hope that it will be useful, but WITHOUT
42  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
43  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
44  * License for more details.
45  */

46 package org.mr.api.jms.selector.syntax;
47
48 import java.io.StringReader JavaDoc;
49
50 import javax.jms.InvalidSelectorException JavaDoc;
51 import javax.jms.Message JavaDoc;
52
53 import org.mr.api.jms.selector.parser.SelectorLexer;
54 import org.mr.api.jms.selector.parser.SelectorParser;
55 import org.mr.api.jms.selector.parser.SelectorTreeParser;
56
57
58 /**
59  * This class enables messages to be filtered using a message selector.
60  * This is a String whose syntax is based on a subset of the SQL92
61  * conditional expression syntax.
62  *
63  * A selector can contain:
64  * <ul>
65  * <li>Literals:</li>
66  * <ul>
67  * <li>A string literal is enclosed in single quotes with an included
68  * single quote represented by doubled single quote such as 'literal'
69  * and 'literal''s'; like Java <i>String</i> literals these use the
70  * unicode character encoding.
71  * </li>
72  * <li>An exact numeric literal is a numeric value without a decimal point
73  * such as 57, -957, +62; numbers in the range of Java <i>long</i> are
74  * supported. Exact numeric literals use the Java integer literal syntax.
75  * </li>
76  * <li>An approximate numeric literal is a numeric value in scientific
77  * notation such as 7E3, -57.9E2 or a numeric value with a decimal such
78  * as 7., -95.7, +6.2; numbers in the range of Java <i>double</i>
79  * are supported. Approximate literals use the Java floating point
80  * literal syntax.
81  * </li>
82  * <li>The boolean literals <i>TRUE </i>and <i>FALSE</i>.</li>
83  * </ul>
84  * <li>Identifiers:</li>
85  * <ul>
86  * <li>Identifiers use the Java identifier syntax. They are case sensitive.
87  * </li>
88  * <li>Identifiers cannot be the names <i>NULL</i>, <i>TRUE</i>, or
89  * <i>FALSE</i>.
90  * </li>
91  * <li>Identifiers cannot be <i>NOT, AND, OR, BETWEEN, LIKE, IN</i>, and
92  * <i>IS</i>.
93  * </li>
94  * <li>Identifiers are either header field references or property references.
95  * </li>
96  * <br>Message header field references are restricted to
97  * <i>JMSDeliveryMode</i>, <i>JMSPriority</i>, <i>JMSMessageID</i>,
98  * <i>JMSTimestamp</i>, <i>JMSCorrelationID</i>, and <i>JMSType</i>.
99  * <i>JMSMessageID</i>, <i>JMSCorrelationID</i>, and <i>JMSType</i>
100  * values may be <i>null</i> and if so are treated as a NULL value.
101  * <li>Any name beginning with 'JMSX' is a JMS defined property name.</li>
102  * <li>Any name beginning with 'JMS_' is a provider-specific property name.
103  * </li>
104  * <li>Any name that does not begin with 'JMS' is an application-specific
105  * property name. If a property is referenced that does not exist in a
106  * message its value is NULL. If it does exist, its value is the
107  * corresponding property value.
108  * </li>
109  * </ul>
110  * <li>Expressions:</li>
111  * <ul>
112  * <li>A selector is a conditional expression; a selector that evaluates to
113  * true matches; a selector that evaluates to false or unknown does not
114  * match.
115  * </li>
116  * <li>Arithmetic expressions are composed of themselves, arithmetic
117  * operations, identifiers with numeric values and numeric literals.
118  * </li>
119  * <li>Conditional expressions are composed of themselves, comparison
120  * operations, logical operations, identifiers with boolean values and
121  * boolean literals.
122  * </li>
123  * <li>Standard bracketing () for ordering expression evaluation is
124  * supported.
125  * </li>
126  * <li>Logical operators in precedence order: NOT, AND, OR.</li>
127  * <li>Comparison operators: =, >, >=, &lt;, &lt;=, &lt;> (not equal).
128  * </li>
129  * <li>Only <i>like </i>type values can be compared. One exception is that it
130  * is valid to compare exact numeric values and approximate numeric
131  * values (the type conversion required is defined by the rules of Java
132  * numeric promotion). If the comparison of non-like type values is
133  * attempted, the selector is always false.
134  * </li>
135  * <li><i>String</i> and <i>Boolean</i> comparison is restricted to = and
136  * &lt;>. Two strings are equal if and only if they contain the same
137  * sequence of characters.
138  * </li>
139  * </ul>
140  * <li>Arithmetic operators in precedence order:</li>
141  * <ul>
142  * <li>+, - unary</li>
143  * <li>*, / multiplication and division</li>
144  * <li>+, - addition and subtraction</li>
145  * <li>Arithmetic operations use Java numeric promotion.</li>
146  * </ul>
147  *
148  * <li><i>arithmetic-expr1 </i>[NOT] BETWEEN <i>arithmetic-expr2 </i>AND<i>
149  * arithmetic-expr3</i> comparison operator
150  * </li>
151  * <ul>
152  * <li>age BETWEEN 15 and 19 is equivalent to age >= 15 AND age &lt;= 19
153  * </li>
154  * <li>age NOT BETWEEN 15 and 19 is equivalent to age &lt; 15 OR age > 19
155  * </li>
156  * </ul>
157  * <li><i>identifier </i>[NOT] IN (<i>string-literal1, string-literal2,...
158  * </i>)
159  * </li>
160  * <br>comparison operator where identifier has a <i>String</i> or NULL
161  * value.
162  * <ul>
163  * <li>Country IN ('UK', 'US', 'France') is true for 'UK' and false for
164  * 'Peru'. It is equivalent to the expression (Country = ' UK') OR
165  * (Country = ' US') OR (Country = ' France')
166  * </li>
167  * <li>Country NOT IN (' UK', 'US', 'France') is false for 'UK' and true
168  * for 'Peru'. It is equivalent to the expression NOT ((Country = 'UK')
169  * OR (Country = 'US') OR (Country = 'France'))
170  * </li>
171  * <li>If <i>identifier </i>of an IN or NOT IN operation is NULL the value
172  * of the operation is unknown.
173  * </li>
174  * </ul>
175  * <li><i>identifier </i>[NOT] LIKE <i>pattern-value</i> [ESCAPE
176  * <i>escape-character</i>]
177  * </li>
178  * <br>comparison operator, where <i>identifier</i> has a <i>String</i>
179  * value; <i>pattern-value</i> is a string literal where '_' stands for
180  * any single character; '%' stands for any sequence of characters
181  * (including the empty sequence); and all other characters stand for
182  * themselves. The optional <i>escape-character</i> is a single character
183  * string literal whose character is used to escape the special meaning
184  * of the '_' and '%' in <i>pattern-value</i>.
185  * <ul>
186  * <li><i>phone LIKE '12%3'</i> is true for '123', '12993' and false for
187  * '1234'
188  * </li>
189  * <li><i>word LIKE 'l_se'</i> is true for 'lose' and false for 'loose'
190  * </li>
191  * <li><i>underscored LIKE '\_%' ESCAPE '\'</i> is true for '_foo' and
192  * false for 'bar'
193  * </li>
194  * <li><i>phone NOT LIKE '12%3'</i> is false for '123' and '12993' and
195  * true for '1234'
196  * </li>
197  * <li>If <i>identifier</i> of a LIKE or NOT LIKE operation is NULL the
198  * value of the operation is unknown.
199  * </li>
200  * </ul>
201  * <li><i>identifier</i> IS NULL</li>
202  * <br>comparison operator tests for a null header field value, or a
203  * missing property value.
204  * <ul>
205  * <li><i>prop_name</i> IS NULL</li>
206  * <li><i>identifier</i> IS NOT NULL comparison operator tests for the
207  * existence of a non null header field value or property value.
208  * </li>
209  * <li><i>prop_name</i> IS NOT NULL</li>
210  * </ul>
211  * </ul></ul>
212  */

213 public class Selector {
214
215     /**
216      * The 'compiled' expression
217      */

218     private final Expression evaluator;
219
220
221     /**
222      * Construct a message selector that selects messages based on the
223      * supplied expression.
224      *
225      * @param expression the conditional expression
226      * @throws InvalidSelectorException if expression is invalid
227      */

228     public Selector(final String JavaDoc expression) throws InvalidSelectorException JavaDoc {
229         try {
230             
231             if (expression == null || expression.length() == 0) {
232                 // always return true for null or empty expressions
233
evaluator = Literal.booleanLiteral(true);
234             }//if
235
else {
236                 SelectorLexer lexer = new SelectorLexer(new StringReader JavaDoc(expression));
237                 lexer.initialise();
238
239                 SelectorParser parser = new SelectorParser(lexer);
240                 parser.initialise();
241                 parser.selector(); // start parsing at the selector rule
242

243                 SelectorTreeParser builder = new SelectorTreeParser();
244                 builder.initialise(new DefaultExpressionFactory());
245                 evaluator = builder.selector(parser.getAST());
246             }//else
247
}//try
248
catch (Exception JavaDoc exception) {
249             throw new InvalidSelectorException JavaDoc(exception.toString());
250         }//catch
251
}//selector
252

253
254     /**
255      * Return if message is accepted by the expression
256      *
257      * @param message the message
258      * @return true if the message is selected, otherwise false
259      */

260     public boolean accept(final Message JavaDoc message) {
261         boolean result = false;
262         try {
263             MantaObject value = evaluator.evaluate(message);
264             
265             if (value instanceof MantaBoolean) {
266                 result = ((MantaBoolean) value).value();
267             }//if
268
} //try
269
catch (TypeMismatchException ignore) {
270             
271         }//catch
272
return result;
273     }//accept
274

275     
276     
277     public static void main (String JavaDoc[] args){
278         try {
279             Selector s = new Selector("ticket='foo'");
280             System.out.println(s);
281         }
282         catch (InvalidSelectorException JavaDoc e) {
283             // TODO Auto-generated catch block
284
e.printStackTrace();
285         }
286     }
287 }//Selector
288
Popular Tags