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 */ 022package org.granite.gravity.selector; 023 024import java.math.BigDecimal; 025import java.util.Collection; 026import java.util.HashSet; 027import java.util.Iterator; 028import java.util.List; 029 030import javax.jms.JMSException; 031 032/** 033 * An expression which performs an operation on two expression values 034 * 035 * @version $Revision: 1.3 $ 036 */ 037public 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}