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    }