001/** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.activemq.filter; 018 019import java.math.BigDecimal; 020import java.util.Collection; 021import java.util.HashSet; 022import java.util.Iterator; 023import java.util.List; 024 025import javax.jms.JMSException; 026 027/** 028 * An expression which performs an operation on two expression values 029 * 030 * 031 */ 032public abstract class UnaryExpression implements Expression { 033 034 private static final BigDecimal BD_LONG_MIN_VALUE = BigDecimal.valueOf(Long.MIN_VALUE); 035 protected Expression right; 036 037 public UnaryExpression(Expression left) { 038 this.right = left; 039 } 040 041 public static Expression createNegate(Expression left) { 042 return new UnaryExpression(left) { 043 public Object evaluate(MessageEvaluationContext message) throws JMSException { 044 Object rvalue = right.evaluate(message); 045 if (rvalue == null) { 046 return null; 047 } 048 if (rvalue instanceof Number) { 049 return negate((Number)rvalue); 050 } 051 return null; 052 } 053 054 public String getExpressionSymbol() { 055 return "-"; 056 } 057 }; 058 } 059 060 public static BooleanExpression createInExpression(PropertyExpression right, List<Object> elements, final boolean not) { 061 062 // Use a HashSet if there are many elements. 063 Collection<Object> t; 064 if (elements.size() == 0) { 065 t = null; 066 } else if (elements.size() < 5) { 067 t = elements; 068 } else { 069 t = new HashSet<Object>(elements); 070 } 071 final Collection inList = t; 072 073 return new BooleanUnaryExpression(right) { 074 public Object evaluate(MessageEvaluationContext message) throws JMSException { 075 076 Object rvalue = right.evaluate(message); 077 if (rvalue == null) { 078 return null; 079 } 080 if (rvalue.getClass() != String.class) { 081 return null; 082 } 083 084 if ((inList != null && inList.contains(rvalue)) ^ not) { 085 return Boolean.TRUE; 086 } else { 087 return Boolean.FALSE; 088 } 089 } 090 091 public String toString() { 092 StringBuffer answer = new StringBuffer(); 093 answer.append(right); 094 answer.append(" "); 095 answer.append(getExpressionSymbol()); 096 answer.append(" ( "); 097 098 int count = 0; 099 for (Iterator i = inList.iterator(); i.hasNext();) { 100 Object o = (Object)i.next(); 101 if (count != 0) { 102 answer.append(", "); 103 } 104 answer.append(o); 105 count++; 106 } 107 108 answer.append(" )"); 109 return answer.toString(); 110 } 111 112 public String getExpressionSymbol() { 113 if (not) { 114 return "NOT IN"; 115 } else { 116 return "IN"; 117 } 118 } 119 }; 120 } 121 122 abstract static class BooleanUnaryExpression extends UnaryExpression implements BooleanExpression { 123 public BooleanUnaryExpression(Expression left) { 124 super(left); 125 } 126 127 public boolean matches(MessageEvaluationContext message) throws JMSException { 128 Object object = evaluate(message); 129 return object != null && object == Boolean.TRUE; 130 } 131 }; 132 133 public static BooleanExpression createNOT(BooleanExpression left) { 134 return new NotExpression(left); 135 } 136 137 public static BooleanExpression createXPath(final String xpath) { 138 return new XPathExpression(xpath); 139 } 140 141 public static BooleanExpression createXQuery(final String xpath) { 142 return new XQueryExpression(xpath); 143 } 144 145 public static BooleanExpression createBooleanCast(Expression left) { 146 return new BooleanUnaryExpression(left) { 147 public Object evaluate(MessageEvaluationContext message) throws JMSException { 148 Object rvalue = right.evaluate(message); 149 if (rvalue == null) { 150 return null; 151 } 152 if (!rvalue.getClass().equals(Boolean.class)) { 153 return Boolean.FALSE; 154 } 155 return ((Boolean)rvalue).booleanValue() ? Boolean.TRUE : Boolean.FALSE; 156 } 157 158 public String toString() { 159 return right.toString(); 160 } 161 162 public String getExpressionSymbol() { 163 return ""; 164 } 165 }; 166 } 167 168 private static Number negate(Number left) { 169 Class clazz = left.getClass(); 170 if (clazz == Integer.class) { 171 return Integer.valueOf(-left.intValue()); 172 } else if (clazz == Long.class) { 173 return Long.valueOf(-left.longValue()); 174 } else if (clazz == Float.class) { 175 return Float.valueOf(-left.floatValue()); 176 } else if (clazz == Double.class) { 177 return Double.valueOf(-left.doubleValue()); 178 } else if (clazz == BigDecimal.class) { 179 // We ussually get a big deciamal when we have Long.MIN_VALUE 180 // constant in the 181 // Selector. Long.MIN_VALUE is too big to store in a Long as a 182 // positive so we store it 183 // as a Big decimal. But it gets Negated right away.. to here we try 184 // to covert it back 185 // to a Long. 186 BigDecimal bd = (BigDecimal)left; 187 bd = bd.negate(); 188 189 if (BD_LONG_MIN_VALUE.compareTo(bd) == 0) { 190 return Long.valueOf(Long.MIN_VALUE); 191 } 192 return bd; 193 } else { 194 throw new RuntimeException("Don't know how to negate: " + left); 195 } 196 } 197 198 public Expression getRight() { 199 return right; 200 } 201 202 public void setRight(Expression expression) { 203 right = expression; 204 } 205 206 /** 207 * @see java.lang.Object#toString() 208 */ 209 public String toString() { 210 return "(" + getExpressionSymbol() + " " + right.toString() + ")"; 211 } 212 213 /** 214 * TODO: more efficient hashCode() 215 * 216 * @see java.lang.Object#hashCode() 217 */ 218 public int hashCode() { 219 return toString().hashCode(); 220 } 221 222 /** 223 * TODO: more efficient hashCode() 224 * 225 * @see java.lang.Object#equals(java.lang.Object) 226 */ 227 public boolean equals(Object o) { 228 229 if (o == null || !this.getClass().equals(o.getClass())) { 230 return false; 231 } 232 return toString().equals(o.toString()); 233 } 234 235 /** 236 * Returns the symbol that represents this binary expression. For example, 237 * addition is represented by "+" 238 * 239 * @return 240 */ 241 public abstract String getExpressionSymbol(); 242 243 private static class NotExpression extends BooleanUnaryExpression { 244 public NotExpression(BooleanExpression right) { 245 super(right); 246 } 247 248 public Object evaluate(MessageEvaluationContext message) throws JMSException { 249 Boolean lvalue = (Boolean) right.evaluate(message); 250 if (lvalue == null) { 251 return null; 252 } 253 return lvalue.booleanValue() ? Boolean.FALSE : Boolean.TRUE; 254 } 255 256 @Override 257 public boolean matches(MessageEvaluationContext message) throws JMSException { 258 Boolean lvalue = (Boolean) right.evaluate(message); 259 if (lvalue == null) { 260 // NOT NULL returns NULL that eventually fails the selector 261 return false; 262 } 263 return !lvalue; 264 } 265 266 public String getExpressionSymbol() { 267 return "NOT"; 268 } 269 } 270}