001    /**
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  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    package org.apache.activemq.filter;
018    
019    import javax.jms.JMSException;
020    
021    /**
022     * An expression which performs an operation on two expression values
023     * 
024     * 
025     */
026    public abstract class ArithmeticExpression extends BinaryExpression {
027    
028        protected static final int INTEGER = 1;
029        protected static final int LONG = 2;
030        protected static final int DOUBLE = 3;
031    
032        /**
033         * @param left
034         * @param right
035         */
036        public ArithmeticExpression(Expression left, Expression right) {
037            super(left, right);
038        }
039    
040        public static Expression createPlus(Expression left, Expression right) {
041            return new ArithmeticExpression(left, right) {
042                protected Object evaluate(Object lvalue, Object rvalue) {
043                    if (lvalue instanceof String) {
044                        String text = (String)lvalue;
045                        String answer = text + rvalue;
046                        return answer;
047                    } else if (lvalue instanceof Number) {
048                        return plus((Number)lvalue, asNumber(rvalue));
049                    }
050                    throw new RuntimeException("Cannot call plus operation on: " + lvalue + " and: " + rvalue);
051                }
052    
053                public String getExpressionSymbol() {
054                    return "+";
055                }
056            };
057        }
058    
059        public static Expression createMinus(Expression left, Expression right) {
060            return new ArithmeticExpression(left, right) {
061                protected Object evaluate(Object lvalue, Object rvalue) {
062                    if (lvalue instanceof Number) {
063                        return minus((Number)lvalue, asNumber(rvalue));
064                    }
065                    throw new RuntimeException("Cannot call minus operation on: " + lvalue + " and: " + rvalue);
066                }
067    
068                public String getExpressionSymbol() {
069                    return "-";
070                }
071            };
072        }
073    
074        public static Expression createMultiply(Expression left, Expression right) {
075            return new ArithmeticExpression(left, right) {
076    
077                protected Object evaluate(Object lvalue, Object rvalue) {
078                    if (lvalue instanceof Number) {
079                        return multiply((Number)lvalue, asNumber(rvalue));
080                    }
081                    throw new RuntimeException("Cannot call multiply operation on: " + lvalue + " and: " + rvalue);
082                }
083    
084                public String getExpressionSymbol() {
085                    return "*";
086                }
087            };
088        }
089    
090        public static Expression createDivide(Expression left, Expression right) {
091            return new ArithmeticExpression(left, right) {
092    
093                protected Object evaluate(Object lvalue, Object rvalue) {
094                    if (lvalue instanceof Number) {
095                        return divide((Number)lvalue, asNumber(rvalue));
096                    }
097                    throw new RuntimeException("Cannot call divide operation on: " + lvalue + " and: " + rvalue);
098                }
099    
100                public String getExpressionSymbol() {
101                    return "/";
102                }
103            };
104        }
105    
106        public static Expression createMod(Expression left, Expression right) {
107            return new ArithmeticExpression(left, right) {
108    
109                protected Object evaluate(Object lvalue, Object rvalue) {
110                    if (lvalue instanceof Number) {
111                        return mod((Number)lvalue, asNumber(rvalue));
112                    }
113                    throw new RuntimeException("Cannot call mod operation on: " + lvalue + " and: " + rvalue);
114                }
115    
116                public String getExpressionSymbol() {
117                    return "%";
118                }
119            };
120        }
121    
122        protected Number plus(Number left, Number right) {
123            switch (numberType(left, right)) {
124            case INTEGER:
125                return new Integer(left.intValue() + right.intValue());
126            case LONG:
127                return new Long(left.longValue() + right.longValue());
128            default:
129                return new Double(left.doubleValue() + right.doubleValue());
130            }
131        }
132    
133        protected Number minus(Number left, Number right) {
134            switch (numberType(left, right)) {
135            case INTEGER:
136                return new Integer(left.intValue() - right.intValue());
137            case LONG:
138                return new Long(left.longValue() - right.longValue());
139            default:
140                return new Double(left.doubleValue() - right.doubleValue());
141            }
142        }
143    
144        protected Number multiply(Number left, Number right) {
145            switch (numberType(left, right)) {
146            case INTEGER:
147                return new Integer(left.intValue() * right.intValue());
148            case LONG:
149                return new Long(left.longValue() * right.longValue());
150            default:
151                return new Double(left.doubleValue() * right.doubleValue());
152            }
153        }
154    
155        protected Number divide(Number left, Number right) {
156            return new Double(left.doubleValue() / right.doubleValue());
157        }
158    
159        protected Number mod(Number left, Number right) {
160            return new Double(left.doubleValue() % right.doubleValue());
161        }
162    
163        private int numberType(Number left, Number right) {
164            if (isDouble(left) || isDouble(right)) {
165                return DOUBLE;
166            } else if (left instanceof Long || right instanceof Long) {
167                return LONG;
168            } else {
169                return INTEGER;
170            }
171        }
172    
173        private boolean isDouble(Number n) {
174            return n instanceof Float || n instanceof Double;
175        }
176    
177        protected Number asNumber(Object value) {
178            if (value instanceof Number) {
179                return (Number)value;
180            } else {
181                throw new RuntimeException("Cannot convert value: " + value + " into a number");
182            }
183        }
184    
185        public Object evaluate(MessageEvaluationContext message) throws JMSException {
186            Object lvalue = left.evaluate(message);
187            if (lvalue == null) {
188                return null;
189            }
190            Object rvalue = right.evaluate(message);
191            if (rvalue == null) {
192                return null;
193            }
194            return evaluate(lvalue, rvalue);
195        }
196    
197        /**
198         * @param lvalue
199         * @param rvalue
200         * @return
201         */
202        protected abstract Object evaluate(Object lvalue, Object rvalue);
203    
204    }