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 */
017 package org.apache.activemq.filter;
018
019 import java.math.BigDecimal;
020 import java.util.Collection;
021 import java.util.HashSet;
022 import java.util.Iterator;
023 import java.util.List;
024
025 import javax.jms.JMSException;
026
027 /**
028 * An expression which performs an operation on two expression values
029 *
030 *
031 */
032 public 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 }