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 092 public String toString() { 093 StringBuffer answer = new StringBuffer(); 094 answer.append(right); 095 answer.append(" "); 096 answer.append(getExpressionSymbol()); 097 answer.append(" ( "); 098 099 int count = 0; 100 for (Iterator i = inList.iterator(); i.hasNext();) { 101 Object o = (Object)i.next(); 102 if (count != 0) { 103 answer.append(", "); 104 } 105 answer.append(o); 106 count++; 107 } 108 109 answer.append(" )"); 110 return answer.toString(); 111 } 112 113 public String getExpressionSymbol() { 114 if (not) { 115 return "NOT IN"; 116 } else { 117 return "IN"; 118 } 119 } 120 }; 121 } 122 123 abstract static class BooleanUnaryExpression extends UnaryExpression implements BooleanExpression { 124 public BooleanUnaryExpression(Expression left) { 125 super(left); 126 } 127 128 public boolean matches(MessageEvaluationContext message) throws JMSException { 129 Object object = evaluate(message); 130 return object != null && object == Boolean.TRUE; 131 } 132 }; 133 134 public static BooleanExpression createNOT(BooleanExpression left) { 135 return new BooleanUnaryExpression(left) { 136 public Object evaluate(MessageEvaluationContext message) throws JMSException { 137 Boolean lvalue = (Boolean)right.evaluate(message); 138 if (lvalue == null) { 139 return null; 140 } 141 return lvalue.booleanValue() ? Boolean.FALSE : Boolean.TRUE; 142 } 143 144 public String getExpressionSymbol() { 145 return "NOT"; 146 } 147 }; 148 } 149 150 public static BooleanExpression createXPath(final String xpath) { 151 return new XPathExpression(xpath); 152 } 153 154 public static BooleanExpression createXQuery(final String xpath) { 155 return new XQueryExpression(xpath); 156 } 157 158 public static BooleanExpression createBooleanCast(Expression left) { 159 return new BooleanUnaryExpression(left) { 160 public Object evaluate(MessageEvaluationContext message) throws JMSException { 161 Object rvalue = right.evaluate(message); 162 if (rvalue == null) { 163 return null; 164 } 165 if (!rvalue.getClass().equals(Boolean.class)) { 166 return Boolean.FALSE; 167 } 168 return ((Boolean)rvalue).booleanValue() ? Boolean.TRUE : Boolean.FALSE; 169 } 170 171 public String toString() { 172 return right.toString(); 173 } 174 175 public String getExpressionSymbol() { 176 return ""; 177 } 178 }; 179 } 180 181 private static Number negate(Number left) { 182 Class clazz = left.getClass(); 183 if (clazz == Integer.class) { 184 return new Integer(-left.intValue()); 185 } else if (clazz == Long.class) { 186 return new Long(-left.longValue()); 187 } else if (clazz == Float.class) { 188 return new Float(-left.floatValue()); 189 } else if (clazz == Double.class) { 190 return new Double(-left.doubleValue()); 191 } else if (clazz == BigDecimal.class) { 192 // We ussually get a big deciamal when we have Long.MIN_VALUE 193 // constant in the 194 // Selector. Long.MIN_VALUE is too big to store in a Long as a 195 // positive so we store it 196 // as a Big decimal. But it gets Negated right away.. to here we try 197 // to covert it back 198 // to a Long. 199 BigDecimal bd = (BigDecimal)left; 200 bd = bd.negate(); 201 202 if (BD_LONG_MIN_VALUE.compareTo(bd) == 0) { 203 return Long.valueOf(Long.MIN_VALUE); 204 } 205 return bd; 206 } else { 207 throw new RuntimeException("Don't know how to negate: " + left); 208 } 209 } 210 211 public Expression getRight() { 212 return right; 213 } 214 215 public void setRight(Expression expression) { 216 right = expression; 217 } 218 219 /** 220 * @see java.lang.Object#toString() 221 */ 222 public String toString() { 223 return "(" + getExpressionSymbol() + " " + right.toString() + ")"; 224 } 225 226 /** 227 * TODO: more efficient hashCode() 228 * 229 * @see java.lang.Object#hashCode() 230 */ 231 public int hashCode() { 232 return toString().hashCode(); 233 } 234 235 /** 236 * TODO: more efficient hashCode() 237 * 238 * @see java.lang.Object#equals(java.lang.Object) 239 */ 240 public boolean equals(Object o) { 241 242 if (o == null || !this.getClass().equals(o.getClass())) { 243 return false; 244 } 245 return toString().equals(o.toString()); 246 247 } 248 249 /** 250 * Returns the symbol that represents this binary expression. For example, 251 * addition is represented by "+" 252 * 253 * @return 254 */ 255 public abstract String getExpressionSymbol(); 256 257}