001 /**
002 * GRANITE DATA SERVICES
003 * Copyright (C) 2006-2013 GRANITE DATA SERVICES S.A.S.
004 *
005 * This file is part of the Granite Data Services Platform.
006 *
007 * Granite Data Services is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * Granite Data Services is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
015 * General Public License for more details.
016 *
017 * You should have received a copy of the GNU Lesser General Public
018 * License along with this library; if not, write to the Free Software
019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
020 * USA, or see <http://www.gnu.org/licenses/>.
021 */
022 package org.granite.gravity.selector;
023
024 import java.math.BigDecimal;
025 import java.util.Collection;
026 import java.util.HashSet;
027 import java.util.Iterator;
028 import java.util.List;
029
030 import javax.jms.JMSException;
031
032 /**
033 * An expression which performs an operation on two expression values
034 *
035 * @version $Revision: 1.3 $
036 */
037 public abstract class UnaryExpression implements Expression {
038
039 private static final BigDecimal BD_LONG_MIN_VALUE = BigDecimal.valueOf(Long.MIN_VALUE);
040 protected Expression right;
041
042 public static Expression createNegate(Expression left) {
043 return new UnaryExpression(left) {
044 public Object evaluate(MessageEvaluationContext message) throws JMSException {
045 Object rvalue = right.evaluate(message);
046 if (rvalue == null) {
047 return null;
048 }
049 if (rvalue instanceof Number) {
050 return negate((Number) rvalue);
051 }
052 return null;
053 }
054
055 @Override
056 public String getExpressionSymbol() {
057 return "-";
058 }
059 };
060 }
061
062 public static BooleanExpression createInExpression(PropertyExpression right, List<?> elements, final boolean not) {
063
064 // Use a HashSet if there are many elements.
065 Collection<?> t;
066 if( elements.size()==0 )
067 t=null;
068 else if( elements.size() < 5 )
069 t = elements;
070 else {
071 t = new HashSet<Object>(elements);
072 }
073 final Collection<?> inList = t;
074
075 return new BooleanUnaryExpression(right) {
076 public Object evaluate(MessageEvaluationContext message) throws JMSException {
077
078 Object rvalue = right.evaluate(message);
079 if (rvalue == null) {
080 return null;
081 }
082 if( rvalue.getClass()!=String.class )
083 return null;
084
085 if( (inList!=null && inList.contains(rvalue)) ^ not ) {
086 return Boolean.TRUE;
087 }
088 return Boolean.FALSE;
089
090 }
091
092 @Override
093 public String toString() {
094 StringBuffer answer = new StringBuffer();
095 answer.append(right);
096 answer.append(" ");
097 answer.append(getExpressionSymbol());
098 answer.append(" ( ");
099
100 if (inList != null) {
101 int count=0;
102 for (Iterator<?> i = inList.iterator(); i.hasNext();) {
103 Object o = i.next();
104 if( count!=0 ) {
105 answer.append(", ");
106 }
107 answer.append(o);
108 count++;
109 }
110 }
111
112 answer.append(" )");
113 return answer.toString();
114 }
115
116 @Override
117 public String getExpressionSymbol() {
118 if( not )
119 return "NOT IN";
120 return "IN";
121 }
122 };
123 }
124
125 abstract static class BooleanUnaryExpression extends UnaryExpression implements BooleanExpression {
126 public BooleanUnaryExpression(Expression left) {
127 super(left);
128 }
129
130 public boolean matches(MessageEvaluationContext message) throws JMSException {
131 Object object = evaluate(message);
132 return object!=null && object == Boolean.TRUE;
133 }
134 }
135
136
137 public static BooleanExpression createNOT(BooleanExpression left) {
138 return new BooleanUnaryExpression(left) {
139 public Object evaluate(MessageEvaluationContext message) throws JMSException {
140 Boolean lvalue = (Boolean) right.evaluate(message);
141 if (lvalue == null) {
142 return null;
143 }
144 return lvalue.booleanValue() ? Boolean.FALSE : Boolean.TRUE;
145 }
146
147 @Override
148 public String getExpressionSymbol() {
149 return "NOT";
150 }
151 };
152 }
153
154 public static BooleanExpression createBooleanCast(Expression left) {
155 return new BooleanUnaryExpression(left) {
156 public Object evaluate(MessageEvaluationContext message) throws JMSException {
157 Object rvalue = right.evaluate(message);
158 if (rvalue == null)
159 return null;
160 if (!rvalue.getClass().equals(Boolean.class))
161 return Boolean.FALSE;
162 return ((Boolean)rvalue).booleanValue() ? Boolean.TRUE : Boolean.FALSE;
163 }
164
165 @Override
166 public String toString() {
167 return right.toString();
168 }
169
170 @Override
171 public String getExpressionSymbol() {
172 return "";
173 }
174 };
175 }
176
177 private static Number negate(Number left) {
178 Class<?> clazz = left.getClass();
179 if (clazz == Integer.class) {
180 return new Integer(-left.intValue());
181 }
182 else if (clazz == Long.class) {
183 return new Long(-left.longValue());
184 }
185 else if (clazz == Float.class) {
186 return new Float(-left.floatValue());
187 }
188 else if (clazz == Double.class) {
189 return new Double(-left.doubleValue());
190 }
191 else if (clazz == BigDecimal.class) {
192 // We ussually get a big deciamal when we have Long.MIN_VALUE constant in the
193 // Selector. Long.MIN_VALUE is too big to store in a Long as a positive so we store it
194 // as a Big decimal. But it gets Negated right away.. to here we try to covert it back
195 // to a Long.
196 BigDecimal bd = (BigDecimal)left;
197 bd = bd.negate();
198
199 if( BD_LONG_MIN_VALUE.compareTo(bd)==0 ) {
200 return new Long(Long.MIN_VALUE);
201 }
202 return bd;
203 }
204 else {
205 throw new RuntimeException("Don't know how to negate: "+left);
206 }
207 }
208
209 public UnaryExpression(Expression left) {
210 this.right = left;
211 }
212
213 public Expression getRight() {
214 return right;
215 }
216
217 public void setRight(Expression expression) {
218 right = expression;
219 }
220
221 /**
222 * @see java.lang.Object#toString()
223 */
224 @Override
225 public String toString() {
226 return "(" + getExpressionSymbol() + " " + right.toString() + ")";
227 }
228
229 /**
230 * TODO: more efficient hashCode()
231 *
232 * @see java.lang.Object#hashCode()
233 */
234 @Override
235 public int hashCode() {
236 return toString().hashCode();
237 }
238
239 /**
240 * TODO: more efficient hashCode()
241 *
242 * @see java.lang.Object#equals(java.lang.Object)
243 */
244 @Override
245 public boolean equals(Object o) {
246
247 if (o == null || !this.getClass().equals(o.getClass())) {
248 return false;
249 }
250 return toString().equals(o.toString());
251
252 }
253
254 /**
255 * Returns the symbol that represents this binary expression. For example, addition is
256 * represented by "+"
257 *
258 * @return teh symbol
259 */
260 abstract public String getExpressionSymbol();
261
262 }