View Javadoc

    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.codehaus.activemq.filter;
    20
    21  import javax.jms.JMSException;
    22  import javax.jms.Message;
    23  import java.util.HashSet;
    24  import java.util.List;
    25  import java.util.regex.Pattern;
    26
    27  /***
    28   * A filter performing a comparison of two objects
    29   *
    30   * @version $Revision: 1.1 $
    31   */
    32  public abstract class ComparisonExpression extends BinaryExpression implements BooleanExpression {
    33
    34      public static BooleanExpression createBetween(Expression value, Expression left, Expression right) {
    35          return LogicExpression.createAND(createGreaterThanEqual(value, left), createLessThanEqual(value, right));
    36      }
    37
    38      public static BooleanExpression createNotBetween(Expression value, Expression left, Expression right) {
    39          return LogicExpression.createOR(createLessThan(value, left), createGreaterThan(value, right));
    40      }
    41
    42      static final private HashSet REGEXP_CONTROL_CHARS = new HashSet();
    43
    44      static {
    45          REGEXP_CONTROL_CHARS.add(new Character('.'));
    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      }
    66
    67      static class LikeExpression extends UnaryExpression implements BooleanExpression {
    68
    69          Pattern likePattern;
    70
    71          /***
    72           * @param left
    73           */
    74          public LikeExpression(Expression right, String like, int escape) {
    75              super(right);
    76
    77              StringBuffer regexp = new StringBuffer(like.length() * 2);
    78              regexp.append("//A"); // The beginning of the input
    79              for (int i = 0; i < like.length(); i++) {
    80                  char c = like.charAt(i);
    81                  if (escape == (0xFFFF & c)) {
    82                      i++;
    83                      if (i >= like.length()) {
    84                          // nothing left to escape...
    85                          break;
    86                      }
    87
    88                      char t = like.charAt(i);
    89                      regexp.append("//x");
    90                      regexp.append(Integer.toHexString(0xFFFF & t));
    91                  }
    92                  else if (c == '%') {
    93                      regexp.append(".*?"); // Do a non-greedy match
    94                  }
    95                  else if (c == '_') {
    96                      regexp.append("."); // match one
    97                  }
    98                  else if (REGEXP_CONTROL_CHARS.contains(new Character(c))) {
    99                      regexp.append("//x");
    100                     regexp.append(Integer.toHexString(0xFFFF & c));
    101                 }
    102                 else {
    103                     regexp.append(c);
    104                 }
    105             }
    106             regexp.append("//z"); // The end of the input
    107
    108             System.out.println("regexp: " + like + ": " + regexp);
    109             likePattern = Pattern.compile(regexp.toString(), Pattern.DOTALL);
    110         }
    111
    112         /***
    113          * @see org.codehaus.activemq.filter.UnaryExpression#getExpressionSymbol()
    114          */
    115         public String getExpressionSymbol() {
    116             return "LIKE";
    117         }
    118
    119         /***
    120          * @see org.codehaus.activemq.filter.Expression#evaluate(javax.jms.Message)
    121          */
    122         public Object evaluate(Message message) throws JMSException {
    123
    124             Object rv = this.getRight().evaluate(message);
    125
    126             if (rv == null) {
    127                 return null;
    128             }
    129
    130             if (!(rv instanceof String)) {
    131                 throw new RuntimeException("LIKE can only operate on String identifiers.  LIKE attemped on: '" + rv.getClass());
    132             }
    133
    134             return likePattern.matcher((String) rv).matches() ? Boolean.TRUE : Boolean.FALSE;
    135         }
    136
    137     }
    138
    139     public static BooleanExpression createLike(Expression left, String right, String escape) {
    140         if (escape != null && escape.length() != 1) {
    141             throw new RuntimeException("The ESCAPE string litteral is invalid.  It can only be one character.  Litteral used: " + escape);
    142         }
    143         int c = -1;
    144         if (escape != null) {
    145             c = 0xFFFF & escape.charAt(0);
    146         }
    147
    148         return new LikeExpression(left, right, c);
    149     }
    150
    151     public static BooleanExpression createNotLike(Expression left, String right, String escape) {
    152         return UnaryExpression.createNOT(createLike(left, right, escape));
    153     }
    154
    155     public static BooleanExpression createInFilter(Expression left, List elements) {
    156         if (elements.isEmpty()) {
    157             return ConstantExpression.FALSE;
    158         }
    159
    160         BooleanExpression answer = createEqual(left, (Expression) elements.get(0));
    161         for (int i = 1; i < elements.size(); i++) {
    162             answer = LogicExpression.createOR(answer, createEqual(left, (Expression) elements.get(i)));
    163         }
    164         return answer;
    165     }
    166
    167     public static BooleanExpression createNotInFilter(Expression left, List elements) {
    168         if (elements.isEmpty()) {
    169             return ConstantExpression.TRUE;
    170         }
    171
    172         BooleanExpression answer = createEqual(left, (Expression) elements.get(0));
    173         for (int i = 1; i < elements.size(); i++) {
    174             answer = LogicExpression.createOR(answer, createEqual(left, (Expression) elements.get(i)));
    175         }
    176         return UnaryExpression.createNOT(answer);
    177     }
    178
    179     public static BooleanExpression createIsNull(Expression left) {
    180         return createEqual(left, ConstantExpression.NULL);
    181     }
    182
    183     public static BooleanExpression createIsNotNull(Expression left) {
    184         return createNotEqual(left, ConstantExpression.NULL);
    185     }
    186
    187     public static BooleanExpression createNotEqual(Expression left, Expression right) {
    188         return UnaryExpression.createNOT(createEqual(left, right));
    189     }
    190
    191     public static BooleanExpression createEqual(Expression left, Expression right) {
    192         return new ComparisonExpression(left, right) {
    193
    194             public Object evaluate(Message message) throws JMSException {
    195                 Object obj1 = left.evaluate(message);
    196                 Object obj2 = right.evaluate(message);
    197
    198                 Comparable lv = obj1 instanceof Comparable ? (Comparable) obj1 : null;
    199                 Comparable rv = obj2 instanceof Comparable ? (Comparable) obj2 : null;
    200                 // Iff one of the values is null
    201                 if (lv == null ^ rv == null) {
    202                     return Boolean.FALSE;
    203                 }
    204                 if (lv == rv) {
    205                     return Boolean.TRUE;
    206                 }
    207                 return compare(lv, rv);
    208             }
    209
    210             protected boolean asBoolean(int answer) {
    211                 return answer == 0;
    212             }
    213
    214             public String getExpressionSymbol() {
    215                 return "=";
    216             }
    217         };
    218     }
    219
    220     public static BooleanExpression createGreaterThan(final Expression left, final Expression right) {
    221         return new ComparisonExpression(left, right) {
    222             protected boolean asBoolean(int answer) {
    223                 return answer > 0;
    224             }
    225
    226             public String getExpressionSymbol() {
    227                 return ">";
    228             }
    229         };
    230     }
    231
    232     public static BooleanExpression createGreaterThanEqual(final Expression left, final Expression right) {
    233         return new ComparisonExpression(left, right) {
    234             protected boolean asBoolean(int answer) {
    235                 return answer >= 0;
    236             }
    237
    238             public String getExpressionSymbol() {
    239                 return ">=";
    240             }
    241         };
    242     }
    243
    244     public static BooleanExpression createLessThan(final Expression left, final Expression right) {
    245         return new ComparisonExpression(left, right) {
    246
    247             protected boolean asBoolean(int answer) {
    248                 return answer < 0;
    249             }
    250
    251             public String getExpressionSymbol() {
    252                 return "<";
    253             }
    254
    255         };
    256     }
    257
    258     public static BooleanExpression createLessThanEqual(final Expression left, final Expression right) {
    259         return new ComparisonExpression(left, right) {
    260
    261             protected boolean asBoolean(int answer) {
    262                 return answer <= 0;
    263             }
    264
    265             public String getExpressionSymbol() {
    266                 return "<=";
    267             }
    268         };
    269     }
    270
    271     /***
    272      * @param left
    273      * @param right
    274      */
    275     public ComparisonExpression(Expression left, Expression right) {
    276         super(left, right);
    277     }
    278
    279     public Object evaluate(Message message) throws JMSException {
    280         Comparable lv = (Comparable) left.evaluate(message);
    281         if (lv == null) {
    282             return null;
    283         }
    284         Comparable rv = (Comparable) right.evaluate(message);
    285         if (rv == null) {
    286             return null;
    287         }
    288         return compare(lv, rv);
    289     }
    290
    291     protected Boolean compare(Comparable lv, Comparable rv) {
    292         Class lc = lv.getClass();
    293         Class rc = rv.getClass();
    294         // If the the objects are not of the same type,
    295         // try to convert up to allow the comparison.
    296         if (lc != rc) {
    297             if (lc == Integer.class) {
    298                 if (rc == Long.class) {
    299                     lv = new Long(((Integer) lv).longValue());
    300                 }
    301                 else if (rc == Double.class) {
    302                     lv = new Double(((Long) lv).doubleValue());
    303                 }
    304                 else {
    305                     throw new RuntimeException("You cannot compare a '" + lc.getName() + "' and a '" + rc.getName()
    306                             + "'");
    307                 }
    308             }
    309             if (lc == Long.class) {
    310                 if (rc == Integer.class) {
    311                     rv = new Long(((Integer) rv).longValue());
    312                 }
    313                 else if (rc == Double.class) {
    314                     lv = new Double(((Long) lv).doubleValue());
    315                 }
    316                 else {
    317                     throw new RuntimeException("You cannot compare a '" + lc.getName() + "' and a '" + rc.getName()
    318                             + "'");
    319                 }
    320             }
    321             if (lc == Double.class) {
    322                 if (rc == Integer.class) {
    323                     rv = new Double(((Integer) rv).doubleValue());
    324                 }
    325                 else if (rc == Long.class) {
    326                     rv = new Double(((Long) rv).doubleValue());
    327                 }
    328                 else {
    329                     throw new RuntimeException("You cannot compare a '" + lc.getName() + "' and a '" + rc.getName()
    330                             + "'");
    331                 }
    332             }
    333         }
    334         return asBoolean(lv.compareTo(rv)) ? Boolean.TRUE : Boolean.FALSE;
    335     }
    336
    337     protected abstract boolean asBoolean(int answer);
    338 }