001    /**
002     *
003     * Licensed to the Apache Software Foundation (ASF) under one or more
004     * contributor license agreements.  See the NOTICE file distributed with
005     * this work for additional information regarding copyright ownership.
006     * The ASF licenses this file to You under the Apache License, Version 2.0
007     * (the "License"); you may not use this file except in compliance with
008     * the License.  You may obtain a copy of the License at
009     *
010     * http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    package org.granite.gravity.selector;
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    
028    /**
029     * An expression which performs an operation on two expression values
030     *
031     * @version $Revision: 1.3 $
032     */
033    public abstract class UnaryExpression implements Expression {
034    
035        private static final BigDecimal BD_LONG_MIN_VALUE = BigDecimal.valueOf(Long.MIN_VALUE);
036        protected Expression right;
037    
038        public static Expression createNegate(Expression left) {
039            return new UnaryExpression(left) {
040                public Object evaluate(MessageEvaluationContext message) throws JMSException {
041                    Object rvalue = right.evaluate(message);
042                    if (rvalue == null) {
043                        return null;
044                    }
045                    if (rvalue instanceof Number) {
046                        return negate((Number) rvalue);
047                    }
048                    return null;
049                }
050    
051                @Override
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<Object>(elements);
068            }
069            final Collection<?> inList = t;
070    
071            return new BooleanUnaryExpression(right) {
072                public Object evaluate(MessageEvaluationContext 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                    }
084                    return Boolean.FALSE;
085    
086                }
087    
088                @Override
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                    if (inList != null) {
097                            int count=0;
098                            for (Iterator<?> i = inList.iterator(); i.hasNext();) {
099                                Object o = i.next();
100                                if( count!=0 ) {
101                                    answer.append(", ");
102                                }
103                                answer.append(o);
104                                count++;
105                            }
106                    }
107    
108                    answer.append(" )");
109                    return answer.toString();
110                }
111    
112                @Override
113                public String getExpressionSymbol() {
114                    if( not )
115                        return "NOT IN";
116                    return "IN";
117                }
118            };
119        }
120    
121        abstract static class BooleanUnaryExpression extends UnaryExpression implements BooleanExpression {
122            public BooleanUnaryExpression(Expression left) {
123                super(left);
124            }
125    
126            public boolean matches(MessageEvaluationContext message) throws JMSException {
127                Object object = evaluate(message);
128                return object!=null && object == Boolean.TRUE;
129            }
130        }
131    
132    
133        public static BooleanExpression createNOT(BooleanExpression left) {
134            return new BooleanUnaryExpression(left) {
135                public Object evaluate(MessageEvaluationContext message) throws JMSException {
136                    Boolean lvalue = (Boolean) right.evaluate(message);
137                    if (lvalue == null) {
138                        return null;
139                    }
140                    return lvalue.booleanValue() ? Boolean.FALSE : Boolean.TRUE;
141                }
142    
143                @Override
144                public String getExpressionSymbol() {
145                    return "NOT";
146                }
147            };
148        }
149    
150        public static BooleanExpression createBooleanCast(Expression left) {
151            return new BooleanUnaryExpression(left) {
152                public Object evaluate(MessageEvaluationContext message) throws JMSException {
153                    Object rvalue = right.evaluate(message);
154                    if (rvalue == null)
155                        return null;
156                    if (!rvalue.getClass().equals(Boolean.class))
157                        return Boolean.FALSE;
158                    return ((Boolean)rvalue).booleanValue() ? Boolean.TRUE : Boolean.FALSE;
159                }
160    
161                @Override
162                public String toString() {
163                    return right.toString();
164                }
165    
166                @Override
167                public String getExpressionSymbol() {
168                    return "";
169                }
170            };
171        }
172    
173        private static Number negate(Number left) {
174            Class<?> clazz = left.getClass();
175            if (clazz == Integer.class) {
176                return new Integer(-left.intValue());
177            }
178            else if (clazz == Long.class) {
179                return new Long(-left.longValue());
180            }
181            else if (clazz ==  Float.class) {
182                return new Float(-left.floatValue());
183            }
184            else if (clazz == Double.class) {
185                return new Double(-left.doubleValue());
186            }
187            else if (clazz == BigDecimal.class) {
188                // We ussually get a big deciamal when we have Long.MIN_VALUE constant in the
189                // Selector.  Long.MIN_VALUE is too big to store in a Long as a positive so we store it
190                // as a Big decimal.  But it gets Negated right away.. to here we try to covert it back
191                // to a Long.
192                BigDecimal bd = (BigDecimal)left;
193                bd = bd.negate();
194    
195                if( BD_LONG_MIN_VALUE.compareTo(bd)==0  ) {
196                    return new Long(Long.MIN_VALUE);
197                }
198                return bd;
199            }
200            else {
201                throw new RuntimeException("Don't know how to negate: "+left);
202            }
203        }
204    
205        public UnaryExpression(Expression left) {
206            this.right = left;
207        }
208    
209        public Expression getRight() {
210            return right;
211        }
212    
213        public void setRight(Expression expression) {
214            right = expression;
215        }
216    
217        /**
218         * @see java.lang.Object#toString()
219         */
220        @Override
221        public String toString() {
222            return "(" + getExpressionSymbol() + " " + right.toString() + ")";
223        }
224    
225        /**
226         * TODO: more efficient hashCode()
227         *
228         * @see java.lang.Object#hashCode()
229         */
230        @Override
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        @Override
241        public boolean equals(Object o) {
242    
243            if (o == null || !this.getClass().equals(o.getClass())) {
244                return false;
245            }
246            return toString().equals(o.toString());
247    
248        }
249    
250        /**
251         * Returns the symbol that represents this binary expression.  For example, addition is
252         * represented by "+"
253         *
254         * @return teh symbol
255         */
256        abstract public String getExpressionSymbol();
257    
258    }