Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/activemq/filter/ComparisonExpression.java


1   /** 
2    * 
3    * Copyright 2004 Protique Ltd
4    * Copyright 2004 Hiram Chirino
5    * 
6    * Licensed under the Apache License, Version 2.0 (the "License"); 
7    * you may not use this file except in compliance with the License. 
8    * You may obtain a copy of the License at 
9    * 
10   * http://www.apache.org/licenses/LICENSE-2.0
11   * 
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS, 
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
15   * See the License for the specific language governing permissions and 
16   * limitations under the License. 
17   * 
18   **/
19  package org.activemq.filter;
20  
21  import java.util.HashSet;
22  import java.util.List;
23  import java.util.regex.Pattern;
24  
25  import javax.jms.JMSException;
26  import javax.jms.Message;
27  
28  /**
29   * A filter performing a comparison of two objects
30   * 
31   * @version $Revision: 1.1.1.1 $
32   */
33  public abstract class ComparisonExpression extends BinaryExpression implements BooleanExpression {
34  
35      public static BooleanExpression createBetween(Expression value, Expression left, Expression right) {
36          return LogicExpression.createAND(createGreaterThanEqual(value, left), createLessThanEqual(value, right));
37      }
38  
39      public static BooleanExpression createNotBetween(Expression value, Expression left, Expression right) {
40          return LogicExpression.createOR(createLessThan(value, left), createGreaterThan(value, right));
41      }
42  
43      static final private HashSet REGEXP_CONTROL_CHARS = new HashSet();
44  
45      static {
46          REGEXP_CONTROL_CHARS.add(new Character('.'));
47          REGEXP_CONTROL_CHARS.add(new Character('\\'));
48          REGEXP_CONTROL_CHARS.add(new Character('['));
49          REGEXP_CONTROL_CHARS.add(new Character(']'));
50          REGEXP_CONTROL_CHARS.add(new Character('^'));
51          REGEXP_CONTROL_CHARS.add(new Character('$'));
52          REGEXP_CONTROL_CHARS.add(new Character('?'));
53          REGEXP_CONTROL_CHARS.add(new Character('*'));
54          REGEXP_CONTROL_CHARS.add(new Character('+'));
55          REGEXP_CONTROL_CHARS.add(new Character('{'));
56          REGEXP_CONTROL_CHARS.add(new Character('}'));
57          REGEXP_CONTROL_CHARS.add(new Character('|'));
58          REGEXP_CONTROL_CHARS.add(new Character('('));
59          REGEXP_CONTROL_CHARS.add(new Character(')'));
60          REGEXP_CONTROL_CHARS.add(new Character(':'));
61          REGEXP_CONTROL_CHARS.add(new Character('&'));
62          REGEXP_CONTROL_CHARS.add(new Character('<'));
63          REGEXP_CONTROL_CHARS.add(new Character('>'));
64          REGEXP_CONTROL_CHARS.add(new Character('='));
65          REGEXP_CONTROL_CHARS.add(new Character('!'));
66      }
67  
68      static class LikeExpression extends UnaryExpression implements BooleanExpression {
69  
70          Pattern likePattern;
71  
72          /**
73           * @param left
74           */
75          public LikeExpression(Expression right, String like, int escape) {
76              super(right);
77  
78              StringBuffer regexp = new StringBuffer(like.length() * 2);
79              regexp.append("\\A"); // The beginning of the input
80              for (int i = 0; i < like.length(); i++) {
81                  char c = like.charAt(i);
82                  if (escape == (0xFFFF & c)) {
83                      i++;
84                      if (i >= like.length()) {
85                          // nothing left to escape...
86                          break;
87                      }
88  
89                      char t = like.charAt(i);
90                      regexp.append("\\x");
91                      regexp.append(Integer.toHexString(0xFFFF & t));
92                  }
93                  else if (c == '%') {
94                      regexp.append(".*?"); // Do a non-greedy match 
95                  }
96                  else if (c == '_') {
97                      regexp.append("."); // match one 
98                  }
99                  else if (REGEXP_CONTROL_CHARS.contains(new Character(c))) {
100                     regexp.append("\\x");
101                     regexp.append(Integer.toHexString(0xFFFF & c));
102                 }
103                 else {
104                     regexp.append(c);
105                 }
106             }
107             regexp.append("\\z"); // The end of the input
108 
109             System.out.println("regexp: " + like + ": " + regexp);
110             likePattern = Pattern.compile(regexp.toString(), Pattern.DOTALL);
111         }
112 
113         /**
114          * @see org.activemq.filter.UnaryExpression#getExpressionSymbol()
115          */
116         public String getExpressionSymbol() {
117             return "LIKE";
118         }
119 
120         /**
121          * @see org.activemq.filter.Expression#evaluate(javax.jms.Message)
122          */
123         public Object evaluate(Message message) throws JMSException {
124 
125             Object rv = this.getRight().evaluate(message);
126 
127             if (rv == null) {
128                 return null;
129             }
130 
131             if (!(rv instanceof String)) {
132               return Boolean.FALSE;
133                 //throw new RuntimeException("LIKE can only operate on String identifiers.  LIKE attemped on: '" + rv.getClass());
134             }
135 
136             return likePattern.matcher((String) rv).matches() ? Boolean.TRUE : Boolean.FALSE;
137         }
138 
139     }
140 
141     public static BooleanExpression createLike(Expression left, String right, String escape) {
142         if (escape != null && escape.length() != 1) {
143             throw new RuntimeException("The ESCAPE string litteral is invalid.  It can only be one character.  Litteral used: " + escape);
144         }
145         int c = -1;
146         if (escape != null) {
147             c = 0xFFFF & escape.charAt(0);
148         }
149 
150         return new LikeExpression(left, right, c);
151     }
152 
153     public static BooleanExpression createNotLike(Expression left, String right, String escape) {
154         return UnaryExpression.createNOT(createLike(left, right, escape));
155     }    
156 
157     public static BooleanExpression createInFilter(Expression left, List elements) {
158       
159       if( !(left instanceof PropertyExpression) )
160         throw new RuntimeException("Expected a property for In expression, got: "+left);      
161       return UnaryExpression.createInExpression((PropertyExpression)left, elements, false);
162       
163     }
164 
165     public static BooleanExpression createNotInFilter(Expression left, List elements) {
166       
167       if( !(left instanceof PropertyExpression) )
168         throw new RuntimeException("Expected a property for In expression, got: "+left);      
169       return UnaryExpression.createInExpression((PropertyExpression)left, elements, true);
170 
171     }
172 
173     public static BooleanExpression createIsNull(Expression left) {
174         return doCreateEqual(left, ConstantExpression.NULL);
175     }
176 
177     public static BooleanExpression createIsNotNull(Expression left) {
178         return UnaryExpression.createNOT(doCreateEqual(left, ConstantExpression.NULL));
179     }
180 
181     public static BooleanExpression createNotEqual(Expression left, Expression right) {
182         return UnaryExpression.createNOT(createEqual(left, right));
183     }
184 
185     public static BooleanExpression createEqual(Expression left, Expression right) {
186       checkEqualOperand(left);
187       checkEqualOperand(right);
188       checkEqualOperandCompatability(left, right);
189       return doCreateEqual(left, right);
190     }
191     
192   private static BooleanExpression doCreateEqual(Expression left, Expression right) {
193         return new ComparisonExpression(left, right) {
194 
195             public Object evaluate(Message message) throws JMSException {
196                 Object obj1 = left.evaluate(message);
197                 Object obj2 = right.evaluate(message);
198                 
199                 // Iff one of the values is null
200                 if (obj1 == null ^ obj2 == null) {
201                     return Boolean.FALSE;
202                 }
203                 if (obj1 == obj2 || obj1.equals(obj2)) {
204                     return Boolean.TRUE;
205                 }
206                 Comparable lv = obj1 instanceof Comparable ? (Comparable) obj1 : null;
207                 Comparable rv = obj2 instanceof Comparable ? (Comparable) obj2 : null;
208                 if( lv==null || rv==null )
209                     return Boolean.FALSE;
210                 return compare(lv, rv);
211             }
212 
213             protected boolean asBoolean(int answer) {
214                 return answer == 0;
215             }
216 
217             public String getExpressionSymbol() {
218                 return "=";
219             }
220         };
221     }
222 
223     public static BooleanExpression createGreaterThan(final Expression left, final Expression right) {
224       checkLessThanOperand(left);
225       checkLessThanOperand(right);
226         return new ComparisonExpression(left, right) {
227             protected boolean asBoolean(int answer) {
228                 return answer > 0;
229             }
230 
231             public String getExpressionSymbol() {
232                 return ">";
233             }
234         };
235     }
236 
237     public static BooleanExpression createGreaterThanEqual(final Expression left, final Expression right) {
238       checkLessThanOperand(left);
239       checkLessThanOperand(right);
240         return new ComparisonExpression(left, right) {
241             protected boolean asBoolean(int answer) {
242                 return answer >= 0;
243             }
244 
245             public String getExpressionSymbol() {
246                 return ">=";
247             }
248         };
249     }
250 
251     public static BooleanExpression createLessThan(final Expression left, final Expression right) {
252       checkLessThanOperand(left);
253       checkLessThanOperand(right);
254         return new ComparisonExpression(left, right) {
255 
256             protected boolean asBoolean(int answer) {
257                 return answer < 0;
258             }
259 
260             public String getExpressionSymbol() {
261                 return "<";
262             }
263 
264         };
265     }
266 
267   public static BooleanExpression createLessThanEqual(final Expression left, final Expression right) {
268       checkLessThanOperand(left);
269       checkLessThanOperand(right);
270         return new ComparisonExpression(left, right) {
271 
272             protected boolean asBoolean(int answer) {
273                 return answer <= 0;
274             }
275 
276             public String getExpressionSymbol() {
277                 return "<=";
278             }
279         };
280     }
281 
282   /**
283      * Only Numeric expressions can be used in >, >=, < or <= expressions.s 
284      * 
285    * @param expr
286    */
287   public static void checkLessThanOperand(Expression expr ) {
288     if( expr instanceof ConstantExpression ) {
289       Object value = ((ConstantExpression)expr).getValue();
290       if( value instanceof Number )
291         return;
292       
293       // Else it's boolean or a String..  
294       throw new RuntimeException("Value '"+expr+"' cannot be compared.");
295     }
296     if( expr instanceof BooleanExpression ) {
297       throw new RuntimeException("Value '"+expr+"' cannot be compared.");
298     }    
299   }
300 
301   /**
302      * Validates that the expression can be used in == or <> expression.  
303      * Cannot not be NULL TRUE or FALSE litterals.
304      * 
305    * @param expr
306    */
307   public static void checkEqualOperand(Expression expr ) {
308     if( expr instanceof ConstantExpression ) {
309       Object value = ((ConstantExpression)expr).getValue();
310       if( value == null )
311         throw new RuntimeException("'"+expr+"' cannot be compared.");
312     }
313   }
314 
315   /**
316    * 
317    * @param left
318    * @param right
319    */
320   private static void checkEqualOperandCompatability(Expression left, Expression right) {
321     if( left instanceof ConstantExpression && right instanceof ConstantExpression ) {
322       if( left instanceof BooleanExpression && !(right instanceof BooleanExpression) )
323         throw new RuntimeException("'"+left+"' cannot be compared with '"+right+"'");
324     }
325   }
326 
327   
328   
329     /**
330      * @param left
331      * @param right
332      */
333     public ComparisonExpression(Expression left, Expression right) {
334         super(left, right);
335     }
336 
337     public Object evaluate(Message message) throws JMSException {
338         Comparable lv = (Comparable) left.evaluate(message);
339         if (lv == null) {
340             return null;
341         }
342         Comparable rv = (Comparable) right.evaluate(message);
343         if (rv == null) {
344             return null;
345         }
346         return compare(lv, rv);
347     }
348 
349     protected Boolean compare(Comparable lv, Comparable rv) {
350         Class lc = lv.getClass();
351         Class rc = rv.getClass();
352         // If the the objects are not of the same type,
353         // try to convert up to allow the comparison.
354         if (lc != rc) {
355             if (lc == Integer.class) {
356                 if (rc == Long.class) {
357                     lv = new Long(((Number) lv).longValue());
358                 }
359                 else if (rc == Float.class) {
360                     lv = new Float(((Number) lv).floatValue());
361                 }
362                 else if (rc == Double.class) {
363                     lv = new Double(((Number) lv).doubleValue());
364                 }
365                 else {
366                     return Boolean.FALSE;
367                 }
368             }
369             else if (lc == Long.class) {
370                 if (rc == Integer.class) {
371                     rv = new Long(((Number) rv).longValue());
372                 }
373                 else if (rc == Float.class) {
374                     lv = new Float(((Number) lv).floatValue());
375                 }
376                 else if (rc == Double.class) {
377                     lv = new Double(((Number) lv).doubleValue());
378                 }
379                 else {
380                     return Boolean.FALSE;
381                 }
382             }
383             else if (lc == Float.class) {
384                 if (rc == Integer.class) {
385                     rv = new Float(((Number) rv).floatValue());
386                 }
387                 else if (rc == Long.class) {
388                     rv = new Float(((Number) rv).floatValue());
389                 }
390                 else if (rc == Double.class) {
391                     lv = new Double(((Number) lv).doubleValue());
392                 }
393                 else {
394                     return Boolean.FALSE;
395                 }
396             } 
397             else if (lc == Double.class) {
398                 if (rc == Integer.class) {
399                     rv = new Double(((Number) rv).doubleValue());
400                 }
401                 else if (rc == Long.class) {
402                     rv = new Double(((Number) rv).doubleValue());
403                 }
404                 else if (rc == Float.class) {
405                   rv = new Float(((Number) rv).doubleValue());
406                 }
407                 else {
408                     return Boolean.FALSE;
409                 }
410             } 
411             else 
412                 return Boolean.FALSE;
413         }
414         return asBoolean(lv.compareTo(rv)) ? Boolean.TRUE : Boolean.FALSE;
415     }
416 
417     protected abstract boolean asBoolean(int answer);
418 }