View Javadoc
1 /*** 2 * Redistribution and use of this software and associated documentation 3 * ("Software"), with or without modification, are permitted provided 4 * that the following conditions are met: 5 * 6 * 1. Redistributions of source code must retain copyright 7 * statements and notices. Redistributions must also contain a 8 * copy of this document. 9 * 10 * 2. Redistributions in binary form must reproduce the 11 * above copyright notice, this list of conditions and the 12 * following disclaimer in the documentation and/or other 13 * materials provided with the distribution. 14 * 15 * 3. The name "Exolab" must not be used to endorse or promote 16 * products derived from this Software without prior written 17 * permission of Exoffice Technologies. For written permission, 18 * please contact info@exolab.org. 19 * 20 * 4. Products derived from this Software may not be called "Exolab" 21 * nor may "Exolab" appear in their names without prior written 22 * permission of Exoffice Technologies. Exolab is a registered 23 * trademark of Exoffice Technologies. 24 * 25 * 5. Due credit should be given to the Exolab Project 26 * (http://www.exolab.org/). 27 * 28 * THIS SOFTWARE IS PROVIDED BY EXOFFICE TECHNOLOGIES AND CONTRIBUTORS 29 * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT 30 * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 31 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 32 * EXOFFICE TECHNOLOGIES OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 33 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 34 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 35 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 37 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 38 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 39 * OF THE POSSIBILITY OF SUCH DAMAGE. 40 * 41 * Copyright 2000-2001,2003 (C) Exoffice Technologies Inc. All Rights Reserved. 42 */ 43 44 package org.exolab.jms.selector; 45 46 import java.io.StringReader; 47 48 import javax.jms.InvalidSelectorException; 49 import javax.jms.Message; 50 51 import org.exolab.jms.selector.parser.SelectorLexer; 52 import org.exolab.jms.selector.parser.SelectorParser; 53 import org.exolab.jms.selector.parser.SelectorTreeParser; 54 55 56 /*** 57 * This class enables messages to be filtered using a message selector. 58 * This is a String whose syntax is based on a subset of the SQL92 59 * conditional expression syntax. 60 * 61 * A selector can contain: 62 * <ul> 63 * <li>Literals:</li> 64 * <ul> 65 * <li>A string literal is enclosed in single quotes with an included 66 * single quote represented by doubled single quote such as 'literal' 67 * and 'literal''s'; like Java <i>String</i> literals these use the 68 * unicode character encoding. 69 * </li> 70 * <li>An exact numeric literal is a numeric value without a decimal point 71 * such as 57, -957, +62; numbers in the range of Java <i>long</i> are 72 * supported. Exact numeric literals use the Java integer literal syntax. 73 * </li> 74 * <li>An approximate numeric literal is a numeric value in scientific 75 * notation such as 7E3, -57.9E2 or a numeric value with a decimal such 76 * as 7., -95.7, +6.2; numbers in the range of Java <i>double</i> 77 * are supported. Approximate literals use the Java floating point 78 * literal syntax. 79 * </li> 80 * <li>The boolean literals <i>TRUE </i>and <i>FALSE</i>.</li> 81 * </ul> 82 * <li>Identifiers:</li> 83 * <ul> 84 * <li>Identifiers use the Java identifier syntax. They are case sensitive. 85 * </li> 86 * <li>Identifiers cannot be the names <i>NULL</i>, <i>TRUE</i>, or 87 * <i>FALSE</i>. 88 * </li> 89 * <li>Identifiers cannot be <i>NOT, AND, OR, BETWEEN, LIKE, IN</i>, and 90 * <i>IS</i>. 91 * </li> 92 * <li>Identifiers are either header field references or property references. 93 * </li> 94 * <br>Message header field references are restricted to 95 * <i>JMSDeliveryMode</i>, <i>JMSPriority</i>, <i>JMSMessageID</i>, 96 * <i>JMSTimestamp</i>, <i>JMSCorrelationID</i>, and <i>JMSType</i>. 97 * <i>JMSMessageID</i>, <i>JMSCorrelationID</i>, and <i>JMSType</i> 98 * values may be <i>null</i> and if so are treated as a NULL value. 99 * <li>Any name beginning with 'JMSX' is a JMS defined property name.</li> 100 * <li>Any name beginning with 'JMS_' is a provider-specific property name. 101 * </li> 102 * <li>Any name that does not begin with 'JMS' is an application-specific 103 * property name. If a property is referenced that does not exist in a 104 * message its value is NULL. If it does exist, its value is the 105 * corresponding property value. 106 * </li> 107 * </ul> 108 * <li>Expressions:</li> 109 * <ul> 110 * <li>A selector is a conditional expression; a selector that evaluates to 111 * true matches; a selector that evaluates to false or unknown does not 112 * match. 113 * </li> 114 * <li>Arithmetic expressions are composed of themselves, arithmetic 115 * operations, identifiers with numeric values and numeric literals. 116 * </li> 117 * <li>Conditional expressions are composed of themselves, comparison 118 * operations, logical operations, identifiers with boolean values and 119 * boolean literals. 120 * </li> 121 * <li>Standard bracketing () for ordering expression evaluation is 122 * supported. 123 * </li> 124 * <li>Logical operators in precedence order: NOT, AND, OR.</li> 125 * <li>Comparison operators: =, >, >=, <, <=, <> (not equal). 126 * </li> 127 * <li>Only <i>like </i>type values can be compared. One exception is that it 128 * is valid to compare exact numeric values and approximate numeric 129 * values (the type conversion required is defined by the rules of Java 130 * numeric promotion). If the comparison of non-like type values is 131 * attempted, the selector is always false. 132 * </li> 133 * <li><i>String</i> and <i>Boolean</i> comparison is restricted to = and 134 * <>. Two strings are equal if and only if they contain the same 135 * sequence of characters. 136 * </li> 137 * </ul> 138 * <li>Arithmetic operators in precedence order:</li> 139 * <ul> 140 * <li>+, - unary</li> 141 * <li>*, / multiplication and division</li> 142 * <li>+, - addition and subtraction</li> 143 * <li>Arithmetic operations use Java numeric promotion.</li> 144 * </ul> 145 * 146 * <li><i>arithmetic-expr1 </i>[NOT] BETWEEN <i>arithmetic-expr2 </i>AND<i> 147 * arithmetic-expr3</i> comparison operator 148 * </li> 149 * <ul> 150 * <li>age BETWEEN 15 and 19 is equivalent to age >= 15 AND age <= 19 151 * </li> 152 * <li>age NOT BETWEEN 15 and 19 is equivalent to age < 15 OR age > 19 153 * </li> 154 * </ul> 155 * <li><i>identifier </i>[NOT] IN (<i>string-literal1, string-literal2,... 156 * </i>) 157 * </li> 158 * <br>comparison operator where identifier has a <i>String</i> or NULL 159 * value. 160 * <ul> 161 * <li>Country IN ('UK', 'US', 'France') is true for 'UK' and false for 162 * 'Peru'. It is equivalent to the expression (Country = ' UK') OR 163 * (Country = ' US') OR (Country = ' France') 164 * </li> 165 * <li>Country NOT IN (' UK', 'US', 'France') is false for 'UK' and true 166 * for 'Peru'. It is equivalent to the expression NOT ((Country = 'UK') 167 * OR (Country = 'US') OR (Country = 'France')) 168 * </li> 169 * <li>If <i>identifier </i>of an IN or NOT IN operation is NULL the value 170 * of the operation is unknown. 171 * </li> 172 * </ul> 173 * <li><i>identifier </i>[NOT] LIKE <i>pattern-value</i> [ESCAPE 174 * <i>escape-character</i>] 175 * </li> 176 * <br>comparison operator, where <i>identifier</i> has a <i>String</i> 177 * value; <i>pattern-value</i> is a string literal where '_' stands for 178 * any single character; '%' stands for any sequence of characters 179 * (including the empty sequence); and all other characters stand for 180 * themselves. The optional <i>escape-character</i> is a single character 181 * string literal whose character is used to escape the special meaning 182 * of the '_' and '%' in <i>pattern-value</i>. 183 * <ul> 184 * <li><i>phone LIKE '12%3'</i> is true for '123', '12993' and false for 185 * '1234' 186 * </li> 187 * <li><i>word LIKE 'l_se'</i> is true for 'lose' and false for 'loose' 188 * </li> 189 * <li><i>underscored LIKE '\_%' ESCAPE '\'</i> is true for '_foo' and 190 * false for 'bar' 191 * </li> 192 * <li><i>phone NOT LIKE '12%3'</i> is false for '123' and '12993' and 193 * true for '1234' 194 * </li> 195 * <li>If <i>identifier</i> of a LIKE or NOT LIKE operation is NULL the 196 * value of the operation is unknown. 197 * </li> 198 * </ul> 199 * <li><i>identifier</i> IS NULL</li> 200 * <br>comparison operator tests for a null header field value, or a 201 * missing property value. 202 * <ul> 203 * <li><i>prop_name</i> IS NULL</li> 204 * <li><i>identifier</i> IS NOT NULL comparison operator tests for the 205 * existence of a non null header field value or property value. 206 * </li> 207 * <li><i>prop_name</i> IS NOT NULL</li> 208 * </ul> 209 * </ul></ul> 210 * 211 * @version $Revision: 1.5 $ $Date: 2003/08/09 15:49:50 $ 212 * @author <a href="mailto:tma@netspace.net.au">Tim Anderson</a> 213 */ 214 public class Selector { 215 216 /*** 217 * The 'compiled' expression 218 */ 219 private final Expression _evaluator; 220 221 222 /*** 223 * Construct a message selector that selects messages based on the 224 * supplied expression. 225 * 226 * @param expression the conditional expression 227 * @throws InvalidSelectorException if expression is invalid 228 */ 229 public Selector(final String expression) throws InvalidSelectorException { 230 try { 231 if (expression == null || expression.length() == 0) { 232 // always return true for null or empty expressions 233 _evaluator = Literal.booleanLiteral(true); 234 } else { 235 SelectorLexer lexer = new SelectorLexer( 236 new StringReader(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 } 247 } catch (Exception exception) { 248 throw new InvalidSelectorException(exception.toString()); 249 } 250 } 251 252 /*** 253 * Return if message is selected by the expression 254 * 255 * @param message the message 256 * @return <code>true</code> if the message is selected, otherwise 257 * <code>false</code> 258 */ 259 public boolean selects(final Message message) { 260 boolean result = false; 261 try { 262 SObject value = _evaluator.evaluate(message); 263 if (value instanceof SBool) { 264 result = ((SBool) value).value(); 265 } 266 } catch (TypeMismatchException ignore) { 267 } 268 return result; 269 } 270 271 } //-- Selector

This page was automatically generated by Maven