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