KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > jms > selector > SelectorParser


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  * Free SoftwareFoundation, Inc.
23  * 59 Temple Place, Suite 330
24  * Boston, MA 02111-1307 USA
25  *
26  * @author Scott Ferguson
27  */

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 JavaDoc;
37 import javax.jms.JMSException JavaDoc;
38 import java.util.logging.Logger JavaDoc;
39
40
41 /**
42  * Parsing the selector.
43  */

44 public class SelectorParser {
45   static final Logger JavaDoc 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 JavaDoc _query;
76   private int _parseIndex;
77   private int _token = -1;
78   private String JavaDoc _lexeme;
79   private CharBuffer _cb = new CharBuffer();
80
81   public Selector parse(String JavaDoc query)
82     throws JMSException JavaDoc
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 JavaDoc(L.l("selector '{0}' must be a boolean",
94                          selector));
95
96     return selector;
97   }
98
99   private Selector parseExpr()
100     throws JMSException JavaDoc
101   {
102     return parseOr();
103   }
104   
105   private Selector parseOr()
106     throws JMSException JavaDoc
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 JavaDoc
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   /**
146    * Parses a comparison expression.
147    *
148    * <pre>
149    * cmp-expr ::= add-expr '=' add-expr
150    * ::= add-expr
151    * </pre>
152    *
153    * @return the parsed expression
154    */

155   private Selector parseCmp()
156     throws JMSException JavaDoc
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 JavaDoc
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 JavaDoc
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 JavaDoc
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 JavaDoc
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 JavaDoc(_lexeme));
321     case LONG:
322       return new LiteralSelector(new Long JavaDoc(_lexeme));
323     case DOUBLE:
324       return new LiteralSelector(new Double JavaDoc(_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   /**
338    * Peeks the next token
339    *
340    * @return integer code for the token
341    */

342   private int peekToken()
343     throws JMSException JavaDoc
344   {
345     if (_token > 0)
346       return _token;
347
348     _token = scanToken();
349
350     return _token;
351   }
352   
353   /**
354    * Scan the next token. If the lexeme is a string, its string
355    * representation is in "lexeme".
356    *
357    * @return integer code for the token
358    */

359   private int scanToken()
360     throws JMSException JavaDoc
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 JavaDoc 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 == '\'' || ch == '\"') {
491
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   /**
521    * Returns the next character.
522    */

523   private int read()
524   {
525     if (_parseIndex < _query.length())
526       return _query.charAt(_parseIndex++);
527     else
528       return -1;
529   }
530
531   /**
532    * Unread the last character.
533    */

534   private void unread(int ch)
535   {
536     if (ch >= 0)
537       _parseIndex--;
538   }
539
540   /**
541    * Creates an error.
542    */

543   public JMSException JavaDoc error(String JavaDoc msg)
544   {
545     msg += "\nin \"" + _query + "\"";
546     
547     return new InvalidSelectorException JavaDoc(msg);
548   }
549
550   /**
551    * Returns the name for a character
552    */

553   private String JavaDoc 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