1 28 29 package com.caucho.jms.selector; 30 31 import com.caucho.log.Log; 32 import com.caucho.util.CharBuffer; 33 import com.caucho.util.IntMap; 34 import com.caucho.util.L10N; 35 36 import javax.jms.InvalidSelectorException ; 37 import javax.jms.JMSException ; 38 import java.util.logging.Logger ; 39 40 41 44 public class SelectorParser { 45 static final Logger log = Log.open(SelectorParser.class); 46 static final L10N L = new L10N(SelectorParser.class); 47 48 static final int TRUE = 1; 49 static final int FALSE = TRUE + 1; 50 static final int NULL = FALSE + 1; 51 52 static final int INTEGER = NULL + 1; 53 static final int DOUBLE = INTEGER + 1; 54 static final int LONG = DOUBLE + 1; 55 static final int STRING = LONG + 1; 56 static final int IDENTIFIER = STRING + 1; 57 58 static final int EQ = IDENTIFIER + 1; 59 static final int NE = EQ + 1; 60 static final int LT = NE + 1; 61 static final int LE = LT + 1; 62 static final int GT = LE + 1; 63 static final int GE = GT + 1; 64 65 static final int NOT = GE + 1; 66 static final int AND = NOT + 1; 67 static final int OR = AND + 1; 68 static final int BETWEEN = OR + 1; 69 static final int LIKE = BETWEEN + 1; 70 static final int IN = LIKE + 1; 71 static final int IS = IN + 1; 72 73 private static IntMap _reserved; 74 75 private String _query; 76 private int _parseIndex; 77 private int _token = -1; 78 private String _lexeme; 79 private CharBuffer _cb = new CharBuffer(); 80 81 public Selector parse(String query) 82 throws JMSException 83 { 84 _query = query; 85 _parseIndex = 0; 86 87 if (peekToken() == -1) 88 return null; 89 90 Selector selector = parseExpr(); 91 92 if (! selector.isUnknown() && ! selector.isBoolean()) 93 throw new InvalidSelectorException (L.l("selector '{0}' must be a boolean", 94 selector)); 95 96 return selector; 97 } 98 99 private Selector parseExpr() 100 throws JMSException 101 { 102 return parseOr(); 103 } 104 105 private Selector parseOr() 106 throws JMSException 107 { 108 Selector left = parseAnd(); 109 110 while (true) { 111 int token = peekToken(); 112 113 switch (token) { 114 case OR: 115 scanToken(); 116 left = new BooleanBinarySelector(token, left, parseAnd()); 117 break; 118 119 default: 120 return left; 121 } 122 } 123 } 124 125 private Selector parseAnd() 126 throws JMSException 127 { 128 Selector left = parseCmp(); 129 130 while (true) { 131 int token = peekToken(); 132 133 switch (token) { 134 case AND: 135 scanToken(); 136 left = new BooleanBinarySelector(token, left, parseCmp()); 137 break; 138 139 default: 140 return left; 141 } 142 } 143 } 144 145 155 private Selector parseCmp() 156 throws JMSException 157 { 158 int token = peekToken(); 159 boolean isNot = false; 160 161 if (token == NOT) { 162 scanToken(); 163 isNot = true; 164 token = peekToken(); 165 } 166 167 Selector left = parseAdd(); 168 169 token = peekToken(); 170 171 if (token == NOT) { 172 isNot = ! isNot; 173 scanToken(); 174 token = peekToken(); 175 } 176 177 if (token >= EQ && token <= GE) { 178 scanToken(); 179 180 left = new BooleanBinarySelector(token, left, parseAdd()); 181 } 182 183 else if (token == BETWEEN) { 184 scanToken(); 185 186 Selector low = parseAdd(); 187 token = scanToken(); 188 if (token != AND) 189 throw error("BETWEEN needs AND"); 190 Selector high = parseAdd(); 191 192 left = new BetweenSelector(left, low, high); 193 } 194 195 else if (token == LIKE) { 196 scanToken(); 197 198 token = scanToken(); 199 if (token != STRING) 200 throw error("LIKE needs string pattern"); 201 202 left = new LikeSelector(left, _lexeme); 203 } 204 205 else if (token == IN) { 206 scanToken(); 207 208 InSelector inSelector = new InSelector(left); 209 210 if (scanToken() != '(') 211 throw error("IN needs `('"); 212 213 while ((token = scanToken()) == STRING) { 214 inSelector.addValue(_lexeme); 215 216 if (peekToken() == ',') 217 scanToken(); 218 } 219 220 if (token != ')') 221 throw error("IN needs `)'"); 222 scanToken(); 223 224 left = inSelector; 225 } 226 227 else if (token == IS) { 228 scanToken(); 229 230 if (peekToken() == NOT) { 231 isNot = ! isNot; 232 scanToken(); 233 } 234 235 if ((token = scanToken()) != NULL) 236 throw error("IS needs NULL"); 237 238 left = new UnarySelector(NULL, left); 239 } 240 241 if (isNot) 242 return new UnarySelector(NOT, left); 243 else 244 return left; 245 } 246 247 private Selector parseAdd() 248 throws JMSException 249 { 250 Selector left = parseMul(); 251 252 while (true) { 253 int token = peekToken(); 254 255 switch (token) { 256 case '+': 257 case '-': 258 scanToken(); 259 left = new NumericBinarySelector(token, left, parseMul()); 260 break; 261 262 default: 263 return left; 264 } 265 } 266 } 267 268 private Selector parseMul() 269 throws JMSException 270 { 271 Selector left = parseUnary(); 272 273 while (true) { 274 int token = peekToken(); 275 276 switch (token) { 277 case '*': 278 case '/': 279 scanToken(); 280 left = new NumericBinarySelector(token, left, parseUnary()); 281 break; 282 283 default: 284 return left; 285 } 286 } 287 } 288 289 private Selector parseUnary() 290 throws JMSException 291 { 292 int token = peekToken(); 293 294 switch (token) { 295 case '+': 296 case '-': 297 scanToken(); 298 return new UnarySelector(token, parseUnary()); 299 300 default: 301 return parseTerm(); 302 } 303 } 304 305 private Selector parseTerm() 306 throws JMSException 307 { 308 int token = scanToken(); 309 310 switch (token) { 311 case TRUE: 312 return new BooleanLiteralSelector(true); 313 case FALSE: 314 return new BooleanLiteralSelector(false); 315 case IDENTIFIER: 316 return IdentifierSelector.create(_lexeme); 317 case STRING: 318 return new LiteralSelector(_lexeme); 319 case INTEGER: 320 return new LiteralSelector(new Long (_lexeme)); 321 case LONG: 322 return new LiteralSelector(new Long (_lexeme)); 323 case DOUBLE: 324 return new LiteralSelector(new Double (_lexeme)); 325 326 case '(': 327 Selector value = parseExpr(); 328 if (scanToken() != ')') 329 throw error("expected ')'"); 330 return value; 331 332 default: 333 throw error("unknown token: " + token); 334 } 335 } 336 337 342 private int peekToken() 343 throws JMSException 344 { 345 if (_token > 0) 346 return _token; 347 348 _token = scanToken(); 349 350 return _token; 351 } 352 353 359 private int scanToken() 360 throws JMSException 361 { 362 if (_token > 0) { 363 int value = _token; 364 _token = -1; 365 return value; 366 } 367 368 int sign = 1; 369 int ch; 370 371 for (ch = read(); Character.isWhitespace((char) ch); ch = read()) { 372 } 373 374 switch (ch) { 375 case -1: 376 case '(': 377 case ')': 378 case '.': 379 case '*': 380 case '/': 381 case ',': 382 return ch; 383 384 case '+': 385 if ((ch = read()) >= '0' && ch <= '9') 386 break; 387 else { 388 unread(ch); 389 return '+'; 390 } 391 392 case '-': 393 if ((ch = read()) >= '0' && ch <= '9') { 394 sign = -1; 395 break; 396 } 397 else { 398 unread(ch); 399 return '-'; 400 } 401 402 case '=': 403 return EQ; 404 405 case '<': 406 if ((ch = read()) == '=') 407 return LE; 408 else if (ch == '>') 409 return NE; 410 else { 411 unread(ch); 412 return LT; 413 } 414 415 case '>': 416 if ((ch = read()) == '=') 417 return GE; 418 else { 419 unread(ch); 420 return GT; 421 } 422 } 423 424 if (Character.isJavaIdentifierStart((char) ch)) { 425 _cb.clear(); 426 427 for (; ch > 0 && Character.isJavaIdentifierPart((char) ch); ch = read()) 428 _cb.append((char) ch); 429 430 unread(ch); 431 432 _lexeme = _cb.toString(); 433 String lower = _lexeme.toLowerCase(); 434 435 int token = _reserved.get(lower); 436 437 if (token > 0) 438 return token; 439 else 440 return IDENTIFIER; 441 } 442 else if (ch >= '0' && ch <= '9') { 443 _cb.clear(); 444 445 int type = INTEGER; 446 447 if (sign < 0) 448 _cb.append('-'); 449 450 for (; ch >= '0' && ch <= '9'; ch = read()) 451 _cb.append((char) ch); 452 453 if (ch == '.') { 454 type = DOUBLE; 455 456 _cb.append('.'); 457 for (ch = read(); ch >= '0' && ch <= '9'; ch = read()) 458 _cb.append((char) ch); 459 } 460 461 if (ch == 'e' || ch == 'E') { 462 type = DOUBLE; 463 464 _cb.append('e'); 465 if ((ch = read()) == '+' || ch == '-') { 466 _cb.append((char) ch); 467 ch = read(); 468 } 469 470 if (! (ch >= '0' && ch <= '9')) 471 throw error(L.l("exponent needs digits at {0}", 472 charName(ch))); 473 474 for (; ch >= '0' && ch <= '9'; ch = read()) 475 _cb.append((char) ch); 476 } 477 478 if (ch == 'F' || ch == 'D' || ch == 'f' || ch == 'd') 479 type = DOUBLE; 480 else if (ch == 'L' || ch == 'l') { 481 type = LONG; 482 } 483 else 484 unread(ch); 485 486 _lexeme = _cb.toString(); 487 488 return type; 489 } 490 else if (ch == '\'') { 492 int end = ch; 493 _cb.clear(); 494 495 for (ch = read(); ch >= 0; ch = read()) { 496 if (ch == end) { 497 int ch1; 498 if ((ch1 = read()) == end) 499 _cb.append((char) end); 500 else { 501 unread(ch1); 502 break; 503 } 504 } 505 else 506 _cb.append((char) ch); 507 } 508 509 if (ch < 0) 510 throw error(L.l("unexpected end of selector")); 511 512 _lexeme = _cb.toString(); 513 514 return STRING; 515 } 516 517 throw error(L.l("unexpected char at {0}", "" + (char) ch)); 518 } 519 520 523 private int read() 524 { 525 if (_parseIndex < _query.length()) 526 return _query.charAt(_parseIndex++); 527 else 528 return -1; 529 } 530 531 534 private void unread(int ch) 535 { 536 if (ch >= 0) 537 _parseIndex--; 538 } 539 540 543 public JMSException error(String msg) 544 { 545 msg += "\nin \"" + _query + "\""; 546 547 return new InvalidSelectorException (msg); 548 } 549 550 553 private String charName(int ch) 554 { 555 if (ch < 0) 556 return L.l("end of query"); 557 else 558 return String.valueOf((char) ch); 559 } 560 561 static { 562 _reserved = new IntMap(); 563 _reserved.put("true", TRUE); 564 _reserved.put("false", FALSE); 565 _reserved.put("and", AND); 566 _reserved.put("or", OR); 567 _reserved.put("not", NOT); 568 _reserved.put("null", NULL); 569 _reserved.put("is", IS); 570 _reserved.put("in", IN); 571 _reserved.put("like", LIKE); 572 _reserved.put("between", BETWEEN); 573 } 574 } 575 | Popular Tags |